java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java接口及常见的Cloneable接口

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

作者:掉了颗兔牙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;
}

小结:

3. 接口的命名规则

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 时会用到。

总结

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

您可能感兴趣的文章:
阅读全文