Java中的接口以及常见的Cloneable接口用法

 更新时间:2024年02月06日 14:16:14   作者:掉了颗兔牙lx  
这篇文章主要介绍了Java中的接口以及常见的Cloneable接口用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

1. 概念

接口在 Java 中是一个抽象类型,是抽象方法的集合,是抽象类的更进一步。

接口通常以 Interface 来声明。

一个类通过继承接口的方式,从而来继承接口的抽象方法。

2. 语法规则

在打印图形的示例中,父类中没有 Shape 没有包含别的非抽象方法,所以也可以将它设计成一个接口。

interface IShape {
    void draw();
}
class Cycle implements IShape {
    @Override
    public void draw() {
        System.out.println("○");
    }
}
 
public class Test {
    public static void main(String[] args) {
        IShape shape = new Rect();
        shape.draw();
    }
}

接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。

类描述对象的属性和方法。接口则包含类要实现的方法。

接口中只能包含抽象方法。对于字段来说, 接口中只能包含静态常量(final static)。

interface IShape {
    void draw();
    public static final int num = 10;
}

小结:

  • 使用 interface 定义一个接口.
  • 子类使用 implements 实现接口,子类可以同时实现多个接口 implements 多个接口。
  • 接口中的方法一定是抽象方法, 因此可以省略 abstract.
  • 接口中的方法一定是 public, 因此可以省略 public.
  • Cycle 使用 implements 继承接口,此时表达的含义不再是 "扩展", 而是 "实现",扩展指的是当前已经有一定的功能了, 进一步扩充功能。实现指的是当前啥都没有, 需要从头构造出来。
  • 接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。
  • 一个类如果同时继承抽象类,实现接口,请先 extends 一个类,而后 implements 多个接口。
  • Java 中允许同时实现多个接口,不允许多继承。

3. 接口的命名规则

  • 我们创建接口的时候, 接口的命名一般以大写字母 I 开头。
  • 接口的命名一般使用 "形容词" 词性的单词。
  • 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性。

4. 实现多个接口

有时候我们需要一个类继承多个父类,但是在 Java 中只支持单继承,所以这时候就可以用多接口实现这种多继承的效果。

例子:

先通过类表示一组动物:

public class Animal {
    protected String name;
 
    // 有参构造方法
    public Animal(String name) {
        this.name = name;
    }
}

动物都有不同的技能,比如说会飞,会游泳,会跑,要想让不同的动物具有各自不同的特点,可以将各种不同的技能设置成接口。

这样也方便多种技能的动物“实现”多个技能。

public interface IFlying {
    void fly();
}
public interface IRunning {
    void running();
}
public interface ISwimming {
    void swimming();
}

接下来就是设计几种不同的动物:

首先是🐱,猫会跑,可以实现跑的接口方法。

public class Cat extends Animal implements IRunning {
    public Cat(String name) {
        super(name);
    }
 
    @Override
    public void running() {
        System.out.println(this.name + "正在跑");
    }
}

还有鱼,鱼可以游泳。

青蛙,青蛙既可以在陆地上跑跳,也可以在水中游泳,所以这个类可以实现两个接口。

public class Frog extends Animal implements ISwimming, IRunning {
    public Frog(String name) {
        super(name);
    }
 
    @Override
    public void running() {
        System.out.println(this.name + "正在跳");
    }
 
    @Override
    public void swimming() {
        System.out.println(this.name + "正在游泳");
    }
}

有了接口后,类的调用者就不必关注具体类型,而只关注某个类具备的能力。

在 walk 方法内部,不必关注到底是哪种动物,只要关注他是否具有跑这个功能就行。其他方法也是如此。

// 多接口
public class TestAniaml {
    public static void main(String[] args) {
        Cat cat = new Cat("猫猫");
        Frog frog = new Frog("青蛙");
        Fish fish = new Fish("小鱼");
        walk(frog);
        walk(cat);
        swim(frog);
        swim(fish);
    }
    public static void walk(IRunning running) {
        running.running();
    }
    public static void swim(ISwimming swimming) {
        swimming.swimming();
    }
}

5. 接口实现示例

给对象数组排序

在Arrays工具类中,sort 函数可以对普通数组进行排序,但是在如下代码中,如果使用 sort 方法进行排序,就会运行出错,抛出异常。

错误:

import java.util.Arrays;
 
/**
 * 接口示例,对学生对象数组进行排序
 */
public class Student implements Comparable<Student> {
    private String name;
    private int score;
 
    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
 
    @Override
    public String toString() {
        return "Student{" +
                this.name + '\'' +
                ", score=" + this.score +
                '}';
    }
 
    public static void main(String[] args) {
        Student[] students = new Student[]{
                new Student("小王", 87),
                new Student("小赵", 90),
                new Student("小敏", 89),
        };
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }
}

从报错信息以及源码上来看,可以发现所有使用 sort (Object[ ] a)方法进行排序的对象都必须实现Comparable接口。

而源码中的比较类型是 int 类型,所以如果我们想要使用 sort 方法,就要先复写Comparable接口中的 compareTo 方法,传入想要比较的对象类型,也就是 Student 类。

然后就可以实现 sort 方法,运行结果成为按照 score 的大小排序的数组:

6. Cloneable 接口和深、浅拷贝

6.1 Cloneable 接口

Cloneable 是 Java 中内置的接口之一。

使用场景:Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝"。

但是要想合法调用 clone 方法, 必须要先实现 Cloneable 接口, 否则就会抛出 CloneNotSupportedException 异常。

/**
 * Cloneable 接口
 */
public class B implements Cloneable{
    @Override
    protected B clone() throws CloneNotSupportedException {
        return (B)super.clone();
    }
 
    public static void main(String[] args) throws CloneNotSupportedException {
        B b = new B();
        B b1 = b.clone();
        B b2 = b;
        System.out.println(b == b1);
        System.out.println(b == b2);
    }
}
 

运行结果:

从结果可以看出 B 类已经具有了拷贝能力,== 看得是两个对象引用的地址是否是同一个,b 和 b2 还是一个对象只是有两个名字所以结果是 true,而 b 经过拷贝创新创建了一个新对象 b1,引用指向的地址自然不是一个,结果就是 false。

拷贝分为浅拷贝和深拷贝,要注意它们的区别。

6.2 浅拷贝

可以从运行结果看出,改变了拷贝的值,随之原对象的值也发生了变化;同样的改变原对象的值,拷贝后的对象的值也发生了变化。 这是因为虽然 b1 和 b 是两个不同的对象,但他们内部包含的 a 对象却是相同的。开始时 a 的默认值都是0,将100赋给 b1 中的 a 时,b 中的 a 也就改变了,因为这两个对象中的 a 是同一个引用。

小结:浅拷贝就是当一个对象是通过另一个对象 clone 出来的,此时这两个对象虽然是独立的两个对象,但是这两个对象的内部包含的其他引用是相同的。

6.3 深拷贝

深拷贝就是当一个对象是通过另一个对象 clone 出来的,此时这两个对象是独立的两个对象,这两个对象所包含的所有其他引用也是独立的。

深拷贝的实现方式:

1. 嵌套实现 clone 方法

2. 序列化实现 clone 方法

现在开发中常见的序列化就是将一个对象转化成字符串( json),后续学习 Java web 时会用到。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java实现Dijkstra输出最短路径的实例

    Java实现Dijkstra输出最短路径的实例

    这篇文章主要介绍了Java实现Dijkstra输出最短路径的实例的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-09-09
  • java跳出循环的方式汇总

    java跳出循环的方式汇总

    本文介绍了Java中三种常用的跳出循环的语句:break、continue和return,break用于完全结束循环并跳出循环体;continue用于跳过本次循环体中尚未执行的语句,开始下一次循环;return用于结束方法,每种方法给大家介绍的非常详细,感兴趣的朋友一起看看吧
    2025-02-02
  • springboot上传文件,url直接访问资源问题

    springboot上传文件,url直接访问资源问题

    这篇文章主要介绍了springboot上传文件,url直接访问资源问题。具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Java多线程中的ThreadPoolExecutor解读

    Java多线程中的ThreadPoolExecutor解读

    这篇文章主要介绍了Java多线程中的ThreadPoolExecutor解读,线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行,需要的朋友可以参考下
    2023-09-09
  • Java 发送http请求(get、post)的示例

    Java 发送http请求(get、post)的示例

    这篇文章主要介绍了Java 发送http请求的示例,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-10-10
  • java CompletableFuture实现异步编排详解

    java CompletableFuture实现异步编排详解

    这篇文章主要为大家介绍了java CompletableFuture实现异步编排详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • spring缓存自定义resolver的方法

    spring缓存自定义resolver的方法

    这篇文章主要为大家详细介绍了spring缓存自定义resolver的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • SpringBoot实现文件下载的限速功能

    SpringBoot实现文件下载的限速功能

    在SpringBoot项目中,实现文件下载的限速功能可以有效控制服务器带宽的占用,并防止单个用户消耗过多的资源,本文将通过具体的代码示例和详细的流程解释,介绍如何在SpringBoot项目中实现文件下载的限速功能,需要的朋友可以参考下
    2024-07-07
  • JavaWeb三大组件之监听器Listener详解

    JavaWeb三大组件之监听器Listener详解

    这篇文章主要介绍了JavaWeb三大组件之监听器Listener详解,在JavaWeb应用程序中,Listener监听器是一种机制,用于监听和响应特定的事件,它可以感知并响应与应用程序相关的事件,从而执行相应的逻辑处理,需要的朋友可以参考下
    2023-10-10
  • java中实现一个定时任务的方式

    java中实现一个定时任务的方式

    本文介绍了三种在Java中实现定时任务的方法,并推荐使用Spring Boot注解方式,介绍了如何使用`@Scheduled`注解结合Cron表达式来设置定时任务,并提供了一个示例配置文件
    2025-03-03

最新评论