多态

同一批事物,它们都是由一个事物泛生得出的(也就是继承),这一批事物我们可以用一个分类去归纳。比如我们生存需要进食,牛肉、猪肉、鸡肉等,当我们处于一个饥饿的状态下,不管什么肉,都会食取充腹;又如,在建房子上,可以聘请不同的设计师来帮我们完成,不管是国外的还是国内的。

多态亦是如此,通过父类就能引用不同的子类,同一个行为具有多个不同表现形式或形态的能力,这可以使我们无需关注某个对象具体是什么类型,就可以去调用该对象的方法,提高了程序的灵活性

//假设Student继承至Person,并重写了todata()方法
public class TestDemo{
    public static void main(String[] args){
        Student p = new Student();
        int a = 10;
        getData(p,a)
    }
    public static String getData(Person person, int Data){
    	String str = person.todata(Data);
        return str;
    }
}

解析:

new Object:这是一个对象的实际类型

Student extends Person :重写了todata()方法

getData(Person person, int Data)Person是一个引用类型,它指定了实际类型的范围,new Student()是形式参数person的实际对象,后面的代码通过对象person调用其实都是在调用Student(),与Person()没有实际的关系

多态中方法调用,子类继承父类,子类没有重写从父类继承过来的方法,调用时就是调用父类继承过来的方法;如果子类重写了这些方法,那就是调用子类重写后的方法

1.调用子类方法

在多态中,无法调用子类的独有方法。多态时,编译器能否通过,主要看其引用中是否有包含调用的内容,而不是看其指向的对象是否包含该内容

原理:“编译看左边,运行看右边”
解析:Java编译器在编译时会检查引用类型中是否包含有调用的成员,如果没有则编译出错。而子类独有的方法是子类的成员,父类没有,所以在使用多态时会报错

public class Person{
    int num  = 5; 
    public void run(){}
    public static void toName(){};
}
public class Student extends Person{
    int num = 8;
    public void text(){}
    public static void toName(){};
}

Person person = new Student();
person.num;//通过Person引用的,调用的是Person类的num属性,因为属性不会重写
person.toName();//通过Person引用的,调用的是Person类的toName方法
person.run();//编译通过,run方法是从Person类继承过来的
person.text();//编译出错,text方法是Student的独有方法,在多态中无法编译

1.1多态中子类引用和父类引用区别

Student stuednt = new Student();
Person person = new Student();

变量student可以调用Student类中的所有方法(包括继承过来的方法)

变量person只能调用从Student类中从Person继承过来的方法,除非子类没有重写父类的方法才会去执行父类的方法

如果变量person非要调用Student类的独有方法,可以使强制转换类型((Student) person).text(),把person的引用类型修改为Student类

  • static修饰的方法属于类,不是属于实例
  • final修饰的方法无法被子类重写,final表示最终形态
  • private修饰的方法对子类不可见,所以无法继承

2.多态的好处与弊端

  • 好处:提高了程序的拓展性

    具体表现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作

  • 弊端:不能使用子类的特有功能。如果非要用,可以进行类型转换(但这就不是多态了)

3.多态的注意事项

  1. 多态是指方法的多态,属性没有多态
  2. 多态的三个条件:“有继承关系”、“重写父类的方法”、“在创建对象时,父类引用指向子类对象”
  3. 如果要执行子类的独有方法,那只能进行类型转换(如:被static、final或private修饰的方法,或不是继承至父类的方法等)

4.instanceof和类型转换

4.1.instanceof,算双目运算符,用来测试一个对象是否为一个类的实例。

格式:object instanceof constructor

public class Person{ public void run(){} }
public class Student extends Person{ public void go(){} }
public class Teacher extends Person{}
Object obj = new Student();//Object > Person > (Student - Teacher)
System.out.println(obj instanceof Person);//true	Object > Person > Student
System.out.println(obj instanceof Object);//true	Object > Person > Student
Sysyem.out.println(obj instanceof Student);//true	Object > Person > Student
System.out.println(obj instanceof Teacher);//false	Object > Person > Teacher
System.out.println(obj instanceof String);//false	object > String
Person per = new Student();//Object > Person > (Student - Teacher)
System.out.println(per instanceof Person);//true
System.out.println(per instanceof Object);//true
System.out.println(per instanceof Student);//true
System.out.println(per instanceof Teacher);//false
System.out.println(per instanceof String);//编译报错,因为Person与String没有交际
Student stu = new Student();
System.out.println(stu instanceof Person);//true
System.out.println(stu instanceof Object);//true
System.out.println(stu instanceof Student);//true
//编译报错,因为Person、String与Student没有交际
System.out.println(stu instanceof Teacher);
System.out.println(stu instanceof String);
  1. 使用object instanceof constructor,编译能否通过主要看变量object的引用类型与constructor类是否存在子父类关系,如果不存在关系则编译报错
  2. 如果存在子父类关系,则看变量object所指向的实际对象new classtype()是不是constructor类的实例,也就是可不可通过constructor类创建由object所指向的实际对象的一个实例,constructor typeName = new classtype()

4.2.类型转换,因为多态中,通过引用对象无法调用实际对象中的独有方法

格式:(classType) varobject typeName = (classType) var

Person per = new Student();
//调用Student中的go()方法
//方案1
Student stu = (Student) per;
stu.go();
//方案2
((Student) per).go();
//类型转换中的问题
Person per = new Student();
Object obj = new Student();
Student stu = new Student();
//向上转型
Person per2 = stu;
//向下转型
Student stu2 = (Studebt) obj;
stu2.go();//编译通过 运行没问题
Person per3 = (Person) obj;
per3.run();//编译通过 运行没问题
//编译通过,运行报错
Object obj2 = new Teacher();
Student stu3 = (Student) obj2;

向上转型(upcasting):子类对象直接赋给父类引用,不用强制转型。如:Person per = new Student();

向下转型(downcasting):子类对象的父类引用赋给子类引用,需要的强制转型。如:Student stu = (Studebt) obj;

向上转型会丢失子类的独有方法。子类需要重写从父类继承下来的方法,否则当使用该对象调用父类继承下来的方法时,会检查子类是否有覆盖,如果没有则运行父类的方法

向上转型的作用,减少重复代码,父类为参数,调有时用子类作为参数,就是利用了向上转型。这样使代码变得简洁。体现了JAVA的抽象编程思想。


posted @   hello_12153_98  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示