java接口

发布于:2024-12-18 ⋅ 阅读:(68) ⋅ 点赞:(0)

目录

一.接口的概念

二.接口的语法

三.接口的简单创建

四.接口的简单使用

五.接口的特性

六.实现多个接口

七.接口之间的继承

 八.接口使用案例

1.Comparable 接口

2.Clonable 接口和深拷贝

九.接口和抽象类的区别


一.接口的概念

说到接口,大家第一反应也许就是USB接口,或者是插座的接口。

对于电脑的USB接口可以插U盘,鼠标,键盘等

对于插座的接口可以插电饭煲,冰箱,吹风机等等。

其实这和java的接口是类似的,就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。

在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。

二.接口的语法

接口的关键字:implements  和  interface

public interface InterfaceName {
    // 常量(可选,必须是`public static final`,可以省略修饰符)
    int CONSTANT = 42;

    // 抽象方法(默认是`public abstract`,可以省略修饰符)
    void method1();
    String method2(String param);
}

要点:

  • 接口中的变量默认是public static final,表示常量,不能更改。
  • 接口中的方法默认是public abstract,实现类必须实现这些方法。
  • Java 8 引入了默认方法静态方法,允许接口包含有实现的方法。

注意:之所以默认方法是public abstract,就跟我一开始在概念处说的,接口可以看做是多个类的公共规范,有了这一层关系,实现该接口的类就必须重写这些方法。

ps:

1. 创建接口时, 接口的命名一般以大写字母 I 开头.

2. 接口的命名一般使用 "形容词" 词性的单词.

3. 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性.

三.接口的简单创建

四.接口的简单使用

下面是一个动物的例子:

public interface IAnimal {
    //抽象方法:默认修饰符为public abstract,没有具体实现

    //睡觉
    void sleep();
    //吃饭
    void eat();
    //发出声音
    void sound();
}

//狗子
//关键字implements,实现IAnimal接口
class dog implements IAnimal{

    //实现了IAnimal接口就必须重写接口的抽象方法
    @Override
    public void sleep() {
        System.out.println("狗子睡大觉...");
    }

    @Override
    public void eat() {
        System.out.println("狗子炫饭...");
    }

    @Override
    public void sound() {
        System.out.println("狗子汪汪汪....");
    }
}

//猫猫
class cat implements IAnimal{

    @Override
    public void sleep() {
        System.out.println("咪咪睡觉....");
    }

    @Override
    public void eat() {
        System.out.println("咪咪吃猫粮...");
    }

    @Override
    public void sound() {
        System.out.println("咪咪喵喵喵....");
    }
}

五.接口的特性

1.接口中的方法默认是抽象的(默认修饰符为public abstract),即只有方法声明(方法名和参数),没有具体实现。

如:

解释:可以看到methodA没有具体实现也没有报错,即默认的修饰符为public abstract,

在methodB中我们给其加上public abstract,但是public abstract是灰色的,一样可以说明接口的方法默认修饰符是public abstract。

2.接口中的属性默认是public static final,即常量,实现类不能修改它们的值。

报错:无法为最终变量“num”赋值

3.接口类型是一种引用类型,但是不能直接new接口的对象

如:

报错:“InterfaceA”是抽象的;无法实例化

4.重写接口中方法时,不能使用默认的访问权限

这里说一下:默认修饰符是default ,虽然没有直接写出来,但是不写编译器默认就是default。

ps:重写方法时访问权限修饰符不能比父类(接口)方法更严格。

  • 例如:父类方法是protected,重写的方法不能是private

而这里接口的方法修饰符原本是public,你使用默认default,范围变小了,自然不符。

5.接口中不能有静态代码块和构造方法

报错:

6.如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类

如:

个特性其实就是抽象类的特性。

7.接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class

这是因为在 Java 中,接口和类都属于 Java 字节码的一种表示形式,最终都会被编译成 JVM(Java 虚拟机)可以理解的 .class文件。

8. jdk8中:接口中还可以包含default方法。

六.实现多个接口

定义两个接口IFlyable和ISwimmable,分别表示会飞和会游泳的能力。

// Flyable 接口
public interface IFlyable {
    void fly();
}

// Swimmable 接口
public interface ISwimmable {
    void swim();
}

定义一个类Duck,它同时实现了FlyableSwimmable接口,并提供具体的实现。

注意多个接口用 '   '隔开

// Duck 类实现多个接口
public class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("Duck is flying.");
    }

    @Override
    public void swim() {
        System.out.println("Duck is swimming.");
    }
}

在主类中,通过不同的接口调用实现类的方法,体现接口的多态性。

public class Main {
    public static void main(String[] args) {
        // 创建 Duck 对象
        Duck duck = new Duck();

        // 使用 Flyable 接口类型调用 fly 方法
        Flyable flyingDuck = duck;
        flyingDuck.fly();

        // 使用 Swimmable 接口类型调用 swim 方法
        Swimmable swimmingDuck = duck;
        swimmingDuck.swim();

        // 直接使用 Duck 类型调用方法
        duck.fly();
        duck.swim();
    }
}

注意:一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类。

ps:IDEA 中使用 ctrl + i 快速实现接口

七.接口之间的继承

定义两个接口:

  1. 父接口 Animal,声明两个通用的方法:eat()sleep()
  2. 子接口 Bird,继承 Animal 并增加一个特定方法:fly()
// 父接口
public interface Animal {
    void eat();
    void sleep();
}

// 子接口继承父接口
public interface Bird extends Animal {
    void fly();
}

创建一个类 Sparrow(麻雀),实现子接口 Bird
由于 Bird 继承了 Animal,因此实现 Bird 接口时,也需要实现 Animal 中定义的所有方法。

// 实现子接口的类
public class Sparrow implements Bird {
    @Override
    public void eat() {
        System.out.println("麻雀吃种子.");
    }

    @Override
    public void sleep() {
        System.out.println("麻雀在鸟巢睡觉.");
    }

    @Override
    public void fly() {
        System.out.println("麻雀在空中飞翔.");
    }
}

定义一个测试类。

public class Main {
    public static void main(String[] args) {
        // 创建实现类对象
        Bird sparrow = new Sparrow();

        // 调用父接口中的方法
        sparrow.eat();
        sparrow.sleep();

        // 调用子接口中定义的方法
        sparrow.fly();
    }
}

 八.接口使用案例

1.Comparable 接口

Comparable接口是 Java 提供的一个用来定义对象自然排序的接口。它位于java.lang包中,并且常用于排序算法或排序集合(如TreeSetTreeMap等)中。

我们在一个学生类中实现它:

然后按住Ctrl 点击 Comparable,可以看到Comparable接口有一个单一的方法:

我们来翻译一下绿色字体:

简单来说:

  • compareTo()方法用于比较当前对象与指定对象的大小关系。
  • 返回值:
    • 负数:当前对象小于指定对象。
    • :当前对象等于指定对象。
    • 正数:当前对象大于指定对象。

在实现Comparable接口之前:

import java.util.*;

// 定义 Student 类
public class Student {
    private String name;
    private int age;

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

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

-----------------------------------------------------------------
//测试类
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        // 数组存储对象
        Student[] students={
                new Student("Alice", 20),
                new Student("Bob", 18),
                new Student("Charlie", 22)
        };

        // 使用 Arrays.sort 排序
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));

    }
}


输出报错,意思就是不能直接使用Arrays.sort排序:

实现Comparable接口之后:

import java.util.*;

// 定义 Student 类
public class Student implements Comparable<Student> {
    private String name;
    private int age;

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

    // 实现 compareTo 方法,按年龄排序(升序)
    @Override
    public int compareTo(Student other) {
        return Integer.compare(this.age, other.age);
    }

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

-------------------------------------------------------------------
//测试类
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        // 数组存储对象
        Student[] students={
                new Student("Alice", 20),
                new Student("Bob", 18),
                new Student("Charlie", 22)
        };

        // 使用 Arrays.sort 排序
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));

    }
}

输出:

ps:

为什么Arrays.sort() 会在排序时调用每个对象的 compareTo() 方法?

它适用于数组中的对象,而非集合。对于实现了 Comparable 接口的对象数组,Arrays.sort() 会使用这些对象的 compareTo() 方法来进行排序。而且Arrays.sort() 的部分源码内部实现了调用 compareTo() 方法。

2.Clonable 接口和深拷贝

Cloneable 是一个标记接口,用于指示一个类的对象可以通过调用 Object 类的 clone() 方法来进行字段级别的拷贝。

特性:

  • 实现 Cloneable 接口
    一个类实现了 Cloneable 接口,表明它的对象可以被克隆,否则调用 clone() 方法时会抛出 CloneNotSupportedException

  • 重写 clone() 方法
    默认情况下,Objectclone() 方法是受保护的(protected),需要在子类中重写为 public 并调用 super.clone()

  • 浅拷贝
    clone() 方法默认执行浅拷贝,即对对象的基本数据类型字段进行值拷贝,对引用类型字段仅拷贝引用,而不是创建新的对象。

我们来看一段浅拷贝的代码:

class Money {
    public double m = 99.99;
}
 
class Person implements Cloneable{
    public Money money = new Money();
 
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
   }
}

--------------------------------------------------------------------
//测试类
 
public class TestDemo3 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person();
        Person person2 = (Person) person1.clone();
        System.out.println("通过person2修改前的结果");
        System.out.println(person1.money.m); 
        System.out.println(person2.money.m);
        person2.money.m = 13.6;
        System.out.println("通过person2修改后的结果");
        //修改后,打印输出我们发现两个值都改了,没有达到我们想要的效果
        //这是因为在我们上面进行克隆操作的时候对象animal的对象m的地址也克隆过去了,
        // 两个对象(person1和person2)的对象m的地址都一样,所以进行修改的时候两个值都修改了
        //所以我们得再次重写一下clone方法
        System.out.println(person1.money.m);
        System.out.println(person2.money.m);
   }
}

输出结果为:

代码解释:代码中会发生 浅拷贝,导致 person1person2money 字段引用的是同一个 Money 对象。因此,通过 person2.money.m 修改的值,会反映到 person1.money.m 上。这是因为 clone() 方法默认只是复制对象的字段引用,而不是深度复制它们。

ps小细节:

那么我们应该怎么修改呢?这就用到深拷贝了,如下代码:

class Money implements Cloneable{
    public double  m=99.99;

    //实现了 Cloneable 接口以支持克隆。
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Animal implements Cloneable{
    public Money money;
   private String name;

    public Animal(String name, double money) {
        this.money=new Money();
        this.name = name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //进行修改后
        //调用 super.clone() 克隆当前对象,复制基本字段。
        //手动克隆引用类型字段 money,确保克隆后的 money 是一个新的对象,而不是指向原对象的引用(            实现深拷贝)。
        Animal tmp=(Animal)super.clone();
        tmp.money=(Money)this.money.clone();
        return tmp;
    }


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

}


-------------------------------------------------------------------------
//测试类

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Animal animal=new Animal("小黑",99.99);
        Animal animal1= (Animal) animal.clone();

        System.out.println(animal);
        System.out.println(animal1);

        System.out.println(animal==animal1);

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

        System.out.println("修改前");
        System.out.println(animal.money.m);
        System.out.println(animal1.money.m);

        animal.money.m=122.99;
        
        System.out.println("修改后");
        System.out.println(animal.money.m);
        System.out.println(animal1.money.m);

    }
}

输出结果为:

九.接口和抽象类的区别

特性 接口 抽象类
多继承支持 支持,类可实现多个接口 不支持,一个类只能继承一个抽象类
字段 只能定义常量(public static final 可定义任意字段
构造方法 不允许 可以有构造方法
方法 默认是抽象方法,可有默认、静态和私有方法 可定义抽象方法和具体方法
子类使用 使用implements实现接口 使用extends继承抽象类
权限 public 各种权限


网站公告

今日签到

点亮在社区的每一天
去签到