Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 日韩在线视频观看,亚洲综合二区,日韩视频一区二区三区

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          如何混淆JavaScript代碼?

          如何混淆JavaScript代碼?

          何混淆JavaScript代碼?

          JavaScript混淆是一種技術,用于使代碼難以閱讀和理解,同時保持其功能性。這通常是為了保護代碼的安全性、隱藏實現細節,或者僅僅是為了阻止隨意的逆向工程嘗試。然而,需要注意的是,混淆并不能提供絕對的安全性,也不應作為主要的防御手段。

          為什么混淆JavaScript?

          1. 保護知識產權:公司或開發者希望保護其獨特的算法和邏輯,防止被競爭對手竊取或復制。

          2. 隱藏實現細節:有時候,開發者可能希望隱藏某些特定的實現細節,以降低被攻擊者利用的風險,或者避免暴露核心的業務邏輯。

          3. 增加攻擊難度:混淆后的代碼對于非專業的攻擊者來說,會大大增加其理解和分析的難度,從而在一定程度上起到威懾作用。

          JavaScript混淆技術

          1. 變量和函數名混淆:將變量和函數名更改為無意義或隨機的名稱,使代碼難以閱讀和理解。這可以通過手動修改或使用專門的混淆工具來實現。

          2. 字符串加密:將代碼中的字符串進行加密或編碼,如使用Base64、Hex等,使得攻擊者難以直接讀取到原始信息。

          3. 控制流混淆:通過改變代碼的執行流程,增加額外的條件判斷、循環和跳轉語句,使得代碼的執行邏輯變得復雜且難以追蹤。

          4. 代碼拆分和動態執行:將代碼拆分成多個部分,并在運行時動態地拼接和執行這些部分。這樣可以使攻擊者難以通過靜態分析來獲取完整的代碼邏輯。

          混淆的最佳實踐

          1. 使用成熟的混淆工具:如JShaman、JS-Obfuscator等,這些工具已經經過廣泛的測試和應用,可以提供可靠的混淆效果。

          2. 徹底測試混淆后的代碼:在混淆代碼后,進行全面的測試以確保其仍然能夠正常工作,沒有引入新的錯誤或問題。

          3. 不要過度依賴混淆:混淆只能作為一種額外的安全措施,而不應成為主要的安全手段。開發者仍需要關注其他的安全最佳實踐,如輸入驗證、訪問控制等。

          4. 意識到混淆的局限性:混淆后的代碼可能會增加調試和維護的難度。因此,在決定對代碼進行混淆之前,需要權衡其帶來的好處和潛在的負面影響。

          結論

          JavaScript混淆是一種有效的技術,可以幫助保護代碼的安全性、隱藏實現細節,并增加攻擊者分析的難度。

          程控制,是任何一門編程語言都有的一個語法。

          如果你學習C語言,或者學過C#、Java等,應該對“流程控制”很熟悉。

          所謂的流程控制,指的是控制程序按照怎樣的順序執行。

          在JavaScript中,共有三種流程控制方式(其實任何語言也都只有這三種啦)。

          順序結構

          選擇結構

          循環結構

          順序結構

          在JavaScript中,順序結構是最基本的結構。所謂順序結構,

          就是代碼按照從上到下、從左到右的“順序”執行,

          舉例:

          <!DOCTYPE html>

          <html>

          <head>

          <title></title>

          <meta charset="utf-8" />

          <script>

          var str1="綠葉學習網";

          var str2="JavaScript";

          var str3=str1 + str2;

          document.write(str3);

          </script>

          </head>

          <body>

          </body>

          </html>

          么是多態

          面向對象程序設計有三要素:封裝、繼承(或組合)、多態,前兩者較好理解,多態總讓人困惑,不知道具體有什么作用,更不知道為什么要用多態。今天就來詳細分析下什么是多態,以及多態有哪些好處,為什么要用多態?

          多態是指同一行為作用于不同對象時,可以表現出多種不同的形式和結果來。例如,子類繼承父類并覆蓋其方法后,用父類引用指向子類對象并調用該方法時,實際執行的是子類的方法。

          這種根據對象實際類型而非聲明類型來確定執行方法的行為,就是多態性的體現。多態主要通過繼承和接口實現,允許同一接口有多種不同的實現方式。

          多態的分類

          • 編譯時多態,又稱靜態綁定,是指編譯器在編譯時通過檢查引用類型的方法是否存在,來定位到相應的類及其方法,而不檢查實際對象是否支持該方法。編譯時多態主要體現在方法重載上,即根據參數類型、數量和順序,在編譯時確定要執行的方法。
          • 運行時多態,又稱動態綁定,是指程序在運行時根據對象的實際類型來確定調用哪個方法,而不是在編譯時確定。這意味著方法的具體實現取決于對象的實際類型,而非其聲明類型。父類引用可以指向不同的子類對象,使得相同方法調用產生不同的行為結果。通過運行時確定具體執行的方法,代碼具有更好的擴展性和可維護性。

          多態的實現方式

          編譯時多態,方法重載(Overloading):

          重載指在同一個類中可以有多個方法,這些方法名稱相同但參數列表不同(參數數量或類型不同)。

          編譯器在編譯階段就能確定具體的方法。以下是一個重載示例,展示了多個同名方法,但參數個數或類型不同。重載的好處是簡化接口設計,不需要為不同類型編寫多個方法名。

          java// OverloadExample.java  全部源碼見文檔鏈接
          /**
           * 重載示例,同名方法,參數個數或類型不同。
           * 編譯器在編譯時確定具體的調用方法。
           */
          class Calculator {
              public int add(int num1, int num2) {
                  return num1 + num2;
              }
          
              public int add(int... nums) {
                  int sum=0;
                  for (int num : nums) {
                      sum +=num;
                  }
                  return sum;
              }
          }
          

          運行時多態,方法重寫(Override)與轉型(Casting):

          運行時多態是在程序運行時確定實際要執行的方法。

          當子類繼承父類并覆蓋同名方法時,這稱為重寫。使用父類引用來聲明子類對象時,子類會向上轉型為父類類型。調用該對象的方法時,實際執行的是子類的方法,而不是父類的方法。

          向上轉型是指使用父類引用聲明子類對象,使子類對象的實際類型變為父類。通過父類引用調用子類的方法,使代碼更加通用,處理一組相關對象時無需知道它們的具體類型。

          向下轉型則是將父類引用轉換為子類引用,這需要顯式進行,并且在轉換前需要使用 instanceof 關鍵字進行類型檢查。

          java// OverrideExample.java 全部源碼見文檔鏈接
          /**
           * 重寫示例,子類覆蓋父類同名方法,體現多態。
           * 子類向上轉型為父類型,父類強制向下轉型為子類型。
           */
          class Shape {
            void draw() {
              System.out.println("Shape->draw");
            }
          
            void drawShape() {
              System.out.println("Shape->drawShape");
            }
          }
          
          class Circle extends Shape {
            @Override
            void draw() {
              System.out.println("Circle->draw");
            }
          
            void drawCircle() {
              System.out.println("Circle->drawCircle");
            }
          }
          
          class Square extends Shape {
            @Override
            void draw() {
              System.out.println("Square->draw");
            }
          
            void drawSquare() {
              System.out.println("Square->drawSquare");
            }
          }
          
          public class OverrideExample {
            public static void main(String[] args) {
              // 用父類引用聲明子類對象,向上轉型
              Shape shape1=new Circle();
              Shape shape2=new Square();
          
              // 子類有同名方法,動態綁定到子類,實質執行的是Circle.draw(),體現多態
              shape1.draw();
          
              // 報錯,編譯時按聲明類型檢查,Shape類中沒有drawCircle方法
              // shape1.drawCircle();
          
              // 執行父類方法,輸出 "Shape->drawShape"
              shape1.drawShape();
          
              if (shape2 instanceof Square) {
                // 向下轉型,用子類重新聲明,成為子類型了
                Square mySquare=(Square) shape2;
          
                // 輸出 "Square->draw"
                mySquare.draw();
          
                // 輸出 "Square->drawSquare"
                mySquare.drawSquare();
          
                // 報錯。若強轉為父類型,則無法調用drawSquare方法
                // ((Shape) mySquare).drawSquare();
          
                // 繼承父類,輸出 "Shape->drawShape"
                mySquare.drawShape();
              }
            }
          }
          
          

          多態三個必要條件:

          嚴格來說,多態需要具備以下三個條件。

          1. 繼承:子類繼承父類或實現接口。
          2. 重寫:子類覆蓋父類的方法。
          3. 父類聲明子類:使用父類引用來聲明子類對象。

          重載不屬于嚴格意義上的多態,因為重載在編譯階段就確定了。我們主要探討運行時的多態,即針對某個類型的方法調用,實際執行的方法取決于運行時的對象,而不是聲明時的類型。

          java// 父類
          class Animal {
              void makeSound() {
                  System.out.println("Animal makes a sound");
              }
          }
          
          // 子類繼承并重寫同名方法
          class Dog extends Animal {
              @Override
              void makeSound() {
                  System.out.println("Dog barks");
              }
          }
          
          public class Test {
              public static void main(String[] args) {
                   // 父類引用聲明子類
                  Animal myAnimal=new Dog();
                   // 運行時對象為子類,故輸出"Dog barks"
                  myAnimal.makeSound();
              }
          }
          

          如何理解父類聲明子類 Parent child=new Child();

          • 解釋:用 Parent 類聲明了一個 child 引用變量(變量存于棧中),并賦值為 Child 實例對象(對象存于堆中)。變量 child 的類型為 Parent(向上轉型),它的值是一個 Child 類型的實例對象。
          • 加載執行順序: 編譯時:JVM 編譯時檢查類的關系和對應方法(包括重載),確定變量的類型并定位相關方法名稱,生成字節碼。 運行時
          • JVM 加載 Parent 和 Child 類。
          • 根據 Parent 和 Child 的大小分配堆內存。
          • 初始化 new Child() 并返回對象引用。
          • 分配棧內存給變量 child。
          • 將對象引用賦值給 child。
          • 總結: 編譯時根據引用類型(不是實例對象)確定方法的名稱和參數(包括重載)。 運行時如果子類覆蓋了父類的方法,則調用子類(實例引用類型)的方法;如果沒有覆蓋,則執行父類(變量引用類型)的方法。

          多態的好處,為什么要用多態?

          在面向對象設計中,“開閉原則”是非常重要的一條。即系統中的類應該對擴展開放,而對修改關閉。這樣的代碼更可維護和可擴展,同時更加簡潔與清晰。

          延續上面的例子,假設業務需要擴充更多子類,我們可以通過以下步驟來體現開閉原則:

          1. 新增子類:根據業務需求,新增符合現有類層次結構的子類,例如增加AnotherChild。
          2. 繼承和重寫:新的子類應該繼承自適當的父類,并根據需要重寫父類的方法或添加新的方法。
          3. 不需要修改現有的代碼:遵循開閉原則,我們不修改現有的 Parent 和 Child 類的代碼。
          4. 使用多態:通過父類引用來聲明子類,例如 Parent child=new AnotherChild();,這樣代碼中現有的邏輯不需要改變。
          5. 編譯時不變性:編譯時確定方法調用的特性不改變,仍然根據引用類型來確定方法的名稱和參數,子類隨意增加,只要覆蓋父類同名方法即可。
          6. 運行時多態性:運行時根據實際對象的類型來決定要執行的方法,這使得代碼具有良好的可擴展性和可維護性。
          java// 定義一個通用Animal類
          class Animal {
              void makeSound() {
                  System.out.println("Animal makes a sound");
              }
          }
          
          // 定義Dog類,它是動物的子類
          class Dog extends Animal {
              @Override
              void makeSound() {
                  System.out.println("Dog barks");
              }
          }
          
          // 定義Cat類,它是動物的子類
          class Cat extends Animal {
              @Override
              void makeSound() {
                  System.out.println("Cat meows");
              }
          
              // Cat自有方法
              void meow() {
                  System.out.println("Cat is meowing...");
              }
          }
          
          // 定義一個動物園類,管理不同的動物
          class Zoo {
              // 傳入的是抽象父類或接口,方便擴展
              void letAnimalMakeSound(Animal animal) {
                  animal.makeSound();
              }
          }
          
          public class AnimalExample {
              public static void main(String[] args) {
                  Zoo zoo=new Zoo();
          
                  Animal myDog=new Dog(); // 向上轉型
                  Animal myCat=new Cat(); // 向上轉型
                  ((Cat)myCat).meow(); // 向下強轉,打印自有方法
          
                  // 通過多態性,動物園可以使用相同的方法處理不同種類的動物
                  zoo.letAnimalMakeSound(myDog); // 輸出 "Dog barks"
                  zoo.letAnimalMakeSound(myCat); // 輸出 "Cat meows"
              }
          }
          

          要增加新的動物(如鳥類,Bird),只需擴展 Animal 類,而無需修改現有 Zoo 類中的方法。

          javaclass Bird extends Animal {
              @Override
              void makeSound() {
                  System.out.println("Bird chirps");
              }
          }
          
          public class AnimalExample {
              public static void main(String[] args) {
                  Zoo zoo=new Zoo();
          
                  Animal myDog=new Dog(); // 向上轉型
                  Animal myCat=new Cat(); // 向上轉型
                  Animal myBird=new Bird(); // 向上轉型
          
                  // 通過多態性,動物園可以使用相同的方法處理不同種類的動物
                  zoo.letAnimalMakeSound(myDog); // 輸出 "Dog barks"
                  zoo.letAnimalMakeSound(myCat); // 輸出 "Cat meows"
                  zoo.letAnimalMakeSound(myBird); // 輸出 "Bird chirps"
              }
          }
          

          這種設計:

          • 允許新增 Animal 的子類,保持對擴展開放;
          • 無需修改依賴 Zoo 的 letAnimalMakeSound 方法,實現對修改封閉。

          我們的業務總在不停變化,如何使得代碼底層不用大改,而表層又能跟隨業務不停變動,這就顯得十分重要。通過這種方式,我們在不修改現有代碼的情況下,可以輕松地引入新的子類并擴展系統功能,同時保持現有代碼的穩定性和可靠性。

          其他語言如何實現多態?

          不同語言因為語言特性的不同,在實現多態上也有不同。Go語言有接口,有struct,但沒有繼承和方法重載,實現多態與Java有所不同。Python和JavaScript作為動態語言,沒有接口和顯式類型聲明,但由于其本身的靈活性,在實現多態上也跟Java有區別。C語言沒有class和接口,struct也沒有成員函數,可通過struct和函數指針來模擬多態。C++有class,在多態上跟Java有點像,但其支持多重繼承,且顯示聲明為virtual的方法才支持動態綁定,其核心機制上與Java也有所不同。

          雖然各語言實現多態各不相同,但總的概念是一致的,即通過多態達到“開閉原則”的設計目標。以下一些語言的例子,其他例子請從倉庫查找源碼。

          Go語言例子

          在Go語言中,雖然沒有傳統意義上的類繼承、父類聲明子類和方法重載,但通過結構體(struct)和接口(interface)以及匿名組合等方式實現類似的功能。這樣也能實現代碼的組織和復用,同時保持了靈活性和簡潔性。

          gopackage main
          
          import (
            "fmt"
          )
          
          // 定義一個Animal接口
          type Animal interface {
            MakeSound()
          }
          
          // 定義一個 Dog 類型
          type Dog struct{}
          
          // 實現 Animal 接口的 MakeSound 方法
          func (d Dog) MakeSound() {
            fmt.Println("Dog barks")
          }
          
          // 定義一個 Cat 類型
          type Cat struct{}
          
          // 實現 Animal 接口的 MakeSound 方法
          func (c Cat) MakeSound() {
            fmt.Println("Cat meows")
          }
          
          // Cat自有方法
          func (c *Cat) Meow() {
            fmt.Println("Cat is meowing...")
          }
          
          // 定義一個 Zoo 類型,用于管理動物
          type Zoo struct{}
          
          // 定義一個方法,讓動物發出聲音
          func (z Zoo) LetAnimalMakeSound(a Animal) {
            a.MakeSound()
          }
          
          func main() {
            zoo :=Zoo{}
            myDog :=Dog{}
            // 接口斷言
            var myCat Animal=&Cat{}
            // 類型斷言,打印自有方法
            (myCat.(*Cat)).Meow()
          
            // 使用多態性,通過接口類型處理不同的具體類型
            zoo.LetAnimalMakeSound(myDog) // 輸出 "Dog barks"
            zoo.LetAnimalMakeSound(myCat) // 輸出 "Cat meows"
          }
          

          當需要增加Bird類型時,直接增加即可。同樣無需修改Zoo類里面的LetAnimalMakeSound方法。

          gotype Bird struct{}
          
          // 實現 Animal 接口的 MakeSound 方法
          func (b Bird) MakeSound() {
              fmt.Println("Bird chirps")
          }
          
          func main() {
            zoo :=Zoo{}
            myDog :=Dog{}
            var myCat Animal=&Cat{}
            (myCat.(*Cat)).Meow()
            myBird :=Bird{}
          
            // 使用多態性,通過接口類型處理不同的具體類型
            zoo.LetAnimalMakeSound(myDog)  // 輸出 "Dog barks"
            zoo.LetAnimalMakeSound(myCat)  // 輸出 "Cat meows"
            zoo.LetAnimalMakeSound(myBird) // 輸出 "Bird chirps"
          }
          

          嚴格的多態概念,包括子類繼承父類、方法重寫以及父類聲明子類等,這些特性在Go語言中無法實現。Go語言沒有class概念,雖然它的struct可以包含方法,看起來像class,但實際上沒有繼承和重載的支持,它們本質上仍是結構體。

          Go語言摒棄了傳統面向對象語言中的class和繼承概念,我們需要用新的視角來理解和實踐面向對象編程在Go中的應用方式

          JavaScript語言例子

          JavaScript是一種動態弱類型的基于對象的語言,其一切皆是對象。它通過對象的原型鏈來實現面向對象編程。盡管JavaScript具有class和繼承的能力,但由于缺少強類型系統,因此無法實現傳統意義上的多態。

          當然,JavaScript作為動態語言,具有天然的動態性優勢。這使得它在靈活性和擴展性方面更具優勢。

          js// 定義一個通用Animal類
          class Animal {
              makeSound() {
                  console.log("Animal makes a sound");
              }
          }
          
          // 定義Dog類,它是動物的子類
          class Dog extends Animal {
              makeSound() {
                  console.log("Dog barks");
              }
          }
          
          // 定義Cat類,它是動物的子類
          class Cat extends Animal {
              makeSound() {
                  console.log("Cat meows");
              }
              // Cat自有函數
              meow() {
                  console.log("Cat is meowing...", this);
              }
          }
          
          // 定義一個動物園類,管理不同的動物
          class Zoo {
              // JS沒有嚴格類型,出原始數據類型外,其他均是Object
              // 說出傳入的對象只要有makeSound方法即可。
              letAnimalMakeSound(animal) {
                  animal.makeSound();
              }
          }
          
          // 測試代碼
          const zoo=new Zoo();
          // JS沒有父類定義子類概念,直接聲明即可,無需向上轉型
          // 通過instanceof類型判斷時可得到子類和父類類型
          const myDog=new Dog();
          const myCat=new Cat();
          
          // 直接調用自有函數
          myCat.meow();
          
          // 可以動態給對象設置函數并綁定對象 
          myDog.meow=myCat.meow.bind(myDog); 
          myDog.meow();
          
          // 動物園可以使用相同的方法處理不同種類的動物
          // 當需要增加其他動物時,直接建立新的類繼承Animal,而無需修改Zoo。
          zoo.letAnimalMakeSound(myDog); // 輸出 "Dog barks"
          zoo.letAnimalMakeSound(myCat); // 輸出 "Cat meows"
          
          

          可以看出JS要實現Java意義的多態是做不到的,但JavaScript更加靈活方便,聲明對象無需類型,還可以動態添加函數和綁定對象。

          Python語言例子

          py# 定義一個通用Animal類  
          class Animal:  
              def make_sound(self):  
                  print("Animal makes a sound")  
            
          # 定義Dog類,繼承Animal
          class Dog(Animal):  
              name="Dog"
              def make_sound(self):  
                  print("Dog barks")  
            
          # 定義Cat類,繼承Animal
          class Cat(Animal):  
              name="Cat"
              def make_sound(self):  
                  print("Cat meows")  
            
              # Cat自有方法  
              def meow(self):  
                  print(self.name + " is meowing...")  
            
          # 定義Bird類,它是動物的子類  
          class Bird(Animal):  
              def make_sound(self):  
                  print("Bird chirps")  
          
          # 定義管理類
          class Zoo:  
              # python與js一樣為動態語言,使用duck typing,不需要顯式聲明接口
              def let_animal_make_sound(self, animal):  
                  animal.make_sound()  
            
          # 測試代碼
          if __name__=="__main__":
              zoo=Zoo()
          
              # 直接創建實例,Python中不需要向上轉型
              my_dog=Dog()
              my_cat=Cat()
              my_bird=Bird()
          
              # 直接調用自有方法
              my_cat.meow()
          
              # Python中可直接給對象設置方法,self不會改變
              my_dog.meow=my_cat.meow
              my_dog.meow()
          
              # 動物園可以使用相同的方法處理不同種類的動物
              zoo.let_animal_make_sound(my_dog)  # 輸出 "Dog barks"
              zoo.let_animal_make_sound(my_cat)  # 輸出 "Cat meows"
              zoo.let_animal_make_sound(my_bird)  # 輸出 "Bird chirps"
          

          Python是一種動態語言,它使用 self 參數來引用實例,無需像其他語言那樣使用 new 關鍵字來實例化對象。Python沒有嚴格的接口概念,不需要像其他語言那樣顯示聲明對象的接口。Python通過繼承和方法重寫來實現多態概念,但不支持傳統意義上的父類聲明子類和方法重載。

          因此,Python在多態性上的表現與JavaScript相似,都是基于動態語言特性,靈活而動態,通過繼承和重寫實現對象行為的多樣性。

          Java多態實例詳解

          理解Java多態的實例可以幫助澄清其原理和執行過程。以下是一個簡單而詳盡的例子,幫助你全面理解Java中多態的工作機制。

          // PolymorphismSimple.java
          // 父類A
          class A {
              public String show(D object) {
                  return ("A and D");
              }
          
              public String show(A object) {
                  return ("A and A");
              }
          
              // 默認注釋掉。可開關注釋測試下
              // public String show(B object) {
              // return ("A and B");
              // }
          }
          
          // 子類B
          class B extends A {
              public String show(B object) {
                  return ("B and B");
              }
          
              public String show(A object) {
                  return ("B and A");
              }
          }
          
          // 孫子類C
          class C extends B {
          }
          
          // 孫子類D
          class D extends B {
          }
          
          // 測試驗證
          public class PolymorphismSimple {
              public static void main(String[] args) {
                  // 父類聲明自己
                  A a=new A();
                  // 父類聲明子類
                  A ab=new B();
                  // 子類聲明自己
                  B b=new B();
                  C c=new C();
                  D d=new D();
          
                  // 1) A and A。b的類型是B,也是B的實例,A里沒有show(B)方法,但有show(A)方法。B的父類是A,因此定位到A.show(A)。
                  System.out.println("1) " + a.show(b));
          
                  // 2) A and A。c的類型是C,也是C的實例,C繼承B,B繼承A。A里沒有show(C)方法,也沒有show(B)方法,最后指向A.show(A)。
                  System.out.println("2) " + a.show(c));
          
                  // 3) A and D, d的類型是D,也是D的實例,D繼承B,B繼承A。A里有show(D)方法,直接定位到A.show(D)。
                  System.out.println("3) " + a.show(d));
          
                  // 4) B and A, ab是B的實例,但用A聲明,即向上轉型得到的類型是A,運行時才能確定具體該調用哪個方法。
                  // ab是B的實例對象,但引用類型是A。類型是在編譯時確定,因此從類型開始定位方法。
                  // A類中沒有show(B)方法,但有show(A)方法,因為A是B的父類,ab也是A的實例,于是定位到A.show(A)方法。
                  // 由于B是A的子類,且B重寫了A的show(A),A的方法被覆蓋了,于是定位到B.show(A),這就是動態綁定。
                  // 雖然B中有show(B)方法,但是因為ab的類型是A,編譯時根據類型定位到A的方法,而不是B。
          
                  // 以下幾種可開關打開/注釋代碼測試下。
                  // -
                  // 若A里有show(A)和show(B),B里有show(B)有show(A),則編譯時關聯到A.show(B),因B覆蓋了A.show(B),動態綁定到B.show(B)。
                  // -
                  // 若A里有show(A)和show(B),B里無show(B)有show(A),則編譯時關聯到A.show(B),因B無覆蓋,則直接調用A.show(B)。
                  // -
                  // 若A里有show(A)無show(B),B里無show(B)有show(A),則編譯時關聯到A.show(A),因B覆蓋了A.show(A),動態綁定到B.show(A)。
                  // -
                  // 若A里有show(A)無show(B),B里無show(A)有show(B),則編譯時關聯到A.show(A),因B無覆蓋,則直接調用A.show(A)。
                  // 查找順序為:編譯時根據引用類型確定所屬類 -> 根據重載參數類型定位(類型按子->父->祖逐級往上查找)到類的具體方法(包括繼承的方法) ->
                  // 運行時實例對象覆蓋(覆蓋只有子->父一層)了引用類型的同名方法 -> 定位到實例對象的方法。
                  System.out.println("4) " + ab.show(b));
          
                  // 5) B and A。ab是B的實例,類型是A。從A類沒找到show(C)方法,也沒找到A.show(B)方法,找到A.show(A)方法。A.show(A)被B.show(A)覆蓋,因此調用B.show(A)。
                  System.out.println("5) " + ab.show(c));
          
                  // 6) A and D。A里面有show(D)的方法,直接定位到。
                  System.out.println("6) " + ab.show(d));
          
                  // 7) B and B。B里面有show(B)的方法,直接定位到。
                  System.out.println("7) " + b.show(b));
          
                  // 8) B and B。B沒有show(c)方法,但有show(B)方法。C繼承自B,父類型是B,因此調用B.show(B)。
                  System.out.println("8) " + b.show(c));
          
                  // 9) A and D。B中沒有show(D)方法,B繼承A,A里有show(D), 故調用A.show(D)方法。
                  System.out.println("9) " + b.show(d));
          
                  // 10) B and A。父類聲明子類,存在向上轉型。A里有show(A),被B.show(A)覆蓋了,因此定位到B.show(A)。
                  System.out.println("10) " + ab.show(a));
          
              }
          }
          

          總結

          多態包括編譯時多態和運行時多態。編譯時多態,即靜態綁定,通常通過方法重載實現。運行時多態則是在代碼運行時確定具體調用的方法。

          從Java的角度看,嚴格意義上的多態需要滿足三個條件:繼承、方法覆蓋和父類引用子類對象。Java完全符合這些要求,實現了嚴格意義上的多態。

          Go語言、Python和JavaScript不完全符合嚴格意義上的多態,但具備多態特性,能夠達成動態確定實際要執行的方法,從而使代碼更加靈活、易于維護和擴展。

          各語言完整示例

          https://github.com/microwind/design-pattern/tree/main/programming-paradigm/oop/polymorphism

          簡單示例

          PolymorphismSimple.java PolymorphismSimple.go polymorphism_simple.c PolymorphismSimple.cpp PolymorphismSimple.js PolymorphismSimple.py PolymorphismSimple.ts


          主站蜘蛛池模板: 麻豆视传媒一区二区三区| 国产精品一区二区在线观看| 中文字幕在线播放一区| 亚洲午夜精品一区二区麻豆 | 国产一区二区福利久久| 日韩福利视频一区| 国产乱码精品一区二区三区四川人| 中文字幕av一区| 日韩十八禁一区二区久久| 日韩免费视频一区二区| 中文字幕AV一区二区三区人妻少妇| 日韩色视频一区二区三区亚洲| 视频一区在线播放| 无码人妻精品一区二区三区在线| 亚洲av无码片区一区二区三区| 国产一区二区三区在线免费观看| 亚洲老妈激情一区二区三区| 日韩中文字幕一区| 国产亚洲3p无码一区二区| 无码一区二区三区AV免费| 国产成人精品无人区一区| 国产精品分类视频分类一区| 国产一区韩国女主播| 少妇精品久久久一区二区三区| 国产人妖在线观看一区二区| 亚洲福利视频一区| 亚洲国产综合无码一区二区二三区| 国产成人精品无码一区二区| 日本中文一区二区三区亚洲| 亚洲福利电影一区二区?| 久久亚洲中文字幕精品一区四| 男插女高潮一区二区| 中文字幕一区二区人妻| 亚洲Av永久无码精品一区二区| 国产一区二区电影| 国产91精品一区二区麻豆亚洲| 亚洲色无码专区一区| 无码国产精品一区二区免费模式| 精品一区二区三区影院在线午夜| 亚洲天堂一区二区三区四区| 国产精品一区二区久久不卡|