Java中接口相关知识

前言:

本篇博客将带大家了解Java中接口相关的知识

目录

何为接口

接口的特点

实现多个接口

接口间的继承

Cloneable接口和深拷贝

抽象类和接口的区别


何为接口

在生活中,大家对于各种各样的接口早已见怪不怪了。对于不同的接口,与之相匹配的东西也不一样。如:电脑上的USB接口只能插符合USB协议的设备;而对于电源插座上的插孔,只能插符合规范的设备。由此,我们可以知晓:接口就是公共的行为规范,在实现时,只要符合规范,就能使用。在Java中也是如此。在Java中,接口可以看成多个类的公共规范,是一种引用数据类型


接口的特点

  1. 接口的定义格式与定义类的格式基本相同,将class关键字换成interface关键字即可。创建接口时,接口的命名一般以大写字母I开头。接口的命名一般使用“形容词”词性的单词。接口中的方法和属性尽量不要加任何修饰符,以保持代码的简洁。
  2. 接口不能直接使用,必须要借助一个类来实现该接口(借助implements),实现接口中全部的抽象方法再举一个例子:笔记本电脑通过USB接口实现对鼠标、键盘的操控
    public class Computer {
        public void open(){
            System.out.println("开机!");
        }
        public void close(){
            System.out.println("关机!");
        }
    
        public void useDevice(IUSB usb){
            usb.openDevice();
            if(usb instanceof Mouse){
                Mouse mouse = (Mouse)usb;
                mouse.click();
            }else if(usb instanceof KeyBoard){
                KeyBoard keyBoard = (KeyBoard) usb;
                keyBoard.inPut();
            }
            usb.closeDevice();
        }
    }
    
    public class Test {
        public static void main(String[] args) {
           Computer computer = new Computer();
           Mouse mouse = new Mouse();
            KeyBoard keyBoard = new KeyBoard();
            computer.useDevice(mouse);
            System.out.println("==================");
            computer.useDevice(keyBoard);
        }
    }

    效果:

  3. 接口是一种引用类型,但是不能直接new接口的对象(因为接口是抽象化的,无法实例化)。
  4. Java中,接口中的每一个方法都是public的抽象方法。即:接口中的每一个方法都会被隐式地指定为public abstract。如果要想让接口中的方法不是抽象方法,则方法要被default修饰(jdk8满足)。
  5. Java中,接口中可以含有变量,但是接口中的变量都会被隐式地指定为public static final
  6. 接口中的方法是不能在接口中实现的(全是抽象方法),只能由实现接口的类来实现。
  7. 重写接口中的方法时,不能使用默认的访问权限(重写的相关知识点)。
  8. 接口中不能含有静态代码块构造方法
  9. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
  10. 如果类没有实现接口中的所有抽象方法,则类必须要设置为抽象类。

实现多个接口

在Java中,一个类只能继承一个父类(Java不支持多继承),但是一个类可以实现多个接口。一个类在实现多个接口的时候,每个接口中的抽象方法都要实现,否则该类必须设置为抽象类。

注意:在继承和实现接口同时存在的时候,要先写继承,再写实现接口

举例:

abstract class Animal{
    public String name;

    public Animal(String name) {
        this.name = name;
    }
}

interface IRunning{//跑步
    void run();
}

interface ISwimming{//游泳
    void swim();
}

interface IFly{//飞
    void fly();
}

class Dog extends Animal implements IRunning{//先继承再实现接口
    public Dog(String name) {
        super(name);
    }
    public void run(){
        System.out.println(name+" 正在跑步(Dog版)");
    }
}
class Frog extends Animal implements ISwimming{
    public Frog(String name) {
        super(name);
    }
    public void swim(){
        System.out.println(name+" 正在游泳(Frog版)");
    }
}

class Bird extends Animal implements IRunning,ISwimming,IFly{//一个类实现多个接口(用逗号隔开)
    public Bird(String name) {
        super(name);
    }
    public void run(){
        System.out.println(name+" 正在跑步(Bird版)");
    }
    public void swim(){
        System.out.println(name+" 正在游泳(Bird版)");
    }
    public void fly(){
        System.out.println(name+" 正在飞(Bird版)");
    }
}
public class Test {
    public static void run(IRunning iRunning){
        iRunning.run();
    }

    public static void swim(ISwimming iSwimming){
        iSwimming.swim();
    }
    public static void fly(IFly iFly){
        iFly.fly();
    }
    public static void main(String[] args) {
        run(new Dog("小狗"));
        
        System.out.println("========");
        
        swim(new Frog("小青蛙"));
        
        System.out.println("========");
        
        run(new Bird("小鸟"));
        swim(new Bird("小鸟"));
        fly(new Bird("小鸟"));
    }
}

效果:

 

接口表达的含义是具有某一种特性。通过接口的实现会让程序员忘记类型,使用类的时候不必再关注类的类型,而更加关注类具有的能力(如上述的小鸟,可以run、swim和fly)


接口间的继承

类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间是可以多继承的。换而言之,用接口可以达到多继承的目的

举例:

interface A{
    void funcA();
}
interface B{
    void funcB();
}
interface CC extends A,B{//接口的继承(接口的拓展),相当于把多个接口合并在一起
    void func();//代表CC这个接口,不仅具备func这个功能,还具备了A和B的接口的功能
    //这样写的好处就是一个CC解决了多个方法的重写问题
}

class C implements CC{//对CC里面的方法进行重写的时候,不仅要重写func还有funcA和funcB都要重写(其实还是有点继承的味道),否则报错
    public void func(){
        //……
    }
    public void funcA(){
        //……
    }
    public void funcB(){
        //……
    }
}

到这里,关于接口的知识点已经差不多都了解完了。那么,我们再举一个关于接口的例子吧:

import java.util.Arrays;
public class Test {
    public static void main(String[] args){
        int[] array = {1,3,2,10,5,3,7};
        Arrays.sort(array);//排序
        System.out.println(Arrays.toString(array));
    }
}

由上述代码可知,sort方法可以对数组中的数据进行排序,那么如果需要排序的对象是学生类呢?

如下:

class Student{
    public String name;
    public int age;
    public int score;

    public Student(String name, int age, int score){
        this.name = name;
        this.age = age;
        this.score = score;
    }
    public String toString() {
        return "Student{"+
                "name='" + name + '\''+
                ", age=" +age +
                ",score=" + score +
                '}';
    }

}
public class Test {
    public static void main(String[] args) {
        Student[] students = new Student[3];//初始化
        students[0] = new Student("zhangsan", 12, 10);
        students[1] = new Student("lisi", 13, 11);
        students[2] = new Student("wangwu", 10, 9);
    }
}

如何对这数组中的三个学生进行比较呢?又按照什么标准进行排序呢?名字?年龄?还是分数呢?直接将students数组放入sort中是否可以像之前一样直接出排好顺序的数组元素呢?答案显然是不能的。要想实现排序,我们需要额外指定。让Student类继承Comparable接口,并实现其中的CompareTo方法。

import java.util.Arrays;
import java.util.Comparator;
class Student implements Comparable<Student>{
    public String name;
    public int age;
    public int score;

    public Student(String name, int age, int score){
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String toString() {
        return "Student{"+
                "name='" + name + '\''+
                ", age=" +age +
                ",score=" + score +
                '}';
    }
    public int compareTo(Student o){
        //按年龄比较
        if(this.age > o.age){
            return 1;
        }else if(this.age < o.age){
            return -1;
        }else{
            return 0;
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Student[] students = new Student[3];//初始化
        students[0] = new Student("zhangsan", 12, 10);
        students[1] = new Student("lisi", 13, 11);
        students[2] = new Student("wangwu", 10, 9);

        Arrays.sort(students);//像上面一样通过sort方法进行排序
        System.out.println(Arrays.toString(students));
    }
}

效果:

同样,也可以按照分数和姓名来进行排序:

通过比较器,也有一样的效果:

import java.util.Arrays;
import java.util.Comparator;
class Student{
    public String name;
    public int age;
    public int score;

    public Student(String name, int age, int score){
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String toString() {
        return "Student{"+
                "name='" + name + '\''+
                ", age=" +age +
                ",score=" + score +
                '}';
    }
}

//按年龄比较:
class AgeComparator implements Comparator<Student>{
    public int compare(Student o1, Student o2){
        return o1.age - o2.age;
    }
}


public class Test {
    public static void main(String[] args) {
        Student[] students = new Student[3];//初始化
        students[0] = new Student("zhangsan", 12, 10);
        students[1] = new Student("lisi", 13, 11);
        students[2] = new Student("wangwu", 10, 9);

        //比较器
        AgeComparator ageComparator = new AgeComparator();

        Arrays.sort(students,ageComparator);
        System.out.println(Arrays.toString(students));
    }
}

 按照其他两种比较方法也是一样的:

//按分数比较:
class ScoreComparator implements Comparator<Student>{
    public int compare(Student o1, Student o2){
        return o1.score - o2.score;
    }
}
//按名字比较:(引用类型)
class NameComparator implements Comparator<Student>{
    public int compare(Student o1, Student o2){
        return o1.name.compareTo(o2.name);
    }
}

Cloneable接口和深拷贝

关于Cloneable接口:

Object类中存在一个Clone方法,调用这个方法可以创建一个对象的“拷贝”,但是要想合法调用clone方法,必须要先实现Cloneable接口,否则抛CloneNotSupportedException异常。

举例: 

class Student implements Cloneable{
    public String name;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();//父类的克隆
        //protected修饰的
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student = new Student();
        student.name = "小名";
        Student student1 = (Student)student.clone();//向下转型(强制类型转换)
        System.out.println(student);
        System.out.println(student1);
    }
}

效果:

这段代码如何引出?

方法如下: 

 关于深、浅拷贝:

何为深拷贝?何又为浅拷贝?

浅拷贝:D是由C拷贝而来,当C改变的时候,D也随之改变,这种拷贝就叫做浅拷贝。

深拷贝:B是由A拷贝而来,当A改变的时候,B未发生改变,这种拷贝就叫做深拷贝。

举例说明:

浅拷贝:

class Money{
    public double money = 12.25;
}

class Student implements Cloneable{
    public String name;
    public Money m = new Money();

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1 = new Student();

        Student student2 = (Student)student1.clone();//向下转型(强制类型转换)
        System.out.println(student1.m.money);
        System.out.println(student2.m.money);

        System.out.println("=========");

        student1.m.money = 19.21;
        System.out.println(student1.m.money);
        System.out.println(student2.m.money);
    }
}

效果:

 改变的明明是student1.m.money,结果student2.m.money也发生了改变,这种就叫做浅拷贝。

图解如下:

 深拷贝: 

class Money implements Cloneable{
    public double money = 12.25;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Student implements Cloneable{
    public String name;
    public Money m = new Money();

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student student = (Student)super.clone();//只是克隆了Student对象
        student.m = (Money)this.m.clone();//克隆了student对象的Money对象
        return student;
        //return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1 = new Student();

        Student student2 = (Student)student1.clone();//向下转型(强制类型转换)
        System.out.println(student1.m.money);
        System.out.println(student2.m.money);

        System.out.println("=========");

        student1.m.money = 19.21;//深拷贝
        System.out.println(student1.m.money);
        System.out.println(student2.m.money);
    }
}

效果:

只改变了student.m.momey,并未改变student2.m.money,这种拷贝叫做深拷贝。

图解如下:


抽象类和接口的区别

核心区别:

抽象类可以包含普通方法和普通字段,这样的普通方法和普通字段可以被子类直接使用而不必重写;而接口中不能包含普通字段,子类必须重写接口中所有的方法(抽象方法)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值