JAVA_EVLEN-面向对象高级二
一 认识多态
定义:
多态是在继承/实现情况下的一种现象,表现为对象多态,行为多态。
前提条件:
有继承/实现关系;存在父类引用子类对象;存在方法重写。
注意事项:
多态是对象,行为的多态,Java中的属性(成员变量)不谈多态。
好处:
1.在多态模式下,右边的对象是解耦合的,更便于扩展和维护。
解耦合:例拆分成一个一个服务,可以随时进行对接。
2.定义方法时,使用父类类型的形参,可以接受一切子类对象,扩展性更强。
存在问题:
多态下不能直接调用子类的独有方法。
解决方法:
强制类型转换 子类 变量名=(子类) 父类变量
强制类型转换注意事项:
强制类型转换可能存在的问题,编译阶段没有继承或者实现关系就可以强制转换,但运行时可能出现类型转换异常
使用 instanceof判断当前对象的真实类型:
格式:对象 instanceof 类型
-
多态代码
public class Test {public static void main(String[] args) {//认识多态:对象多态,行为多态//1.对象多态People p1=new Teacher();p1.run(); //识别技巧:编译看左边,运行看右边System.out.println(p1.name);//识别技巧:编译看左边,运行看左边People p2=new Student();p2.run(); //识别技巧:编译看左边,运行看右边System.out.println(p2.name);//识别技巧:编译看左边,运行看左边} }
public class Test2 {public static void main(String[] args) {//目标:理解多态的好处//好处1:在多态模式下,右边的对象是解耦合的,更便于扩展和维护。People p1=new Student();p1.run(); // p1.test(); //多态存在的问题,无法调用子类的独有功能//强制类型转换Student s1= (Student) p1;s1.test();//强制类型转换可能存在的问题,编译阶段没有继承或者实现关系就可以强制转换,但运行时可能出现类型转换异常 // Teacher t1=(Teacher)p1; //会出现类型转换异常Student s=new Student();go(s);Teacher t=new Teacher();go(t);}//好处2:使用父类类型的形参,可以接受一切子类对象,扩展性更强。public static void go(People p){p.run();if(p instanceof Student){Student s=(Student) p;s.test();} else if (p instanceof Teacher) {Teacher t=(Teacher) p;t.teach();}} }
public class People {public String name="父类People的name";public void run(){System.out.println("人可以跑~~~");}}
public class Student extends People{public String name="子类Student的name";@Overridepublic void run() {System.out.println("学生跑的快~~~");}public void test(){System.out.println("学生要考试~~~");} }
public class Teacher extends People{public String name="子类Teacher的name";@Overridepublic void run() {System.out.println("老师跑的慢~~~");}public void teach(){System.out.println("老师要教书~~~");} }
二 final
final:
final关键字是最终的意思,可以修饰(类,方法,变量)
修饰类:该类称为最终类,特点是不能被继承了
修饰方法:该方法被称为最终方法,特点是不能被重写了。
修饰变量:该变量只能被赋值一次
注意:
final修饰基本类型的变量,变量存储的数据不能被改变
final修饰引用类型的变量,变量存储的地址不能被改变,但地址指向对象的内容是可以改变的
扩展(变量):
局部变量
成员变量:
1.静态成员变量 2.实例成员变量
扩展(常量):
使用了static final修饰的成员变量称为常量
作用:通常用于记录系统的配置信息
优势及执行原理:
1.代码可读性更好,可维护性更好
2.程序编译后,会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,
这样可以保证使用常量和直接使用字面量的性能是一样的
三 抽象类
是什么样的
都是abstruct修饰的;抽象方法只有方法签名,不能写方法体。0
注意事项和特点:
1.抽象类中可以不写抽象方法,但有抽象方法的类一定是抽象类
2.类的成员(成员变量,方法,构造器)抽象类都具备
3.抽象类不能创建对象,仅能作为一种特殊的父类,让子类继承并实现
使用抽象类的好处:
父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们抽出这样的抽象类,就是为了更好的支持多态
-
抽象类代码举例
public class Test {public static void main(String[] args) {Animals dog=new Dog();dog.setName("旺财");dog.cry();System.out.println("-----------------");Animals cat=new Cat();dog.setName("喵吉");dog.cry();} }
public abstract class Animals {private String name;public abstract void cry();public String getName() {return name;}public void setName(String name) {this.name = name;} }
public class Cat extends Animals{@Overridepublic void cry() {System.out.println(getName()+"喵喵~~~");} }
public class Dog extends Animals{@Overridepublic void cry() {System.out.println(getName()+"汪汪~~~");} }
抽象类常用的应用场景(模版方法设计模式)
解决问题:
解决代码中存在重复代码的问题
如何写:
定义一个抽象类,
在里面定义2个方法,一个是模版方法:放相同的代码里,
一个是抽象方法:具体交给子类去完成。
(建议使用final关键字修饰模版,提供保护)
-
模版方法设计模式举例代码
public class Test {public static void main(String[] args) {People child=new Child();child.writing();System.out.println("------------------");People animal=new Animal();animal.writing();} }
public abstract class People {public final void writing(){System.out.println("天空下起了朦胧的小雨,\\t");System.out.println("我举着一把老旧的油纸伞,穿梭于鳞次栉比的巷子之间,");writmain();}public abstract void writmain();}
public class Child extends People{@Overridepublic void writmain() {System.out.println("寻找着我妹妹的踪迹.");} }
public class Animal extends People{@Overridepublic void writmain() {System.out.println("寻找着那只白色的小猫.");} }
四 接口(interface)
认识接口
Java提供了一个关键字interface,用这个关键字我们可以定义一个特殊的结构:接口
public interface 接口名{
//成员变量(常量)
//成员方法(抽象方法)
}
注意:接口不能用来创建对象;接口是用来被类实现(implements)的,实现接口的类称之为实现类
修饰符 class 实现类 implements 接口1,接口2,接口3,…{
}
一个类可以实现多个接口(接口可以理解为干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类
使用接口的好处
1.可以解决类单继承的问题,通过接口,我们可以让一个类有一个亲爹的同时,还可拥有多个干爹去拓展自己的功能
2.一个类我们说可以实现多个接口,同样,一个接口也可以被多个类实现的。这样做的好处是我们的程序就可以面向接口编程了,这样我们程序员就可以很方便的灵活切换各种业务实现了
接口-综合案例
JDK8开始新增的方法
1.默认方法:使用default修饰,使用实现类的对象调用
2.静态方法:static方法,必须用当前接口名调用
3.私有方法:private修饰,jdk9开始,只有在接口内部使用
4.他们都会默认采用public修饰
为什么JDK8开始新增这些方法
增强了接口的能力,更便于项目的扩展与维护
使用接口的注意事项
1.一个接口继承多个接口,如果多个接口存在方法签名冲突,则此时不支持多继承
2.一个类实现了多个接口,如果多个接口存在方法名冲突,则此时不支持多实现
3.一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类优先使用父类
4.一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可
-
使用接口的注意事项举例代码
public class Test {public static void main(String[] args) {Zi zi=new Zi();zi.run(); //打印====父类run方法执行了====System.out.println("---------------");IT3 it3=new IT3();it3.run(); //打印====IT3===} }//1.一个接口继承多个接口,如果多个接口存在方法签名冲突,则此时不支持多继承 interface I{void test1(); }interface J{String test1(); }//interface K extends I ,J{ // //}//2.一个类实现了多个接口,如果多个接口存在方法名冲突,则此时不支持多实现 /* class E implements I,J{}*///3.一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类优先使用父类 class Fu{public void run(){System.out.println("====父类run方法执行了====");} }interface IT{default void run(){System.out.println("====ITrun方法执行了====");} }class Zi extends Fu implements IT{}//4.一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可 interface IT1{default void run(){System.out.println("====IT1====");} }interface IT2{default void run(){System.out.println("====IT2====");} }class IT3 implements IT1,IT2{@Overridepublic void run() {System.out.println("====IT3===");} }