0、回顾
(1)final:终结器
被final修饰的属性值不能改(基本类型就是数值不变,引用类型保存的地址值不变)
被final修饰的方法不能重写
被final修饰的类不能有子类
(2)向下转型:
①语法︰ 子类名称 子类引用 = (子类名称) 父类引用;Dog dog = (Dog) animal;
· 要求∶要发生向下转型首先需要发生向上转型,父类引用必须要和当前子类的对象建立联系。即animal实际上指向的就是Dog类的对象
Animal animal = new Dog(0);
· 向下转型存在类型转换异常的风险,因此要使用向下转型可以借助instanceof关键字只有这个关键字返回true,再使用向下转型:
引用名称 instanceof 类名称 -> true或false,表示该引用是否指向一个类的对象
②向下转型一般用在向上转型的过程中,需要调用某些子类独有的方法或属性Animal animal = new Dog();
· 通过animal引用能够调用哪些方法,要看Animal父类中有哪些方法
· 至于调用方法到底调用的是子类中的方法还是父类中的方法,要看new在哪。若产生的是子类对象且该子类覆写了调用方法,则一定调用子类覆写后的方法
· 若需要调用子类中独有的方法,就需要还原这个animal引用为子类引用,这就是向下转型的应用场景:和向上转型搭配使用
③向上转型∶参数统一化,降低圈复杂度(减少大量的if-else语句)
向下转型:在向上转型过程中调用某些子类独有的方法
1、要实现多态,最核心的依赖于继承与方法重写,关键问题在于父类无法强制要求子类重写方法。因此,就该定义抽象类
(1)抽象类:
普通类的超集,只是比普通类多了一些[0~N]抽象方法而已。
①使用关键字abstract来定义抽象类与抽象方法abstract class A{ //抽象类 public abstract void testA(); //抽象方法(只声明) }
· 只要类使用abstract来定义,这个类无论是否包含抽象方法,都是抽象类。
· 抽象类无法直接实例化对象。因为这个类本身就是一个抽象的概念,不存在具体对象
· 抽象类必须有子类,子类继承抽象类后必须要覆写所有的抽象方法(前提:该子类是普通类,若该子类是抽象类,可以不覆写抽象方法)
· 抽象方法使用abstract来定义,只有方法声明,没有方法体的方法称为抽象方法。只有在子类覆写该方法时,该方法才有了具体实现,在抽象类中,该方法只有声明
*在Java中,没有方法体的方法一定是抽象方法?
答案错!Java中还有一类方法没有方法体,只有方法声明,使用native关键字声明,这种方法称为本地方法本地方法指的是,Java调用C++实现的代码,具体的方法实现在C++代码中,Java只是调用。(JVM:本身就是C++实现的,有大量的C++函数,Java直接调用)。JNDI平台,借助这个开发平台,可以实现在Java中调用C++的代码。Oracle(Java公司)未来JVM可以直接运行C++的项目。
(2)若有抽象类A其中有抽象方法x(),抽象类B继承抽象类A其中有抽象方法y(),则普通类C继承B时,必须要把x()、y()都覆写,
(3)抽象类只是比普通类多了一些抽象方法而已,抽象类的内部仍然可以存在构造方法与普通方法
虽然抽象类无法直接实例化对象,子类在产生对象时,仍然满足继承的原则,先调用父类的构造方法实例化父类,然后再调用子类构造
2、要对子类进行一些强制性的方法覆写要求,会用到抽象类。但是即便是抽象类,子类也仍然存在单继承局限的要求,以及必须满足is a原则,继承的类之间,是一个垂直结构的树形关系。
3、接口∶之后能使用抽象类也能使用接口实现的场景下,优先考虑使用接口实现。接口优先原则
(1)定义︰
接口中只存在全局常量与抽象方法(JDK8之前),在Java中,接口使用interface关键字来定义.
· 接口当中的成员变量默认是:public static final
· 接口当中的成员方法默认是:public abstract
(2)接口的命名规范:使用大写的l开头
(3)接口的子类,称为实现接口
①子类要实现接口,使用 implements 关键字来表示子类实现(约等于继承)接口,子类必须覆写接口中的所有抽象方法(前提∶子类是普通类)
②子类的命名∶以父类接口名称开头,以impl结尾。例如 MessageImpl : 一眼看上去就知道是IMessage接口的子类
③接口中只能定义全局常量与抽象方法,不能存在构造方法,不能存在成员变量,因此接口是一个更加"纯粹"的抽象类。接口无法直接实例化对象,需要通过子类向上转型为其实例化
(4)接口使用原则:
①由于接口中只存在抽象方法与全局常量,因此,在接口定义中,以下关键字统统都可以省略,且在阿里编码规约中明确表示,以下关键字不要出现在接口的定义中
· public //描述属性
· static final //描述常量
· abstract //描述抽象方法
②子类可以同时实现多个父接口(打破抽象类的单继承局限~~)
实现多个父接口,用逗号分隔。若子类同时实现了多个父接口,则必须覆写这些接口中的所有抽象方法(前提︰子类是普通类)
③当子类同时需要实现多个父接口,以及继承一个抽象类时,请先使用extends继承一个类,而后使用implements实现多个接口class MessageImplNew extends News implements IMessage{ //覆写方法 }
· 按顺序,先写extends类,再写implement接口
④接口不能使用extends继承类,但是接口可以使用extends来继承父接口,而且可以继承多个
4、抽象类与接口比较
5、接口的应用场景
(1)接口表示标准或规范(以USB为例)
①USB接口就是表示一种规范/标准public interface USB { void setUp(); //安装驱动 void work(); //正常工件 }
②鼠标
public class Mouse implements USB{ @Override public void setup(){ System.out.print1n("安装鼠标驱动中.."); } @Override public void work() { system.out.println("鼠标正常工作~"); } }
③键盘
public class KeyBoard implements USB{ @Override public void setup() { system.out.println("安装键盘驱动中.."); } @Override public void work() { system.out.println("键盘正常工作~"); } }
④模拟USB插槽(电脑对外提供的方法)
public class Computer { public void plugIn(USB usb){ usb.setUp(); usb.work(); } public static void main(String[] args) { Computer computer = new Computer(); Mouse mouse = new Mouse(); computer.plugIn(mouse); //需要将鼠标对象连接到电脑上 KeyBoard keyBoard = new KeyBoard(); computer.plugIn(keyBoard); //需要将键盘对象连接到电脑上 } }
(2)接口表示一种能力/行为
①Cat就具备在地上跑的能力public class Cat extends Animal implements IRun{...}
②Dog就具备了地上跑,水里游的能力
public class Dog extends AnimaL implements IRun,ISwim{...}
③Duck具备地上跑,水里游,天生飞的能力
public class Duck extends Animal implements IRun,ISwim,IFLy{...}
④可以方便调用不同的方法
public static void main(String[] args){ Dog dog = new Dog("66",7); Cat cat = new Cat("元宝",7); Robot robot = new Robot(); fun(dog); fun(cat); fun(robot); } //调用传入对象的run方法 public static void fun(IRun runObj) { runObj.run(); }
6、JDK中的常用接口
(1)java.lang.Comparable接口compareTo方法
int[] nums = {1,5,3,2,6,8,9,7}; Arrays.sort(nums); //对nums,数组排序
· 此时可以正常排序
student[] students = new Student[3]; students[e] = new Student("铭哥",65); students[1] = new Student("子健",90); students[2] = new Student("云超",77.8); Arrays.sort( students);
(2)当传入对象时自定义类时则无法完成排序,需要在Student类里覆写compareTo方法来实现排序
①原本内容public int compareTo(Object o){ return 0; }
· return < 0 :表示当前对象 < 传入对象o
· return == 0 :表示当前对象 == 传入对象o
· return > 0 ∶表示当前对象 > 目标对象o
②覆写后@override public int compareTo(Object o) { if (this == o){ //判断传入对象是否当前对象是同一个引用 return 0; }else if(!(o instanceof Student)) { return -1; //判断是否是Student类型 }else { //此时o一定是Student类型,且和当前对象不是同一个Student对象 Student stu = (student) o; return (int)(this.score - stu.score); } }
· 此时将传入对象按照成绩升序排序(降序的话,把return 后面的改一下)