Java基础篇——三大特性(多态)

这是Java三大特性的最后一篇文章,本篇主要讲解多态的概念和应用。如果是对Java有兴趣的小伙伴可以关注一下,后续会推出一系列的Java基础和进阶的总结(或者说是个人的理解吧!)可以让你学到一些基础但是又非常实用的东西,基本上都是自己的一些理解和实践结果,对于新手来说可以避免走弯路(后期会出Java的其他重要的内容)也欢迎各位大佬和我讨论Java的一些问题。

Java基础篇——三大特性(封装):https://blog.csdn.net/weixin_45629315/article/details/105932038

Java基础篇——三大特性(继承):https://blog.csdn.net/weixin_45629315/article/details/105876883

                                                                  养成习惯先点赞后观看!!!! 

                                                                              正式开始这一次的分享

                                           

目录

多态的概念

多态实现的条件

多态中重写的基本规则

多态的具体实例

例一:

例二:

例三: 

例四:

多态的优点

总结 

后言 

多态的概念

多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作,就像下面的图一样:(不同的打印机打印出来了不同的效果)

                                        

多态性是面向对象编程的又一个重要特征,它是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义。
       对面向对象来说,多态分为编译时多态运行时多态。其中编译时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的方法。通过编译之后会变成两个不同的方法,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是大家通常所说的多态性。 

具体的几个生活中的例子

在实际登陆系统中,有几种情况,一种是系统管理人员,一种是客户,一种是系统的用户。我们在前面只道定义一个人来使用系统。但是后面到后台又会具体判断使用系统的人到底是什么人,属这就是多态的实际意义。 

现实中,比如我们按下 F1 键这个动作:

  • 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
  • 如果当前在 Word 下弹出的就是 Word 帮助;
  • 在 Windows 下弹出的就是 Windows 帮助和支持

多态实现的条件

       实现多态的条件有:继承、重写和向上转型

  • 继承:在多态中必须存在有继承关系的子类和父类。
  • 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法,如果没有重写的话在父类中就会调用。当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。要想调用父类中被重写的方法,则必须使用关键字 super
  • 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。  

继承在前面已经给出了链接不是很清楚的小伙伴可以返回去看一下, 重写就是在继承中的子类重新定义了父类中的方法,向上转型在继承中就是【父类 名称=new 子类()】类似这种格式的初始化对象就是会产生向上转型这个现象(后面的例子中会具体的指出)。

多态中重写的基本规则

  1. 参数必须要一样,且返回类型必须兼容

    重写是派生类对基类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

    基类定义出其他的程序代码要如何使用方法。不管基类使用了哪种参数,覆盖此方法的派生类也一定要使用相同的参数。同样,不论基类声明的返回类型是什么,派生类必须要声明返回一样的类型或该类型的派生类。要记得,派生类对象必须保证可以执行基类的一切

  2. 不能降低方法存取的极限

    简而言之,方法和变量的存取权必须相同或者更为开放。

    例如不能把public的方法降低为private。

  3. 基类的成员方法只能被它的派生类重写。

  4. 声明为 final 的方法不能被重写。

  5. 声明为 static 的方法不能被重写,但是能够被再次声明。

  6. 构造方法不能被重写。

  7. 如果不能继承一个方法,那么它一定不能被重写

  8. 当需要在派生类中调用基类的被重写方法时,要使用 super 关键字。

多态的具体实例

例一:

最简单的多态(构造器中的多态):在同一个名字的构造器中使用不同的参数可以得到不同的结果,这就是最简单易懂的多态了吧!

public class People {
	People(){
		System.out.println("构造器一");
	}
	
    People(int age){
    	System.out.println("构造器二:年龄为"+age);
	}
    
    People(String name,int age){
    	System.out.println("构造器三:姓名为"+name+" 年龄为:"+age);
    }
    
    public static void main(String[] args) {
		// TODO Auto-generated method stub
        @SuppressWarnings("unused")
		People p1=new People();
        @SuppressWarnings("unused")
		People p2=new People(12);
        @SuppressWarnings("unused")
		People p3=new People("YYH",12);
	}
}

OUTPUT:
构造器一
构造器二:年龄为12
构造器三:姓名为YYH 年龄为:12

例二:

public class Person {
    public void drink(){
        System.out.println("人喝水");
    }
    public void eat() {
    	System.out.println("人吃东西");
    }
}


class Man extends Person{
    public void drink(){
        System.out.println("男人喝水");
    }
}
public class Test {
    public static void main(String[] args) {
    	//子类对象的多态性:父类的引用指向子类对象
        Person p=new Man();            //向上转型
        //虚拟方法调用:通过父类的引用指向子类对象的实体,调用方法时,实际执行子类重写父类的方法
        p.drink();
        p.eat();
  } 
}
OUTPUT:
男人喝水
人吃东西

 小知识:虚拟方法的存在是为了多态。Java 中其实没有虚拟方法的概念,它的普通函数就相当于 C++ 的虚函数,动态绑定是Java的默认行为。如果 Java 中不希望某个函数具有虚函数特性,可以加上 final 关键字变成非虚函数。

在向上转型的过程中,发现子类中重写了drink方法,然后就会调用子类中重写过的方法,所以输出了“男人喝水”,在子类中没有重写eat方法所以就会调用父类中的eat方法。

也就是:当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。

例三: 

这个例子比较的经典,引用其他博主的文章(在上一篇的继承文章中也有提到),个人觉得要是这个例子理解了以后,继承和多态的基础就基本掌握了。

class A {
    public String show(D obj) {
        return ("A and D");
    }
    public String show(A obj) {
        return ("A and A");
    } 

}
class B extends A{
	//重载
	
    public String show(B obj){
        return ("B and B");
    }
  //重写
    public String show(A obj){
        return ("B and A");
    } 

}
class C extends B{}
class D extends B{}
public class t {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();                             //1.只能调用子类中重写父类的方法,不可以调用重载的方法
        B b = new B();
        C c = new C();
        D d = new D();
        System.out.println("1--" + a1.show(b));
        System.out.println("2--" + a1.show(c));
        System.out.println("3--" + a1.show(d));
        System.out.println("--------");
        System.out.println("4--" + a2.show(b));
        System.out.println("5--" + a2.show(c));
        System.out.println("6--" + a2.show(d));
        System.out.println("6--" + a2.show(a1));
        System.out.println("*");
        System.out.println("7--" + b.show(b));
        System.out.println("8--" + b.show(c));
        System.out.println("9--" + b.show(d));      
    }
}

重点:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法,但是它仍然要根据继承链中方法调用的优先级来确认方法,该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)

例四:

     继承和运行时的多态

1.创建 Figure 父类,在该类中首先定义存储二维对象的尺寸,然后定义有两个参数的构造方法,最后添加 area() 方法,该方法计算对象的面积。代码如下:

package Polymorphic;

public class Figure {
	double dim1;
    double dim2;

    Figure(double d1, double d2) {
                                         //有参的构造方法
        this.dim1 = d1;
        this.dim2 = d2;
    }

    double area() {
        // 用于计算对象的面积,父类中没有实际意义,需要在子类中重写
        return 0;
    }
}

 2.创建继承自 Figure 类的 Rectangle 子类,该类调用父类的构造方法,并且重写父类中的 area() 方法。代码如下:

package Polymorphic;

public class Rectangle extends Figure{
	Rectangle(double d1, double d2) {
        super(d1, d2);
    }

    double area() {
        System.out.println("长方形的面积:");
        return super.dim1 * super.dim2;
    }
}

3.创建继承自 Figure 类的 Triangle 子类,该类与 Rectangle 相似。调用父类的构造方法,并且重写父类中的 area() 方法。代码如下:

package Polymorphic;

public class Triangle extends Figure {
	Triangle(double d1, double d2) {
        super(d1, d2);
    }

    double area() {
        System.out.println("三角形的面积:");
        return super.dim1 * super.dim2 / 2;
    }
}

4.创建 Ftest 测试类,在该类的 main() 方法中首先声明 Figure 类的变量 figure,然后分别为 figure 变量指定不同的对象,并调用这些对象的 area() 方法。代码如下:

package Polymorphic;

public class Ftest {
	public static void main(String[] args) {
		Figure figure; // 声明Figure类的变量
        figure = new Rectangle(9, 9);
        System.out.println(figure.area());
        System.out.println("===============================");
        figure = new Triangle(6, 8);
        System.out.println(figure.area());
        System.out.println("===============================");
        figure = new Figure(10, 10);
        System.out.println(figure.area());
	}
}

从上述代码可以发现,无论 figure 变量的对象是 Rectangle 还是 Triangle,它们都是 Figure 类的子类,因此可以向上转型为该类,从而实现多态。

5.执行上述代码,输出结果如下:

详细转载于:http://c.biancheng.net/view/1001.html

OUTPUT:
长方形的面积:
81.0
===============================
三角形的面积:
24.0
===============================
父类中计算对象面积的方法,没有实际意义,需要在子类中重写。
0.0

看完例子现在是不是:

                                                                  

多态的优点

  • 1. 消除类型之间的耦合关系
  • 2. 可替换性
  • 3. 可扩充性
  • 4. 接口性
  • 5. 灵活性
  • 6. 简化性

总结 

多态简单理解就是同个东西在某些特定的情况下面可以出现不同的结果,在继承中配合向上转型可以实现很功能,我们需要好好的学习多态,毕竟在后面做工程中用到的还是很多的。

多态结合继承和封装可以做出不一样的东西大大的简便了程序的可读性,三者其实是一体的谁也离不开谁,所以我们需要一起掌握封装,继承和多态这Java三大特点。

后言

这些都是自己翻阅资料或者是查看其他大佬的blog总结的,如有侵权请告知!!!如有错误请指出,谢谢。希望对你们有所帮助,本人也正在学习Java的路上也是小白一枚,还需要大佬们的多多支持。

整理不易,点赞支持!!!

                                                                    

 No pains No results

猜你喜欢

转载自blog.csdn.net/weixin_45629315/article/details/105938017