【Java SE】抽象类和接口

目录

抽象类

♪ 什么是抽象类

♪ 抽象类的特性

♪ 抽象类的作用

接口

♪ 什么是接口

♪ 接口的特性

♪ 接口的实现样例

抽象类和接口的区别 


抽象类

♪ 什么是抽象类

抽象类是一个被 abstract 修饰的类,它除了可以含有普通类的方法,属性和构造方法外还可以包含一种被 abstract 修饰的抽象方法(抽象方法不用给出具体的实现体)。

public abstract class Test {
    //抽象方法(被abstract修饰,没有方法体)
    public abstract void method1();
    //也可以包含普通方法,属性和构造方法
    int a;
    public void method2(){
        System.out.println("hhh");
    }
    public Test(int a){
        this.a = a;
    }
}

♪ 抽象类的特性

1.抽象类必须被继承,且子类如果不是抽象类则必须重写父类中的抽象方法

abstract class A{
    public abstract void method();
}
//子类不是抽象类:必须重写抽象方法
class B extends A{
    @Override
    public void method(){
        System.out.println("hhh");
    }
}
//子类为抽象类可以不重写抽象方法
abstract class C extends A{
    int a;
}

2.抽象类不能直接实例化对象

public abstract class Test {
    public abstract void method();
    public static void main(String[] args) {
        Test test = new Test();//'Test' 为 abstract;无法实例化
    }
}

3.抽象方法需要被重写,故不能被 private,final,static 修饰

public abstract class Test{
    private abstract void method1();//error:非法的修饰符组合:‘abstract’和‘private’
    public abstract final void method2();//error:非法的修饰符组合:‘abstract’和‘final’
    public abstract static void method3();//error:非法的修饰符组合:‘abstract’和‘static’
}

4.抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类

♪ 抽象类的作用

使用抽象类相当于多了一重编译器的校验:如果一个实际工作不应该由父类完成, 而应由子类完成 . 那么此时如果不小心误用成父类了, 使用普通类编译器是不会报错的 . 但是父类是抽象类就会在实例化的时候提示错误 , 让我们尽早发现问题。
故使用抽象类可以充分利用编译器的效验

接口

♪ 什么是接口

日常生活中存在许多接口(笔记本电脑上的USB口,电源插座等),他们都是公共的行为规范标准,在使用时,只要符合规范标准,就可以通用。

Java中的接口与与之类似,它可以看成是多个类的公共规范,是一种引用数据类型 
接口的定义格式与类的定义格式基本相同,将 class 关键字换成 interface 关键字即可
public interface ITest{
    int a = 10;//默认被public static final修饰
    void method();//默认被public abstract修饰
}

也可以在用 abstract 关键字修饰接口(一般不写)

public abstract interface Test{
    int a = 10;//默认被public static final修饰
    void method();//默认被public abstract修饰
}

注:接口的命名一般以 I 为开头,命名一般使用形容词

♪ 接口的特性

1.接口不能直接实例化

interface ITest{
    void method1();
}
public class Test {
    public static void main(String[] args) {
        ITest iTest = new ITest();//error:'ITest' 为 abstract;无法实例化
    }
}

2.接口中的方法默认是 public abstract ,且只能是 public abstract

interface ITest{
    void method1();//默认被public abstrcat修饰
    public abstract void method2();//不推荐加上默认修饰的写法
    void method3(){}//error:接口 abstract 方法不能有主体
    private abstract void method4();//error:非法的修饰符组合: 'abstract' 和'private'
    private void method5();//此处不允许使用修饰符 'private'
    final void method6();//error:非法的修饰符组合: 'final' 和'abstract'
    
}

注:jdk8中接口还可以包含default 方法和 public static 方法,这两种方法应具有主体

3.接口中的属性默认是 public static final ,且只能是 public static final 

public interface ITest{
    int a = 10;//默认被public static final修饰
    public static final int b = 20;//不推荐把默认修饰加上的写法
    private int c = 10;//error:此处不允许使用修饰符 'private'
    int d;//error:变量 'd' 可能尚未初始化

}

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

interface ITest{
    public ITest(){}//error:在接口中不允许
    {}//error:在接口中不允许
    static{}//error:在接口中不允许

}

5.接口可以通过 ​​​​​​​extends 关键字继承一个或多个接口

interface I1{
    void method1();
}
interface I2{
    void method2();
}
//继承一个接口
interface I3 extends I1{
    void method3();
}
//继承多个接口
interface I4 extends I1, I2{
    void method4();
}

6.接口不能直接使用,必须要有一个“实现类”通过 implement 关键字“实现”该接口

interface ITest{
    void method();
}
public class Test implements ITest{
    @Override
    public void method(){//重写方法的访问修饰符不能小于重写前
        System.out.println("hhh");
    }
}

注 

1.重写方法的访问修饰符不能小于重写前的访问修饰符

2.如果类没有全部重写接口中的所以抽象方法,则必须定义为抽象类

3.一个类也可以实现多个接口(用,分开),但必须重写全部的抽象方法

♪ 接口的实现样例

给定一个学生对象数组,我们要如何根据成绩高低对数组中元素进行排序呢?

class 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{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        Student[] students = new Student[]{
                new Student("老六", 99),
                new Student("小七", 95),
                new Student("小八", 97),
        };
    }
}

我们知道数组中有一个现成的sort方法,那么是否可以直接使用这个方法对数组进行排序呢?

import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        Student[] students = new Student[]{
                new Student("老六", 99),
                new Student("小七", 95),
                new Student("小八", 97),
        };
        Arrays.sort(students);//运行出错
        System.out.println(Arrays.toString(students));
    }
}

在main函数里直接使用sort方法在运行时会出错。可见两个学生对象的大小不像整数那样可以直接比较,需要我们额外指定。

那应该怎样额外指定比较规则呢?在 sort 方法中会自动调用compareTo方法。对于 sort 方法来说,   需要传入的数组的每个对象都是 " 可比较 " 需要具备 compareTo 这样的能力 .。因此 通过重写 compareTo 方法的方式 , 就可以定义比较规则
import java.util.Arrays;


class Student implements Comparable{
    private String name;
    private int score;
    public Student(String name, int score){
        this.name = name;
        this.score = score;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        Student student = (Student)o;
        return student.score - this.score;
    }
}
public class Test {
    public static void main(String[] args) {
        Student[] students = new Student[]{
                new Student("老六", 99),
                new Student("小七", 95),
                new Student("小八", 97),
        };
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
    }
}

通过重写compareTo方法就能将对students对象里的元素按成绩高低进行排序

为了进一步加深对接口的理解 , 我们可以尝试自己实现一个 sort 方法来完成刚才的排序过程 ( 使用冒泡排序 )
public class Test {
    public static void sort(Comparable[] array){
        for(int bound = 0; bound < array.length; bound++){
            for(int cur = array.length - 1; cur > bound; cur--){
                if(array[cur - 1].compareTo(array[cur]) > 0){
                    Comparable tmp = array[cur - 1];
                    array[cur - 1] = array[cur];
                    array[cur] = tmp;
                }
            }
        }
    }
}

抽象类和接口的区别 

相同点

抽象类和接口都不能直接实例化,都只有在“实现类”/“子类”重写全部抽象方法后才能被实例化

不同点

1.接口只有定义,不能有方法的实现,jdk8中可以定义default方法体,而抽象类可以有定义与实现,方法可在抽象类中实现。

2.实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,但一个类只能继承一个抽象类。

3.接口强调特定功能的实现(相当于has a),而抽象类强调所属关系(相当于is a)。

4.接口成员属性默认是public static final(被final修饰,是不能修改的常量),成员方法默认是public abstract,不能包含普通方法和字段;抽象类中成员属性和方法默认default,可以包含普通方法和普通字段。

No区别抽象类(abstract)接口(interface)
1结构组成普通类+抽象方法抽象方法+全局常量
2权限各种权限public
3子类使用使用extends关键字继承抽象类使用implements关键字实现接口
4关系一个抽象类可以实现若干个接口接口不能继承抽象类,但接口可以使用extends关键字继承多个接口
5子类限制一个类只能继承一个抽象类一个类可以实现多个接口

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

记得开心一点啊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值