Java接口

定义:Java接口(英文名:interface)是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。

接口更像是一个模具,它提供应该有的样子,而具体的内容(方法)实现,需要继承接口的类去实现。有了接口就可以让一个类去实现多个接口,具有多个接口的特征,填补了java继承只能有一个父类的弊端。

1、接口的创建

这里先举一个简单的创建接口的形式:

package cn.edu.ncu.inter;

public interface Human {

    int family = 1;       //隐含是public static final,可以不写出来

    void eat();     //隐含是public abstract ,可以不写出来
    void sleep();
    void pee();
}

语法格式:

[可见度] interface 接口名称 [extends 其他的类名] {
    // 声明变量        
    // 抽象方法 

}

2、接口中属性和方法的限制

可以看到,在创建接口时,对于修饰符有严格的要求,可以不写出来,但是写就不能有错误

对于接口的属性

  • 修饰符只能是public static final
  • 属性必须赋初值,否则会报错

对于接口的方法:

  • 修饰符只能是public abstract

对于接口:

  • 修饰符只能是public

出现接口的初衷,就是为了提供一系列的方法的特征,去让类实现,属性在接口中无太大意义,所以它的修饰符只能是public static final,只读且只有一份。

3、接口的实现

类继承接口,则必须将接口中的所有方法实现,否则会报错

package cn.edu.ncu.inter;

public class Chinese implements Human {   //Human接口定义请看 1、接口的创建

    @Override
    public void eat() {
        System.out.println("We Chinese eat");
    }

    @Override
    public void sleep() {
        System.out.println("We Chinese sleep");
    }

    @Override
    public void pee() {
        System.out.println("We Chinese pee");
    }


    public static void main(String... args){

        Chinese cn1 = new Chinese();
        cn1.sleep();	//We Chinese sleep
    }
}

其中方法上的“@Override”表示检测是否以实现接口中的方法,如果未实现,会出现编译报错。

语法格式:

可见度 class 类名 implements 要实现的接口(可以多个,逗号隔开) {

   
    所有要实现的接口中的方法
    ···
    ···
    ···

}

注意:

  • 尽管public修饰符在接口中可以省略掉,但是在实现这个接口的类中,实现的方法必须使用public修饰,且不可省略

  • 在Java 8中,可以使用关键字default修饰接口方法,但是该方法必须有方法体。在实现该接口时,类可以直接使用该方法,不需要再去实现,也可以去重写该方法。

    在Asian接口中添加一个默认方法(Japan类和Asian的出处可移步“4、接口的继承”)

    default void learn(){
        System.out.println("We study very hard.");
    }
    

    在Japan类中添加主方法创建Japen实例,直接使用该方法

    public static void main(String... args){
        Japan japanese = new Japan();
        japanese.learn();		//We study very hard.
    }
    
  • 在Java 8中,允许接口存在公有的静态方法,接口中的静态方法和类中的公有静态方法一样使用

  • 使用instanceof 检查类型,可以发现japanese实例也属于Comparable

    System.out.println(japanese instanceof Comparable);    //ture
    

4、接口的继承

接口的继承类似于类的继承,同样使用“extends”关键字,但是在接口的继承中允许一个接口继承多个类。如果一个接口继承了另一个接口,那么实现这个接口的类,就必须将这两个接口中的所有方法实现。

package cn.edu.ncu.inter;

public interface Asian extends Human{	//Human接口定义请看 1、接口的创建

    void shit();
    void asianSquats();
}

实现Asian接口的Japan类

package cn.edu.ncu.inter;

public class Japan implements Asian{

    @Override
    public void eat() {
        System.out.println("we Japan eat");
    }

    @Override
    public void sleep() {
        System.out.println("we Japan sleep");
    }

    @Override
    public void pee() {
        System.out.println("we Japan pee");
    }

    @Override
    public void shit() {
        System.out.println("we Japan shit");
    }

    @Override
    public void asianSquats() {
        System.out.println("we Japan asianSquats");		
    }

}

5、Java API中两个重要的接口——Comparable接口

Comparable接口用于实现对象的可比较性,在java.lang包中,有着Comparable接口的定义

package java.lang;
import java.util.*;
public interface Comparable<T> {
    public int compareTo(T o);
}
  • 这里的T表示泛型,可以被替换成一种具体的类型
  • Comparable接口已经被Byte、Short、Integer、Long、Float、Double、Character、BigInteger、BigDecimal、Calendar、String以及Date实现了,小于返回-1,等于返回0,大于返回1

关于实现Comparable接口的一个例子

package cn.edu.ncu.inter;

public class Chinese implements Human,Comparable<Chinese> {	//Human接口定义请看 1、接口的创建

    private int age;
    private String sex;

    public Chinese(int age, String sex) {
        this.age = age;
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public String getSex() {
        return sex;
    }

    @Override
    public void eat() {
        System.out.println("we Chinese eat");
    }

    @Override
    public void sleep() {
        System.out.println("we Chinese sleep");
    }

    @Override
    public void pee() {
        System.out.println("we Chinese pee");
    }



    @Override
    public int compareTo(Chinese o) {
        if (getAge()>o.getAge())
            return 1;
        else if(getAge()<o.getAge()){
            return -1;
        }
        else
            return 0;
    }

}

创建Chinese的实例,使用compareTo方法

package cn.edu.ncu.inter;

public class Test {
    public static void main(String... args){
        Chinese chinese1 = new Chinese(22,"男");
        Chinese chinese2 = new Chinese(12,"女");
        System.out.println(chinese2.compareTo(chinese1));		//-1
    }
}

注意:

  • 在实现Comparable接口时,“implement Compareable<Chinese>”,必须要将泛型替换成相应的要比较的类
  • 在Chinese对compareTo方法实现中,将自己实例的age与另一Chinese类的实例的age进行比较,自己可以使用this.getAge(),也可以省略this,直接写getAge

java.util.Arrays.sort(Object[ ])方法

定义的java.util.Arrays.sort(Object[])方法中,利用到了对象的compareTo方法,进而来对对象进行排序

java源码中sort方法的定义:

public static void sort(Object[] a) {
    if (LegacyMergeSort.userRequested)
        legacyMergeSort(a);
    else
        ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}

利用sort方法的一个例子

package cn.edu.ncu.inter;

public class Test {
    public static void main(String... args){
        Chinese chinese1 = new Chinese(22,"男");
        Chinese chinese2 = new Chinese(12,"女");
        Chinese chinese3 = new Chinese(43,"女");
        Chinese chinese4 = new Chinese(2,"女");
        Chinese chinese5 = new Chinese(12,"女");

        Chinese[] chinese = {chinese1, chinese2,chinese3, chinese4,chinese5};
        java.util.Arrays.sort(chinese);

        for (Chinese cn:chinese
             ) {
            System.out.println(cn);
        }
    }
}

输出:

在这里插入图片描述

Object类中也有一个比较的方法equals,为了防止两者不冲突,对于两个对象o1和o2,应该确保当且仅当o1.equals(o2)为true时o1.compareTo(o2)==0成立,为此可以重写equals方法

6、Java API中两个重要的接口——Cloneable接口

Cloneable接口是一个特殊的接口,是一个空的接口,叫做标记接口(方法体为空的接口),表示该对象可以通过clone方法实现复制。虽然为空,但是Object类中的clone()方法利用这一标记,实现了可克隆。

Cloneable接口的定义

public interface Cloneable {
}

Java库中的很多类(例如,Date、Calendar和ArrayList)实现了Cloneable。这样这些类的实例可以被克隆。例如,下面的代码

package cn.edu.ncu.inter;

import java.util.Calendar;
import java.util.GregorianCalendar;

public class Test {
    public static void main(String... args){

        Calendar calendar = new GregorianCalendar(2013,2,1);
        Calendar calendar1 = calendar;
        Calendar calendar2 = (Calendar) calendar.clone();
        System.out.println("calendar == calendar1 is "+
                (calendar == calendar1));
        System.out.println("calendar == calendar2 is "+
                (calendar == calendar2));
        System.out.println("calendar.equals(calendar2) is "+
                calendar.equals(calendar2));
    }

}

输出结果

在这里插入图片描述

calendar 和 calendar1指向的是同一个对象,而使用clone()后,另外开辟了一块新的空间,复制calendar指向的对象,该对象由calendar2引用。

特别说明的是,类似于ArrayList的集合框架也是可以复制的。

实现Cloneable接口的自定义类

在自定义类中,也要实现Cloneable接口,需要重写Object中的clone方法,一般固定为如下写法

@Override
public Object clone(){
    
    try{
        return super.clone();
    }
    catch (CloneNotSupportedException ex){
        return null
    }
}

Object中的clone方法定义的方法头如下:

protected native Object clone() throws ClonesNotSupportedException;

说明:

  • 实现Cloneable接口的自定义类,只有将protected改为public,才能让该方法在任何一个包中都可以使用

  • 自定义类,克隆的对象实例中,对于数据域是基本数据类型,复制的是它的值,而如果数据域是对象,复制的就是该域的引用。

    如下图,有两个对象实例,house1和house2(被clone之后的House),whenBuilt是Date类,只能复制该域的引用,默认的clone方法克隆的叫做浅复制,定制的clone方法可以实现深复制

在这里插入图片描述

为实现深复制,可以将clone()方法重写为如下形式

public Object clone() throws CloneNotSupportedException{

    //Perform a shallow copy
    House houseClone = (House)super.clone();
    //Deep copy on whenBuilt
    houseClone.whenBuilt = (java.util.Date)(whenBuilt.clone());
    return houseClone;
}

或者

public Object clone(){
    try{
        //Perform a shallow copy
        House houseClone = (House)super.clone();
        //Deep copy on whenBuilt
        houseClone.whenBuilt = (java.util.Date)(whenBuilt.clone());
        return houseClone;
    }
    catch (CloneNotSupportedException ex){
        return null;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

upupoo577

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值