?作者簡介:大家好,我是橘橙黃又青,一個想要與大家共同進步的男人????
??個人主頁:再無B~U~G-CSDN博客
1.多態(tài)
1.1 多態(tài)的概念


1.2 多態(tài)實現(xiàn)條件
1. 必須在繼承體系下2. 子類必須要對父類中方法進行重寫3. 通過父類的引用調用重寫的方法
?多態(tài)體現(xiàn):在代碼運行時,當傳遞不同類對象時,會調用對應類中的方法。
案例(反復觀看):
public class Animal {
String name;
int age;
//構造方法
public Animal(String name, int age){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(name + "吃飯");
}
}
public class Cat extends Animal{
public Cat(String name, int age){
super(name, age);
}
@Override
public void eat(){
System.out.println(name+"吃魚~~~");
}
}
public class Dog extends Animal {
public Dog(String name, int age){
super(name, age);
}
@Override
public void eat(){
System.out.println(name+"吃骨頭~~~");
}
}
///分割線//
public class TestAnimal {
// 編譯器在編譯代碼時,并不知道要調用Dog 還是 Cat 中eat的方法
// 等程序運行起來后,形參a引用的具體對象確定后,才知道調用那個方法
// 注意:此處的形參類型必須時父類類型才可以
public static void eat(Animal a){
a.eat();
}
public static void main(String[] args) {
Cat cat = new Cat("元寶",2);
Dog dog = new Dog("小七", 1);
eat(cat);
eat(dog);
}
}
輸出結果:
元寶吃魚 ~~~元寶正在睡覺小七吃骨頭 ~~~小七正在睡覺
?
1.3 重寫
【方法重寫的規(guī)則】?
- 訪問權限不能比父類中被重寫的方法的訪問權限更低。例如:如果父類方法被public修飾,則子類中重寫該方法就不能聲明為 protected
- 子類在重寫父類的方法時,一般必須與父類方法原型一致: 返回值類型 方法名 (參數列表) 要完全一致
- 被重寫的方法返回值類型可以不同,但是必須是具有父子關系的.
- 父類被static、private修飾的方法、構造方法都不能被重寫。
- 重寫的方法, 可以使用 @Override 注解來顯式指定. 有了這個注解能幫我們進行一些合法性校驗. 例如不小心將方法名字拼寫錯了 (比如寫成 aet), 那么此時編譯器就會發(fā)現(xiàn)父類中沒有 aet 方法, 就會編譯報錯, 提示無法構成重寫.
?【重寫和重載的區(qū)別】
區(qū)別點
|
重寫
(override)
|
重載
(override)
|
參數列表
|
一定不能修改
|
必須修改
|
返回類型
|
一定不能修改【除非可以構成父子類關系】
|
可以修改
|
訪問限定符
|
一定不能做更嚴格的限制(可以降低限制)
|
可以修改
|
?
靜態(tài)綁定 :也稱為前期綁定 ( 早綁定 ) ,即在編譯時,根據用戶所傳遞實參類型就確定了具體調用那個方法。典型代表函數重載。動態(tài)綁定 :也稱為后期綁定 ( 晚綁定 ) ,即在編譯時,不能確定方法的行為,需要等到程序運行時,才能夠確定具體調用那個類的方法。
1.4 向上轉移和向下轉型
2.4.1 向上轉型
?向上轉型:實際就是創(chuàng)建一個子類對象,將其當成父類對象來使用。
語法格式:父類類型 對象名 = new 子類類型()
比如:
Animal animal = new Cat("元寶",2); ?
animal是父類類型,但可以引用一個子類對象,因為是從小范圍向大范圍的轉換。 ?
public class TestAnimal {
// 2. 方法傳參:形參為父類型引用,可以接收任意子類的對象
public static void eatFood(Animal a){
a.eat();
}
// 3. 作返回值:返回任意子類對象
public static Animal buyAnimal(String var){
if("狗".equals(var) ){
return new Dog("狗狗",1);
}else if("貓" .equals(var)){
return new Cat("貓貓", 1);
}else{
return null;
}
}
public static void main(String[] args) {
Animal cat = new Cat("元寶",2); // 1. 直接賦值:子類對象賦值給父類對象
Dog dog = new Dog("小七", 1);
eatFood(cat);
eatFood(dog);
Animal animal = buyAnimal("狗");
animal.eat();
animal = buyAnimal("貓");
animal.eat();
}
}
2.4.2 向下轉型

package com.cdm.test;
class Animal {
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println(this.name +" 正在吃!");
}
}
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age);//alt +回車
}
public void bark() {
System.out.println(this.name + " 旺旺叫!");
}
@Override
public void eat() {
System.out.println(this.name +" 正在吃狗糧!");
}
}
class Cat extends Animal {
public Cat(String name, int age) {
super(name, age);//alt +回車
}
public void bark() {
System.out.println(this.name + " 喵喵叫!");
}
@Override
public void eat() {
System.out.println(this.name +" 正在貓狗糧!");
}
}
package com.cdm.test;
public class TestAnimal {
public static void main(String[] args) {
Cat cat = new Cat("元寶",2);
Dog dog = new Dog("小七", 1);
// 向上轉型
Animal animal = cat;
animal.eat();
animal = dog;
animal.eat();
// animal.bark();
// 編譯失敗,編譯時編譯器將animal當成Animal對象處理
// 而Animal類中沒有bark方法,因此編譯失敗
// 向上轉型
// 程序可以通過編程,但運行時拋出異常---因為:animal實際指向的是狗
// 現(xiàn)在要強制還原為貓,無法正常還原,運行時拋出:ClassCastException
cat = (Cat)animal;
cat.bark();
// animal本來指向的就是狗,因此將animal還原為狗也是安全的
dog = (Dog)animal;
dog.bark();
}
}
報錯信息:
public class TestAnimal {
public static void main(String[] args) {
Cat cat = new Cat("元寶",2);
Dog dog = new Dog("小七", 1);
// 向上轉型
Animal animal = cat;
animal.eat();
animal = dog;
animal.eat();
if(animal instanceof Cat){
cat = (Cat)animal;
cat.mew();
}
if(animal instanceof Dog){
dog = (Dog)animal;
dog.bark();
}
}
}
關于instanceof和equals我們后面會講到。
2.5 多態(tài)的優(yōu)缺點
假設有如下代碼:
class Shape {
//屬性....
public void draw() {
System.out.println("畫圖形!");
}
}
class Rect extends Shape{
@Override
public void draw() {
System.out.println("?");
}
}
class Cycle extends Shape{
@Override
public void draw() {
System.out.println("●");
}
}
class Flower extends Shape{
@Override
public void draw() {
System.out.println("?");
}
}
什么叫 "圈復雜度" ?
- 圈復雜度是一種描述一段代碼復雜程度的方式. 一段代碼如果平鋪直敘, 那么就比較簡單容易理解. 而如果有很多的條件分支或者循環(huán)語句, 就認為理解起來更復雜.
- 因此我們可以簡單粗暴的計算一段代碼中條件語句和循環(huán)語句出現(xiàn)的個數, 這個個數就稱為 "圈復雜度". 如果一個方法的圈復雜度太高, 就需要考慮重構.
- 不同公司對于代碼的圈復雜度的規(guī)范不一樣. 一般不會超過 10
例如我們現(xiàn)在需要打印的不是一個形狀了, 而是多個形狀. 如果不基于多態(tài), 實現(xiàn)代碼如下: ?文章來源:http://www.zghlxwxcb.cn/news/detail-851489.html
public static void drawShapes() {
Rect rect = new Rect();
Cycle cycle = new Cycle();
Flower flower = new Flower();
String[] shapes = {"cycle", "rect", "cycle", "rect", "flower"};
for (String shape : shapes) {
if (shape.equals("cycle")) {
cycle.draw();
} else if (shape.equals("rect")) {
rect.draw();
} else if (shape.equals("flower")) {
flower.draw();
}
}
}
public static void drawShapes() {
// 我們創(chuàng)建了一個 Shape 對象的數組.
Shape[] shapes = {new Cycle(), new Rect(), new Cycle(),
new Rect(), new Flower()};
for (Shape shape : shapes) {
shape.draw();
}
}
class Triangle extends Shape {
@Override
public void draw() {
System.out.println("△");
}
}
1. 屬性沒有多態(tài)性????????當父類和子類都有同名屬性的時候,通過父類引用,只能引用父類自己的成員屬性2. 構造方法沒有多態(tài)性
2.6 避免在構造方法中調用重寫的方法 ?
class B {
public B() {
// do nothing
func();
}
public void func() {
System.out.println("B.func()");
}
}
class D extends B {
private int num = 1;
@Override
public void func() {
System.out.println("D.func() " + num);
}
}
public class Test {
public static void main(String[] args) {
D d = new D();
}
}
// 執(zhí)行結果D . func () 0
原因:文章來源地址http://www.zghlxwxcb.cn/news/detail-851489.html
- 構造 D 對象的同時, 會調用 B 的構造方法.
- B 的構造方法中調用了 func 方法, 此時會觸發(fā)動態(tài)綁定, 會調用到 D 中的 func
- 此時 D 對象自身還沒有構造, 此時 num 處在未初始化的狀態(tài), 值為 0.?
- 所以在構造函數內,盡量避免使用實例方法,除了final和private方法。
到了這里,關于【JAVASE】帶你了解面向對象三大特性之一(多態(tài))的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!