目录
抽象类
♪ 什么是抽象类
抽象类是一个被 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 子类限制 一个类只能继承一个抽象类 一个类可以实现多个接口