多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性
多态性我们大概可以分为两类:
(1)方法的重载与重写
(2)对象的多态性
//用父类的引用指向子类对象(用大的类型去接受小的类型,向上转型、自动转换)
Chicken home = new HomeChicken();
在编程时针对抽象类型的编写代码,称为面向抽象编程(或面向接口编程)父类通常都定义为抽象类、接口
对象的多态性:
对象多态性是从继承关系中的多个类而来,
向上转型:将子类实例转为父类引用
格式:父类 父类对象 = 子类实例 ; 自动转换
以基本数据类型操作为例:int i = ‘a' ;
(因为char的容量比int小,所以可以自动完成)
向下转型:将父类实例转为子类实例
格式:子类 子类对象 = (子类)父类实例 ;强制转换
以基本数据类型操作为例:char c = (char)97;
因为整型是4个字节比char 2个字节要大,所以需要强制完成
a、方法的重载与重写就是方法的多态性表现
b、多个子类就是父类中的多种形态
c、父类引用可以指向子类对象,自动转换
d、子类对象指向父类引用需要强制转换(注意:类型不对会报异常)
e、在实际开发中尽量使用父类引用(更利于扩展)
指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,
该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,
必定是使用子类中定义的这些方法(动态连接、动态调用)。
例如:
class A{
void fun1(){}
void fun2(){}
}
class B extends A{
void fun1(String a){} //重载fun1
void fun2(){}	//重写fun2
}
class C{
public static void main(String[] args){
A a = new B();
a.fun1(); //这里会调用A类的fun1方法,由于向上转型,B的fun1(String a) 会被丢弃
a.fun2(); //这里调用B的fun2方法,由于是new 的B对象,而B重写了fun2,所以会调用B的fun2
}
}
对于面向对象而言,多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要是指方法的重载,而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性
java实现多态有三个必要条件:继承、重写、向上转型。
继承:在多态中必须存在有继承关系的子类和父类。
重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法
基于继承实现的多态
继承是通过重写父类的同一方法的几个不同子类来体现的
对于引用子类的父类类型,在处理该引用时,它适用于继承该父类的所有子类,子类对象的不同,对方法的实现也就不同,
执行相同动作产生的行为也就不同。
基于接口实现的多态
指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。
可以参考:https://www.cnblogs.com/chenssy/p/3372798.html
20、instanceof关键字
instanceof 是用于检查对象是否为指定的类型,通常在把父类引用强制转换为子类引用时要使用,以避免发生类型转换异常(ClassCastException)。
语法格式如下:
对象 instanceof 类型--返回boolean类型值
示例:
if(homeChicken instanceof Chicken){
//...
}
该语句一般用于判断一个对象是否为某个类的实例,是返回true,否返回false
父类的设计法则
通过instanceof关键字,我们可以很方便的检查对象的类型,但如果一个父类的子类过多,这样的判断还是显得很繁琐,那么如何去设计一个父类呢?
a、父类通常情况下都设计为抽象类或接口,其中优先考虑接口,如接口不能满足才考虑抽象类。
b、一个具体的类尽可能不去继承另一个具体类,这样的好处是无需检查对象是否为父类的对象。
21、内部类
内部类就是在一个类的内部定义的类。
成员内部类:内部类对象依赖外部类对象而存在,即在创建一个普通内部类对象时首先需要创建其外部类对象
内部类对象可以访问外部类对象中所有访问权限的字段,同时,外部类对象也可以通过内部类的对象引用来访问内部类中定义的所有访问权限的字段
成员内部类格式如下:
class Outer {
class Inner{}
}
编译上述代码会产生两个文件:
Outer.class和Outer$Inner.class。
在外部创建内部类对象
内部类除了可以在外部类中产生实例化对象,也可以在外部类的外部来实例化。
那么,根据内部类生成的*.class文件:Outer$Inner.class
“$” 符号在程序运行时将替换成“.”
所以内部类的访问:通过“外部类.内部类”的形式表示。