1.多态性
1.0个人理解
- 面向对象多态这个点其实是比较难理解的,但是结合封装和继承的角度去看的话,其实不难,多态性只是概念上比较难懂,更多时候是需要去多写代码去理解它的性质。
- 多态的前提是要有继承和重写的,举个例子来说吧,
- 每一个动物都会叫,但是每种动物的叫声可能就不一样了,这个时候我们定义一个动物类写一个叫声方法,
- 然后猪类、猫类、狗类这些类继承了动物类就获得了(重写)动物类的叫声方法,
- 我们在这个方法里定义每种动物自己特定的叫声(方法体),当调用的时候有动物类的引用就可以,然后造猪类、猫类、狗类的对象就行了(父类引用指向子类对象)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class animals { public void voice(){ System.out.println("动物都可以叫"); } } class dog extends animals{ @Override public void voice() { System.out.println("汪汪汪"); } } class cat extends animals{ @Override public void voice() { System.out.println("喵喵喵"); } } class text{ public static void main(String[] args) { animals a = new dog(); a.voice(); animals a1 = new cat(); a1.voice(); text t = new text(); t.method(new dog()); t.method(new cat()); } public void method(animals als){ als.voice(); } }
|
1.1多态核心
简单来说就是事物存在的多种形态
多态前提:要有继承关系,要有方法重写,要有父类引用指向子类对象
父类引用指向子类对象:
1
| Father father = new Son();
|
1.2多态弊利
利处
提高了代码的维护性(继承保证)
提高了代码的扩展性(由多态保证)
弊端
不能使用子类的特有属性和方法
关键字instanceof 判断前面的引用是否是后面的数据类型
1.3成员访问特点
成员变量
编译看左边(父类),运行看左边(父类)
成员方法
编译看左边(父类),运行看右边(子类){动态绑定}
静态方法
编译看左边(父类),运行看左边(父类)
静态和类相关,算不上重写,所以,访问还是左边的
只有非静态的成员方法,编译看左边,运行看右边
CODE
1 2 3 4 5 6 7
| ainmals als = new cat(); als.eat();
System.out.println(als.leg);
|
1.4虚拟方法调用
虚拟方法调用(多态情况下)
- 调用子父类同名同参的方法时,在多态的情况下,父类的方法就称为虚拟方法
- 父类根据赋给它不同的子类,动态调用属于子类自己的该方法
- 这样的方法在编译期间,是无法确定的
动态绑定
ainmals als = new cat();//父类引用指向子类对象
als.eat();
编译时为父类类型,但是方法调用是在运行才知道
所以调用的子类的方法
1.5上下转型
向上转型(就是多态)
向上转型(父类引用指向子类对象)
父类名称 父类变量名=new 子类名称();
Person p=new superman();
向下转型 (需用instanceof判断)
强制类型转换
子类名称 子类变量名 = (子类名称)父类变量名
superman s=(superman)p;
2.instanceof关键词
2.1instanceof用法
常用于多态向下转型时
为避免出现classcast异常,向下转型前先使用它进行判断
判断格式
判断对象a是否是类A的实例
是返回true 不是返回false
如此格式返回true如下格式也返回true
2.2代码体现
1 2 3 4 5 6 7 8 9 10 11
| Watch watch = new TraditionWatch(); watch.seeTime(); watch.collect(); if (watch instanceof TraditionWatch){ TraditionWatch tdw =(TraditionWatch) watch; tdw.crafts(); } if (watch instanceof SmartWatch){ SmartWatch swh = (SmartWatch) watch; swh.fashion(); }
|
3.面试题
3.1如下代码输出?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class InterviewTest {
public static void main(String[] args) { faze fe = new zil(); fe.add(10,2,3,4,2,2,1);
if (fe instanceof zil) { zil z = (zil) fe; z.add(1, 2, 3); } } }
class faze{
public void add(int a,int ... arr){ System.out.println("faze"); } }
class zil extends faze{
@Override public void add(int a, int[] arr) { System.out.println("zil"); }
public void add(int a, int b,int c) { System.out.println("zil222"); } }
|
4.抽象(abstract)
4.1理解抽象
- 抽象可以理解为关键词,也可以理解为面向对象的一种性质
- 抽象可以修饰类和方法,抽象方法没有方法体
- 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类或者接口
- 抽象类不能实例化,要实例化只能通过子类(抽象多态)
- 抽象类子类要么是抽象类,要么实现所有所有父类的抽象方法
1 2 3
| abstract class CLASS_NAME{ public abstract void METHOD_NAME( ); }
|
4.2关键词冲突
static
- 被abstract修饰的方法没有方法体
- 被static修饰的方法可以用类名调用,抽象方法没有方法体没意义
final
- final修饰的方法体不能被重写,abstract则是子类必须重写
private
- 被abstract修饰是为了让子类看到并强制重写
- 被private修饰不让子类访问,所以两者也是矛盾的
4.3匿名抽象
对象不匿名,类匿名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Test public void anonymousUs(){ aHuman aa = new aHuman() { @Override public void eat() { System.out.println("建筑工人多吃肉有力气干活"); }
@Override public void learn() { System.out.println("建筑工人学习土木知识"); } }; anony(aa);
|
对象,类都匿名
1 2 3 4 5 6 7 8 9 10 11
| anony(new aHuman() { @Override public void eat() { System.out.println("电器工人多吃肉有力气干活"); }
@Override public void learn() { System.out.println("电器工人学习CAD和工业知识"); } });
|
5.接口(Interface)
5.1理解接口
- 从狭窄的角度来讲就是指Java中的interface
- 从广义的角度来讲就是对外提供规则的都是接口
- 接口就是一种规范(开发中会体现面向接口编程)
- 极大意义上弥补Java的单继承性
- 接口的使用充分的体现了多态性
5.2接口特点
- 接口中没有构造器(无法实例化)
- 接口实例化通过实现类来实例化(多态体现)
- 接口中的方法都是抽象的(JDK1.8前)
- 实现接口的类,如果没有实现全部接口的方法,必须加上abstract
- 如果此类实现了接口的所有方法,就没必要加上abstract
5.3JDK8新特征
成员特点
变量:只能是常量,并且是static和public的
方法:只能是抽象方法(1.8以后还可以定义静态方法,default方法)
注:静态方法和default方法有方法体,抽象方法没有方法体
注意事项
- 接口中的静态方法只能通过接口.方法名调用
- 接口中的default方法类可以实现,也可以不实现
- 当实例类继承的两个接口中出现同名的方法后,需要通过接口名.super.方法名调用
- 若上述两个接口的参数也一样的情况下会报错(接口冲突)
- 实际开发中不会这么无聊的去写
1 2 3 4 5 6 7 8 9
| interface See{ public static final MAX_NUM = 996; public abstract void methdo1(); public default void method2(){}; public static void method3(){}; }
|
5.4匿名接口
- 非匿名实现类的匿名对象(多态写法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Computer.transferData(new Flash()); ````
2. 接口匿名 类非匿名
```java USB mp3 = new USB() { @Override public void start() { System.out.println("mp3工作"); }
@Override public void stop() { System.out.println("mp3停止工作"); } };
|
- 接口匿名 类也匿名
1 2 3 4 5 6 7 8 9 10 11
| Computer.transferData(new USB() { @Override public void start() { System.out.println("游戏机工作"); }
@Override public void stop() { System.out.println("游戏机停止工作"); } });
|
6.两者区别
- 抽象类中定义的是该继承体系的共性功能,被继承体现的是”is a”的关系
- 接口中定义的是该继承体系的拓展功能,被实现体现的是”like a”的关系
- 其实接口也在逐渐的类化,例如JDK8加入了静态方法和默认方法
- JDK11又加入了私有方法,基本上实在向抽象类的意义靠拢拉近的
内部定义要求
Abstract:变量/常量谐可 抽象/非抽象方法谐可 有构造方法
Interface:常量 只能抽象方法 没有构造方法
关系区别
类与类:继承、单继承
类与接口:实现、单实现、多实现
接口与接口:继承、单继承、多继承
7.代码块
7.1非静态代码块
随着对象的创建而创建,每创建一个对象执行一次
可在创建对象时,对对象属性进行初始化
7.2静态代码块
随着类的加载就执行,并且只执行一次
用于初始化类的信息,优先于主方法执行,一般用于加载驱动
注:内部书写要求依据static使用来写
7.3题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 看代码想结果 class mst { static{ System.out.println("static code area"); }
public static void main(String[] args) { System.out.println("我是main方法"); studentss s1=new studentss(); studentss s2=new studentss(); } } class studentss{ static{ System.out.println("Students 静态代码块"); }
{ System.out.println("Students 构造代码块"); }
public studentss(){ System.out.println("Students 构造方法"); } }
|
1 2 3 4 5 6 7 8
| 运行结果 static code area 我是main方法 Students 静态代码块 Students 构造代码块 Students 构造方法 Students 构造代码块 Students 构造方法
|