多态
Java作为面向对象的语言,可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。
Java中多态的代码体现在一个子类对象(实现类对象)既可以给这个子类(实现类对象)引用变量赋值,又可以给这个子类(实现类对象)的父类(接口)变量赋值。
定义:父类引用变量指向子类对象
多态的前提:必须有子父类关系 或者 类实现接口关系,否则无法完成多态。
在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。
1定义与使用格式
父类类型 变量名 = new 子类类型();
变量名.方法名();
例:普通类多态:
public class Fu {
int a=1;
public void method(){
System.out.println("这是父类方法");
}
}
public class Zi extends Fu{
int a=2;
public void method(){
System.out.println("这是子类方法");
}
public void zi(){
System.out.println("这是子类方法2");
}
}
public class Test {
public static void main(String[] args) {
Fu f=new Zi();
System.out.println(f.a);
f.method();
}
}

抽象类多态:
public abstract class Animal {
public abstract void sleep();
}
public class Dog extends Animal{
public void sleep(){
System.out.println("狗趴着睡觉");
};
}
public class Test {
public static void main(String[] args) {
Animal an=new Dog();
an.sleep();
}
}

接口多态:
public interface JiDu {
public abstract void jidu();
}
public class Pig implements JiDu{
public void jidu() {
System.out.println("缉毒猪在缉毒");
}
}
public class Test {
public static void main(String[] args) {
JiDu jd=new Pig();
jd.jidu();
}
}

自己理解:
JiDu jd=new Pig();
正常建对象是 Pig p=new Pig();
这样jd和p都引用了Pig()的地址,也可以说pig()有了两种状态,这就是多态。
2 多态--成员的特点
2.1多态中成员变量的特点:
当子父类中出现同名的成员变量时,多态调用该变量时:
编译时期:参考的是引用型变量所属的类中是否有被调用的成员变量。没有,编译失败。(看父)
运行时期:调用引用型变量所属的类中的成员变量。(看父)
简单记:编译和运行都参考等号的左边。编译运行看左边。
2.2多态中成员方法的特点:
同一个父类的方法会被不同的子类重写。在调用方法时,调用的为各个子类重写后的方法。
编译时期:参考引用变量所属的类,如果类中没有调用的方法,编译失败。(看父)
运行时期:参考引用变量所指的对象所属的类,并运行对象所属类中的成员方法。(调用子)。子类独有的方法无法调用。
简单记:编译看左边,运行看右边。
3 instanceof关键字
可以通过instanceof关键字来判断某个对象是否属于某种数据类型。
例:
public class Animal{} //动物类
public class Cat extends Animal{} //猫类
public class Person extends Animal{} //人类
public class Pot{} //锅类
public class Test {
public static void main(String[] args) {
Animal an=new Person();
System.out.println(an instanceof Cat);
System.out.println(an instanceof Person);
System.out.println(an instanceof Object);
}
}

但是如果
System.out.println(an instanceof Pot); 就编译失败

所以只有同体系才能比较,不同的直接编译失败。
4多态转型
4.1向上转型
当有子类对象赋值给一个父类引用时,便是向上转型,多态本身就是向上转型的过程。
格式:
父类类型 变量名 = new 子类类型();
个人理解:double b=100;(小转大)与这个同理
4.2向下转型
一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用转为子类引用,这个过程是向下转型。
如果是直接创建父类对象,是无法向下转型的(先向上转了,才能向下转)
格式:
子类类型 变量名 = (子类类型) 父类类型的变量;
例:
public abstract class Animal{
public abstract void eat();
}
public class Cat extends Animal{
public void eat() {
System.out.println("猫吃鱼");
}
public void cathMouse(){
System.out.println("猫抓老鼠");
}
}
public class Dog extends Animal{
public void eat() {
System.out.println("狗吃骨头");
}
public void lookhome(){
System.out.println("狗看家");
}
}
public class Test {
public static void main(String[] args) {
Animal d=new Dog();
d.eat();
Animal c=new Cat();
c.eat();
Dog d2=(Dog)d;
Cat c2=(Cat)c;
d2.lookhome();
c2.cathMouse();
}
}

但是如果写成这样:
Cat c2=(Cat)d;
可以编译,但会出现异常:
所以,向下转时,必须用instanceof加个判断
public class Test {
public static void main(String[] args) {
Animal d=new Dog();
d.eat();
Animal c=new Cat();
c.eat();
method(d);
method(c);
}
public static void method(Animal an){
if(an instanceof Dog){
Dog d2=(Dog)an;
d2.lookhome();
}else if(an instanceof Cat){
Cat c2=(Cat)an;
c2.cathMouse();
}
}
}

5多态的好处与弊端
好处:隐藏了子类类型,提高了代码的扩展性
弊端:只能使用父类共性的内容,而无法使用子类特有功能,功能有限制。
6 什么时候使用
6.1什么时候使用向上转型:
当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作,这时就可以使用向上转型。
6.2什么时候使用向下转型
当要使用子类特有功能时,就需要使用向下转型。
向下转型的好处:可以使用子类特有功能。
向下转型的弊端:需要面对具体的子类对象;在向下转型时容易发生ClassCastException类型转换异常。在转换之前必须做类型判断。
7多态举例
7.1传参
public interface USB {
public abstract void openUsb();
public abstract void closeUsb();
}
public class Notebook{
public void run(){
System.out.println("笔记本运行");
}
public void shutdown(){
System.out.println("笔记本关机");
}
//usb方法,传一个usb对象
public void useUsb(USB u){
u.openUsb();
u.closeUsb();
}
}
public class Mouse implements USB{
public void openUsb() {
System.out.println("插上鼠标");
}
public void closeUsb() {
System.out.println("拔下鼠标");
}
}
public class Keyboard implements USB{
public void openUsb() {
System.out.println("插上键盘");
}
public void closeUsb() {
System.out.println("拔下键盘");
}
}
public class Test {
public static void main(String[] args) {
Notebook n=new Notebook();
Mouse m=new Mouse();
Keyboard k=new Keyboard();
n.run();
n.shutdown();
n.useUsb(m);
n.useUsb(k);
}
}

分析:这里最关键的就是:public void useUsb(USB u){}
这里参数是传一个USB类型的对象
假设当传值时,传入一个鼠标对象m(Mouse m=new Mouse();)
那么调用方法的同时,相当于实现了一个多态:
USB u=new Mouse();
这是多态最常见的应用。
之前集合ArrayList的方法Add(Object obj),参数是一个Object类型的对象,但是实际用时,是传入一个集合中存放的对象的类型的对象(就是存什么,就传什么),这也是一种多态。
7.2 返回值
如果一个方法的返回值类型是父类,那么可以返回一个子类对象。
例:
public class Father {
public void test(){
System.out.println("父类方法");
}
}
public class Son extends Father{
public void test(){
System.out.println("子类方法");
}
}
public class Test {
public static void main(String[] args) {
Father f=methods();
f.test();
System.out.println(f instanceof Son);
System.out.println(f instanceof Father);
}
public static Father methods(){ //返回值是父类
return new Son(); //返回子类对象
}
}

8 总结:封装、继承、多态的作用
封装:把对象的属性与方法的实现细节隐藏,仅对外提供一些公共的访问方式
继承:子类会自动拥有父类所有可继承的属性和方法。(抽象类,接口都体现了继承)
多态:父类引用变量指向子类对象。配合继承与方法重写提高了代码的复用性与扩展性;如果没有方法重写,则多态同样没有意义。
扩展:java面试题,可以经常看看,例:
https://blog.csdn.net/linzhiqiang0316/article/details/80473906

浙公网安备 33010602011771号