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 Stream写出既高雅又装*的代码

    如何用Java Stream写出既高雅又装*的代码

    如何让同事看不懂你写的代码,然后觉得你非常牛逼,这里用到了stream()与Lambda,需要有点基础,没基础你炫个&#128296;优雅永不过时~ 看下面文章时记得穿燕尾服,拿高脚杯
    2021-08-08
  • SpringBoot @ModelAttribute使用场景分析

    SpringBoot @ModelAttribute使用场景分析

    这篇文章主要介绍了SpringBoot @ModelAttribute使用场景分析,文中通过实例代码图文相结合给大家介绍的非常详细,需要的朋友可以参考下
    2021-08-08
  • 利用java实现中奖概率详情

    利用java实现中奖概率详情

    这篇文章主要介绍了利用java实现中奖概率详情,根据概率将奖品划分区间,每个区间代表一个奖品,然后抽取​ ​随机数​​,反查落在那个区间上,即为所抽取的奖品,需要的朋友可以参考一下
    2022-07-07
  • springboot如何设置请求参数长度和文件大小限制

    springboot如何设置请求参数长度和文件大小限制

    这篇文章主要介绍了springboot如何设置请求参数长度和文件大小限制,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • Java 实现图片压缩的两种方法

    Java 实现图片压缩的两种方法

    这篇文章主要介绍了Java 实现图片压缩的两种方法,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-09-09
  • Java ServletContext对象原理及功能解析

    Java ServletContext对象原理及功能解析

    这篇文章主要介绍了Java ServletContext对象原理及功能解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • Spring中的SpringData详细说明

    Spring中的SpringData详细说明

    这篇文章主要介绍了Spring中的SpringData详细说明,Spring Data 是Spring 的一个子项目, 旨在统一和简化对各类型持久化存储, 而不拘泥于是关系型数据库还是NoSQL 数据存储,需要的朋友可以参考下
    2023-11-11
  • @TableName注解和@Table的区别及说明

    @TableName注解和@Table的区别及说明

    这篇文章主要介绍了@TableName注解和@Table的区别及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Java并发编程之LockSupport类详解

    Java并发编程之LockSupport类详解

    LockSupport是一种线程阻塞工具,它可以在线程内任意位置让线程阻塞.接下来就带着大家详细了解一下LockSupport类,,需要的朋友可以参考下
    2021-05-05
  • Java并发编程深入理解之Synchronized的使用及底层原理详解 上

    Java并发编程深入理解之Synchronized的使用及底层原理详解 上

    在并发编程中存在线程安全问题,主要原因有:1.存在共享数据 2.多线程共同操作共享数据。关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时synchronized可以保证一个线程的变化可见(可见性),即可以代替volatile
    2021-09-09

最新评论