多态
面向对象三大特征:封装,继承。多态
|
多态定义
多态:同一行为,不同的类具备不同的表现形式
|
多态出现前提
1.继承类或者实现接口【前提条件】
2.出现父类指向子类的引用【格式体现】
3.必须重写方法【才能表现出同一动作,不同对象表现不同】
|
多态表现
1.多态表现格式
父类类型 变量名=new 字类对象();
变量名.方法名();
备注:父类类型指的是子类对象继承的类或者实现的接口
注意:如果使用多态方式调用方法,首先检查父类当中是否有该方法,如果没有编译报错,如果有执行的是子类重写之后的方法,如果子类当中没有重写,就执行父类的方法,子类当中不是重写父类的方法,是不能调用的。
|
|
多态好处
在实际研发过程中,父类类型一般作为方法形参,传递子类对象给方法,进行方法的调用,其实就是父类方法上写出来就是让子类重写的。
|
多态作为形参的体现
父类作为形参,根据传入不同的对象,完成不同对象是之间的转换,最终达到实参传入哪个对象就代表哪个对象,再使用对象调用方法,调用的就是子类重写的方法。
不仅仅可以做到替代,在扩展方面,无论之后出现多少子类,都直接传入对象就可以了,根本不需要重新编写方法。
1.创建子类对象
2.把子类对象当作参数传入方法
3.里面的对象调用方法,调用的就是传入子类对象内部重写的方法。
|
多态优点
1.程序编写更简单
2.良好的扩展性
|
注意
1.没有使用多态:在测试类每个子类单独创建对象,单独调用
2.使用了多态:父类 对象名=new 子类对象();
不管后面new的哪一个子类,父类变量名都一样,如果都含有work方法那么就不管new的那个对象,直接对象名.work()就可以根据对象不同而得到不同的结果。
|
多态情况下访问类中的成员变量有两种方式
1.直接通过对象名调用变量:看等号左边是谁就有先调用谁,没有寄往上找
2.间接通过成员方法访问创元变量:等号右边,方法属于谁,优先使用谁。先去罩子类里面被重写的方法,没有重写就去父类里面找
|
类中的成员通过this.调用,只不过可以省略
|
向上转型
本身是子类类型,向父类类型转型的过程,过程是默认的,当一个父类引用指向了一个子类对象,就是向上转型
例如:Animal animal=new Cat();
向下转型
父类类型向子类类型转型过程,强制的转型,一个已经向上转型的子类对象,使用枪支转换转为向下转型。
1.先向上转型
Animal animal=new Cat();
2.向下转型
Cat cat=(Cat)animal;
注意
向上转型一定安全,但是一旦转型,就不能再调用子类里面独有的方法,想要使用只有zai1转回来才可以,就需要用到向下转型,才能调用子类独有的方法,但是可能存在转型异常(转错了,一个子类向上转为了父类,父类向下转为了另一个子类就错了)。
|
转型异常解决
关键字:【instanceof】
格式:变量名 instanceof 数据类型【返回true或者false】
在向下转型之前应该先进行格式判断
多态完整代码
public class Test {
public static void main(String[] args) {
//我给你什么样的动物,然后让他执行该动物独有功能
//先向上转型
Demo01Instanceof animal=new Dog();
//想要使用独有的方法需要向下转型
give(animal);
}
public static void give(Demo01Instanceof animal) {
if(animal instanceof Cat) {
Cat cat=(Cat)animal;
cat.eat();
cat.sleep();
}else if(animal instanceof Dog){
Dog dog=(Dog)animal;
dog.eat();
dog.sleep();
}
}
}
final
final:最终的不可改变的
常见的四种用法
1.修饰类
2.修饰方法
3.修饰局部变量
4.修饰成员变量
|
修饰类
格式:public final class 类名{}
1.不能有子类,可以有父类,可以实现接口
2.成员方法不能被重写,因为没有子类
修饰方法
格式:public final 返回值 方法名(参数列表){}
1.最终方法不能被重写
2.在子类里面,值能改方法名或者改参数列表
3.abstract和final不能同时修饰一个方法
|
局部变量和成员变量必须全部大写
|
局部变量:在方法中,不一定会用到,所以不必赋值
格式:final 数据类型 变量名=数值;【什么的时候可以不赋值】
1.对于基本数据类型:一次赋值,【数据】不能再改变
2.对于引用数据类型:不可变的是内存地址,可变的是内容
final Peoplen p=new People("小刘");
p=new People("小丽");//报错,因为改变了内存地址
p.setName("小丽");//可以完成,因为没改变地址,只是改变了值。
成员变量:类加载的时候就会用到,所以声明的时候必须赋值
格式:final 数据类型 变量名=数值;【声明的时候必须赋值】
对于成员变量来说,使用final之后,变量也是不可改变的,
1.成员变量有默认值,用了final之后必须手动赋值,不再有默认值
2..由于final的成员变量要么直接赋值,要么通过构造方法赋值【二选一】
1.直接赋值
final String name="小王";
2.通过构造方法赋值
final String name;
public Student(){
name="小刘";
}
3.必须保证所有重载的构造方法,都要对final成员变量赋值;不然系统认为你那个没有赋值的构造方法是错误的。同时,如果生成get和set方法,set方法不允许。