多态
同一批事物,它们都是由一个事物泛生得出的(也就是继承),这一批事物我们可以用一个分类去归纳。比如我们生存需要进食,牛肉、猪肉、鸡肉等,当我们处于一个饥饿的状态下,不管什么肉,都会食取充腹;又如,在建房子上,可以聘请不同的设计师来帮我们完成,不管是国外的还是国内的。
多态亦是如此,通过父类就能引用不同的子类,同一个行为具有多个不同表现形式或形态的能力,这可以使我们无需关注某个对象具体是什么类型,就可以去调用该对象的方法,提高了程序的灵活性
//假设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.多态的注意事项
- 多态是指方法的多态,属性没有多态
- 多态的三个条件:“有继承关系”、“重写父类的方法”、“在创建对象时,父类引用指向子类对象”
- 如果要执行子类的独有方法,那只能进行类型转换(如:被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);
- 使用
object instanceof constructor
,编译能否通过主要看变量object的引用类型与constructor类是否存在子父类关系,如果不存在关系则编译报错- 如果存在子父类关系,则看变量object所指向的实际对象
new classtype()
是不是constructor类的实例,也就是可不可通过constructor类创建由object所指向的实际对象的一个实例,constructor typeName = new classtype()
4.2.类型转换,因为多态中,通过引用对象无法调用实际对象中的独有方法
格式:
(classType) var
或object 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的抽象编程思想。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!