java接口

一、接口基本概述

Java 中,接口可以看成是:多个类的公共规范,是一种引用数据类型。
接口不能被实例化,
接口中成员默认public static final,
接口中方法默认public abstract,方法不能有具体实现,
接口不能有构造器和静态代码块,
接口中可以有static 修饰的方法
如果类中没有重写接口方法,必须将该类设置为抽象类
public interface TestInterface {
    //成员变量默认static
    public String name="1";
    public static int age=0;
    //抽象方法()相当于公共标准的意思
    public abstract void draw();//不能有具体实现,默认Publid abstract
    //从java8开始提供default来支持方法具体实现
    default public void func(){
        System.out.println("hello");
    }
    public static void fun1(){
        System.out.println("类名直接调用方法");
    }
}
接口需要被类实现,使用关键字implements,在类中需要重写接口的方法

class Rect implements TestInterface{
    public void draw(){
        System.out.println("矩形");
    }
}
class Flower implements  TestInterface{
    public void draw(){
        System.out.println("花");
    }
}

 接口不能直接使用,必须要有一个"实现类""实现"该接口,实现接口中的所有抽象方法。

二、举例子

创建一个USB接口

public interface USB {
    void openDevice();
    void closeDevie();
}
 创建鼠标类实现USB接口
public class Mouse implements USB{
    @Override
    public void openDevice() {
        System.out.println("打开鼠标服务");
    }

    @Override
    public void closeDevie() {
        System.out.println("关闭鼠标服务");
    }
    public void click(){
        System.out.println("点击鼠标");
    }
}
 创建键盘类实现USB接口
public class KeyBoard implements USB{
    @Override
    public void openDevice() {
        System.out.println("敲击键盘");
    }

    @Override
    public void closeDevie() {
        System.out.println("关闭键盘服务");
    }
    public void inPut(){
        System.out.println("输入服务");
    }
}
 创建电脑类,无实现USB接口
public class Computer {
    public void open(){
        System.out.println("开机");
    }
    public void close(){
        System.out.println("关机");
    }
    public void useDevice(USB usb){//只要实现了USB接口的都能传进来
        usb.openDevice();
        if (usb instanceof Mouse){
            Mouse mouse=(Mouse) usb;//发生向下转型
            mouse.click();
        }else if (usb instanceof KeyBoard){
            KeyBoard keyBoard=(KeyBoard) usb;
            keyBoard.inPut();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        Computer computer=new Computer();
        Mouse mouse=new Mouse();
        KeyBoard keyBoard=new KeyBoard();
        computer.useDevice(mouse);
        computer.useDevice(keyBoard);
    }
}

三、第二个例子

创建一个Animal类
public class Animal {
    public String name;
    public Animal(String name){
        this.name=name;
    }

}
 将动物可能出现的动作规范为接口
public interface IRunning {
    public void run();
}
interface ISwimming{
    public void swim();
}
创建一个鱼类和狗类,继承父类Animal,实现各自的动作
public class Fish extends Animal implements ISwimming{
    public Fish(String name){
        super(name);
    }
    public void swim(){
        System.out.println("鱼在游泳");
    }
}
public class Dog extends Animal implements IRunning{//先继承再实现
    public Dog(String name){
        super(name);
    }
    public void run(){
        System.out.println("狗在跑");
    }
}

 创建一个鸭子类,由于鸭子会游泳和跑步,实现了多个接口,解决类不能多继承的问题

class Duck extends Animal implements IRunning,ISwimming{
    public Duck(String name){
        super(name);
    }
    public void run(){
        System.out.println("鸭子在跑");
    }
    public void swim(){
        System.out.println("鸭子在游泳");
    }
}
注意:一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类
如下面的Test测试,接口抛开了类型的限制,只要该类实现了某个接口,都能直接传入walk或者swim方法
public class Test {
    //只要实现IRunning接口的都能是实现
    public static void walk(IRunning running){
        running.run();
    }
    public static void swim(ISwimming swimming){
        swimming.swim();
    }
    public static void main(String[] args) {
        
        walk(new Dog("旺财"));//发生向上转型
        walk(new Duck("唐老鸭"));
    }
}

四、接口间的继承

//鳄鱼即会跑也会游泳
//crocodile接口既有自己的方法也有ISwimmingh和IRunning接口的方法

interface crocodile extends ISwimming,IRunning{
    //自己的方法
    public void hunt();//捕猎
    //接口IRunning和接口ISwimming的方法
    public void run();
    public void swim();
}

五、 对象之间的比较

public class Test {
    public static void main(String[] args) {
        Student[] students=new Student[3];
        students[0]=new Student("laowu",45,45.23F);
        students[1]=new Student("zhangsan",25, 78.23F);
        students[2]=new Student("lisi",43,123.34F);
        System.out.println(students[0].compareTo(students[1]));
    }
}

 假如我想对几个对象进行按照某种规则排序排序,可以将被比较的类实现comparable接口,而实现该接口需要重写compareTo方法

class Student implements Comparable<Student>{//实现Comparable接口需要重写compareto方法
    public int age;
    public String name;
    public float score;
    public Student (String name,int age,float score){
        this.age=age;
        this.name=name;
        this.score=score;
    }

    @Override
    public String toString() {
        return "student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", 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;
        }
    }
}

假如按name比较,由于String类是实现了comparable接口,那么可以按照以下代码进行比较

public int compareTo(Student o) {
        //假如按字符串比较
        if (this.name.compareTo(o.name)>0){
            return 1;
        } else if (this.name.compareTo(o.name)<0) {
            return -1;
        }else {
            return 0;
        }
    }

 下面为String类compareTo源码

public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

在test类中写入自己写的Sort方法代码

//实现了Comparable接口的数组都能传进来
    public static void sort(Comparable[] array){
        for (int i=0;i< array.length;i++){
            for (int j=0;j< array.length-1-i;j++){
                if (array[j].compareTo(array[j+1])>0){
                    Comparable tmp=array[j];
                    array[j]=array[j+1];
                    array[j+1]=tmp;
                }
            }
        }

    }

 Sort以冒泡排序的形式,按字符比较,此时在main函数中调用Arrays.toStirng方法

public static void main(String[] args) {
        Student[] students=new Student[3];
        students[0]=new Student("laowu",45,45.23F);
        students[1]=new Student("zhangsan",25, 78.23F);
        students[2]=new Student("lsi",43,123.34F);
        System.out.println(students[0].compareTo(students[1]));
        sort(students);
        System.out.println(Arrays.toString(students));
    }

 输出结果为按字符大小比较的结果

需要注意的是,一旦在实现了Comparable接口的类中重写了compareTo方法,该方法就固定了,以后调用该方法就只能按字符大小比较,对类的侵入性很强,不够灵活。

基于以上理由,我们可以引入Comparator接口

定义一个类实现Comparator接口,需要重写compare方法,该类以对象的年龄进行比较

class AgeComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age-o2.age;
    }
}

 在test类中实例化AgeComparator,把ageComparator引用放入Arrays.sort的第二个参数

public class Test {

    public static void main(String[] args) {
        Student[] students=new Student[3];
        students[0]=new Student("laowu",45,45.23F);
        students[1]=new Student("zhangsan",25, 78.23F);
        students[2]=new Student("lsi",43,123.34F);
        //比较器
        AgeComparator ageComparator=new AgeComparator();
        Arrays.sort(students,ageComparator);
        System.out.println(Arrays.toString(students));
    }
}

 输出结果为按照年龄大小排序的结果

同样的,定义按照分数大小排序的比较器

class ScoreComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return (int) (o1.score-o2.score);
    }
}

调用Arrays.sort时把scoreComparator传进第二个参数

public static void main(String[] args) {
        Student[] students=new Student[3];
        students[0]=new Student("laowu",45,45.23F);
        students[1]=new Student("zhangsan",25, 78.23F);
        students[2]=new Student("lsi",43,123.34F);
        AgeComparator ageComparator=new AgeComparator();
       
        ScoreComparator scoreComparator=new ScoreComparator();
        Arrays.sort(students,scoreComparator);
        System.out.println(Arrays.toString(students));
}

 同理,按照字符比较的比较器代码如下

//按照字符比较
class NameComparator implements Comparator<Student>{
    public int compare(Student o1,Student o2){
        return o1.name.compareTo(o2.name);//String类实现了Comparable接口并重写了compareTo方法,直接调用即可
    }
}

六、克隆接口和深拷贝

创建一个类实现Cloneable接口,按住ctrl点击Cloneable,发现该接口无任何抽象方法

class Student implements Cloneable{
    public String name;

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

但是在测试类里依然不能调用克隆方法

要能调用克隆方法,必须在Student类中重写object类的clone方法,因为object类是所有类的父类

@Override
    //调用改方法可能会出现该异常(编译时的异常)
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

public static void main(String[] args) throws CloneNotSupportedException{
        Student student1=new Student();
        student1.name="小猫";
        Student student2=(Student) student1.clone();//发生向下整型
        System.out.println(student1.name);
        System.out.println(student2.name);
    }

打印结果如下,此时不是深拷贝

观察以下代码

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("_______________");
        student2.m.money=89;
        System.out.println(student1.m.money);
        System.out.println(student2.m.money);
    }
}

 输出结果如下,可以看到下划线之前money的值为12.25,但是只修改了student2.m.money,发现student1的money也改变了

student2由student1拷贝而来,当修改student2里面的值从而引起原来的对象值也改变,这种叫浅拷浅拷贝原理

 图中两行代码的执行流程如上图所示,虽然tsudent2由student1克隆而来,但是student里面的m对象依然指向的是studengt1 里m指向的地址,只拷贝了第一层,没有拷贝更深层的m对象,所以当修改student2.m.money,两个Student对象的m.money值都会改变。要想让student1.m.money的值不改变就必须连m对象也拷贝一份。

深拷贝是指,拷贝而来的对象,当修改该对象的某个值时,不会导致原来的拷贝对像值发生修改

protected Object clone() throws CloneNotSupportedException {

        Student student =(Student) super.clone();//这行代码只是克隆了一个Student类的对象,用student接收
        student.m=(Money) this.m.clone();//将这个studet的m的对象也克隆一份,并强制转换成Money类型
        return student;
}

这时候改变student2.m.money的值,student1的money的值不会受到影响

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值