深入浅出java多态性,为什么要有多态

深入浅出java多态性,为什么要有多态

我们都知道面向对象三大特征:封装,继承,多态 相比于封装和继承,多态似乎理解起来更加抽象,这篇文章将彻底揭露java多态性,文章内容较多,请耐心观看

1.通过代码体现多态性

我们先准备好三个类,男人类male,女人类female,以及他们共同的父类person类

public class person {

public void eat(){

System.out.println("person中的eat方法");

}

}

public class female extends person {

@Override

public void eat() {

System.out.println("细嚼慢咽");

}

public void walk() {

System.out.println("female中的的walk");

}

}

public class male extends person {

@Override

public void eat() {

System.out.println("狼吞虎咽");

}

public void walk() {

System.out.println("male中的的walk");

}

}

先通过最熟悉的创建对象的方式来测试这些类

public class test {

public static void main(String[] args) {

person p = new person();

male man = new male();

female woman = new female();

p.eat();

man.eat();

woman.eat();

}

}

输出结果:

person中的eat方法

狼吞虎咽

细嚼慢咽

这些都是非常正常的,毫无疑问,我们改一下test中的代码

public class test {

public static void main(String[] args) {

person p = new person();

person man = new male();

person woman = new female();

p.eat();

man.eat();

woman.eat();

}

}

请看输出结果:

person中的eat方法

狼吞虎咽

细嚼慢咽

通过上面的代码,可以提出几个疑问:

person man = new male();为什么没有报错?在person man = new male();中,man属于person类声明的对象引用,为什么不调用person中的方法

2.解释

在本例中,male和female都是person的子类,我们做的测试都是基于这个条件,这就引出了多态成立的一个条件:

类和类存在继承关系,父类引用指向子类对象,子类重写父类的方法

通过代码我们可以发现,通过person声明的引用可以是male,也可以是female,这就体现了多态性,即一个引用可以有不同的实现方式,说简单就是,只要是person的子类,都可以赋给person声明的引用

需要注意的是: 在 person man = new male();,中,虽然man是person的引用,但实际指向的是male在堆上创建的male对象,所以man调用的方法就是male中重写父类的方法了,这就涉及到了一个概念:虚拟方法调用,文章下面会讲

不要忘了我们male类中还有一个方法,这不是白写的,我们在person man = new male();前提下来调用这个方法: 发现报错了,无法通过编译!,为什么会这样,请接着往下看:

3.多态条件下的同名同参的方法调用

在编译期,也就是将我们写好的java代码编译成class文件的时候,在编译器编译 person man = new male();这段代码的时候,因为man是person类型的,所以man在本质上一个person类型的引用,这是我们写代码的时候声明的,毫无疑问,所以所以man只能调用在person类中出现过的方法,请记住下面四句话:

如果子类重写了这个方法,且这两个方法同名同参,就调用子类的如果子类没有这个方法,就调用父类的,不能调用子类中存在而父类中不存在的方法!编译器看左边,运行期执行的是子类重写父类的方法

4.为什么要有多态

在我们编写代码的时候,尽量本着高内聚,低耦合的原则去编写,不理解这个概念没关系,我们通过一个案例来表示

public class test {

public static void main(String[] args) {

fun(new Dog());

fun(new Cat());

}

public static void fun(Animal animal){

animal.action();

}

}

class Animal{

public void action(){}

}

class Dog extends Animal{

@Override

public void action() {

System.out.println("狗类的动作");

}

}

class Cat extends Animal{

@Override

public void action() {

System.out.println("猫类的动作");

}

}

在test类中定义的fun方法中,参数并没有写死,而是只要是Animal的子类都可以调用,这样就避免课将参数写死而导致代码的难以服用,在以后的框架以及其他技术中,这类的写法非常之多,如果没有多态,那么抽象类和接口也就没有意义,体现不了java的面向对象编程思想

5.关于属性的多态

我们来一个骚操作

public class test {

public static void main(String[] args) {

Animal a = new Dog();

System.out.println(a.id);

}

}

class Animal{

int id = 1;

}

class Dog extends Animal{

int id = 2;

}

输出:1 到这里就看不懂了,a是animal类型的,调用的是animal中的属性,不做多解释,我们抛出一个结论:

多态只适用于方法,不适合属性

6.虚拟方法调用

这只是一个粗糙的管你虚拟方法的介绍,更加具体深入的介绍请看:重载重写的本质

7.向下转型

有了对象的多态性之后,内存中其实是加载了子类的属性和方法的,但由于声明的引用是父类类型,导致编译时只能调用父类中的属性和方法,子类特有的属性和方法无法调用,仔细看这句话,如何才能调用子类特有的属性和方法? 解决办法:强转 用我们第一步的代码来看:

public class test {

public static void main(String[] args) {

person p = new male();

male m =(male)p;

}

}

这和基本数据类型的强转差不多,这样就可以使用子类特有的属性和方法了,这就是向下转型 类比基本数据类型,可以看一下这张图: 是不是容易理解多了,这里多提一下向上转型,说白了向上转型就是多态,我们之前的案例都是向上转型,即父类引用指向子类对象 在进行类型转换的时候可能会出现很多问题,在这里有必要说一下:

问题一:编译时通过,运行时报错 看代码:用第一步的代码来做演示:person p = new male();

female f = (female)p;

f.walk();

在运行的时候会抛出:Exception in thread "main" java.lang.ClassCastException类型转换错误异常问题二:编译时通过,运行时通过 Object o = new male();

person p1 = (person)o;

p1.eat();

8.instanceof

在做类型转换的时候要使用instanceof

a instanceof A:判断a是不是A的一个实例,返回true或false

拿第一部的代码来演示:

public class test {

public static void main(String[] args) {

person p = new male();

System.out.println(p instanceof male);

female f = new female();

System.out.println(f instanceof person);

}

}

输出结果:

true

true

9.关于向下转型的碎碎念

还是第一步的代码,对比两段代码

person p2 = new person();

if(p2 instanceof male){

male m1 = (male)p2;

}else{

System.out.println("wrong");

}

person p3 = new male();

if(p3 instanceof male){

male m2 = (male)p3;

m2.eat();

}else{

System.out.println("wrong");

}

结果输出的是wrong和狼吞虎咽,父类不可以强转为子类,如果强转成功,就失去了父类的特性,多态也就丧失了意义

10.总结

相关推荐

重庆配眼镜哪里最好,十年验光师亲授精准选店,避坑技巧一网打尽!
侧田为什么退出乐坛,并非退出只是转入内地发展
田朴珺:从大尺度床戏到地产大亨妻子,她的成功背后有多少隐秘?
大优到惨败!申真谞,手握第三败!中国95后世冠,顽强逆转,赢了!
碧蓝航线犬时间多少 犬建造时间一览
365账户受到限制怎么办

碧蓝航线犬时间多少 犬建造时间一览

⌛ 06-28 👁️ 7925
智能转型之路:用WPS表格打造全自动欠料运算报表的实战指南