1. 程式人生 > >Java程式設計入門筆記(八)

Java程式設計入門筆記(八)

隨遇而安——多型

為什麼使用多型?
不用為每一增加的子類增加對應的麻煩,最重要又可以偷懶了~

什麼是多型?
多型:同一個引用型別,使用不同的例項而執行不同操作

使用父類作為方法形參實現多型
使用父類作為形式引數,可以接受子類的物件作為實參。
進入到方法之後,該物件僅能當做父類使用,無法訪問子類的成員。

public class Master {
    public void feed( Pet pet ) {
       //使用父類作為方法形參   
    }
}
// 測試方法 

Dog dog = new Dog();
Master master = new Master();
master.
feed( dog ); //同一種操作方式,不同的操作物件

父類作為返回值
使用父類作為返回值型別,可以返回任意子類的例項

public class Master {
    public Pet chooseRandomPet(Pet[] pets){
           … …         
    }
}

父類到子類的轉換

public class Dog extends Pet {
	public void catchingFlyDisc() {
       	 … …
	}
}
public class Penguin  extends Pet {
	public void
swimming () { … … } } public class Master { public void play(Pet pet){ // pet.catchingFlyDisc(); //報錯,父類引用不能呼叫子類特有方法 Dog dog = (Dog)pet; dog.catchingFlyDisc(); //可以使用強制型別轉換,將父類轉換成子類型別 } } //測試類 Pet pet = new Dog(); Master master = new Master(); master.playWith(pet);

判斷父類例項的類別


instanceof運算子

語法:物件 instanceof 類或介面

public class Master {
	public void play(Pet pet){
               if (pet instanceof Dog) {    //如果傳入的是狗狗
	         Dog dog = (Dog) pet;
	         dog.catchFlyingDisc();
	}else if (pet instanceof Penguin) {   //如果傳入的是企鵝
	         Penguin pgn = (Penguin) pet;
	         pgn.swim();
	}
	}
}		

塑型

  • 塑型(type-casting)又稱為型別轉換
  • 方式
    隱式(自動)的型別轉換
    顯式(強制)的型別轉換
  • 塑型的物件包括
  • 基本資料型別
    將值從一種形式轉換成另一種形式
    • 引用變數
      將物件暫時當成更一般的物件來對待,並不改變其型別
      只能被塑型為
      • 任何一個父類型別
      • 物件所屬的類實現的一個介面
      • 被塑型為父類或介面後,再被塑型回其本身所在的類

隱式(自動)的型別轉換

  • 基本資料型別
    相容型別之間儲存容量低的自動向儲存容量高的型別轉換
  • 引用變數
    • 被塑型成更一般的類
Employee  emp; 
emp = new Manager(); //將Manager型別的物件直接賦給
                                     //Employee類的引用變數,系統會                                   
                                     //自動將Manage物件塑型為Employee類
  • 被塑型為物件所屬類實現的介面型別
Car  jetta = new Car(); 
Insurable  item = jetta; 

顯式(強制)的型別轉換

  • 基本資料型別
(int)871.34354;     // 結果為 871 
(char)65;              // 結果為‘A’ 
(long)453;            // 結果為453L
  • 引用變數:還原為本來的型別
Employee  emp; 
Manager man;
emp = new Manager();
man = (Manager)emp; //將emp強制塑型為本來的型別

塑型應用的場合

  • 賦值轉換
    賦值號右邊的表示式型別或物件轉換為左邊的型別
  • 方法呼叫轉換
    實參的型別轉換為形參的型別
  • 算數表示式轉換
    算數混合運算時,不同型別的項轉換為相同的型別再進行運算
  • 字串轉換
    字串連線運算時,如果一個運算元為字串,一個運算元為數值型,則會自動將數值型轉換為字串

方法的查詢
如果在塑型前和塑型後的類中都提供了相同的方法,如果將此方法傳送給塑型後的物件,那麼系統將會呼叫哪一個類中的方法?

  • 例項方法的查詢
  • 類方法的查詢

例項方法的查詢
從物件建立時的類開始,沿類層次向上查詢
在這裡插入圖片描述

Manager   man = new Manager(); 
Employee  emp1 = new Employee(); 
Employee  emp2 = (Employee)man; 
emp1.computePay();     // 呼叫Employee類中的computePay()方法 
man.computePay();       // 呼叫Manager類中的computePay()方法  
emp2.computePay();     // 呼叫Manager類中的computePay()方法 

類方法的查詢
總是在引用變數宣告時所屬的類中進行查詢
在這裡插入圖片描述

Manager  man = new Manager(); 
Employee emp1 = new Employee(); 
Employee emp2 = (Employee)man; 
man.expenseAllowance();          //in Manager 
emp1.expenseAllowance();         //in Employee 
emp2.expenseAllowance();         //in Employee!!! 

繫結

指將一個方法呼叫同一個方法主體連線到一起

  • 根據繫結時期的不同,可分為
    • 早期繫結
      程式執行之前執行繫結
    • 晚期繫結
      也叫作“動態繫結”或“執行期繫結
      基於物件的類別,在程式執行時執行繫結
//基類Shape建立了一個通用介面
class Shape { 
    void draw()    {} 
    void erase()   {} 
} 
//派生類覆蓋了draw方法,為每種特殊的幾何形狀都提供獨一無二的行為
class Circle extends Shape { 
	void draw() 
      { System.out.println("Circle.draw()"); } 
	void erase() 
      { System.out.println("Circle.erase()"); } 
}
class Square extends Shape { 
	void draw() 
      { System.out.println("Square.draw()"); }
	void erase() 
      { System.out.println("Square.erase()"); } 
} 
class Triangle extends Shape { 
	void draw() 
      { System.out.println("Triangle.draw()"); } 
   void erase() 
      { System.out.println("Triangle.erase()"); }
 } 
// 對動態繫結進行測試如下
public class BindingTester{ 
    public static void main(String[] args) { 
       Shape[] s = new Shape[9]; 
       int n;
       for(int i = 0; i < s.length; i++) { 
            n = (int)(Math.random() * 3);
            switch(n) {  
                case 0: s[i] =  new Circle(); break;
                case 1: s[i] =  new Square(); break;
                case 2: s[i] =  new Triangle();
             } 
        }      
        for(int i = 0; i < s.length; i++)   s[i].draw(); 
      }
}
執行結果
Square.draw()
Triangle.draw()
Circle.draw()
Triangle.draw()
Triangle.draw()
Circle.draw()
Square.draw()
Circle.draw()
Triangle.draw()
說明
編譯時無法知道s陣列元素的具體型別,執行時才能確定型別,所以是動態繫結
在主方法的迴圈體中,每次隨機生成指向一個Circle、Square或者Triangle的引用
所有類都在music包中
Note類中定義了三個音符
Instrument類中宣告並實現了一個play方法
Wind類繼承了Instrument類,過載了play方法
Music類中包含了main方法
class Note {
  private int value;
  private Note(int val) { value = val; }
  public static final Note
    MIDDLE_C = new Note(0), 
    C_SHARP  = new Note(1),
    B_FLAT   = new Note(2);
} 
class Instrument {
  public void play(Note n) {
    System.out.println("Instrument.play()");
  }
}

class Wind extends Instrument {
  public void play(Note n) {
    System.out.println("Wind.play()");
  }
}
public class Music {
  public static void tune(Instrument i) {
      i.play(Note.MIDDLE_C);
  }
  public static void main(String[] args) {
    Wind flute = new Wind();
    tune(flute); 
  }
} 

執行結果
Wind.play()
說明
執行中,Instrument類的物件實際是Wind類的,所以呼叫了Wind類中的play方法

內部類

  • 在另一個類或方法的定義中定義的類
  • 可訪問其外部類中的所有資料成員和方法成員
  • 可對邏輯上相互聯絡的類進行分組
  • 對於同一個包中的其他類來說,能夠隱藏
  • 可非常方便地編寫事件驅動程式
  • 宣告方式
    • 命名的內部類:可在類的內部多次使用
    • 匿名內部類:可在new關鍵字後宣告內部類,並立即建立一個物件
  • 假設外層類名為Myclass,則該類的內部類名為
    Myclass$c1.class (c1為命名的內部類名)
    Myclass$1.class (表示類中宣告的第一個匿名內部類)
public class Parcel1 {
    class Contents { //內部類
        private int i = 11;
        public int value() { return i; }
     }
     class Destination  { //內部類
        private String label;
        Destination(String whereTo)  {   label = whereTo;    }
        String readLabel() { return label; }
     }
     public void ship(String dest) {
         Contents c = new Contents();
         Destination d = new Destination(dest);
         System.out.println(d.readLabel());
      }
      public static void main(String[] args)  {
       Parcel1 p = new Parcel1();
       p.ship("Tanzania");
    }
} 
說明
在Parcel1類中聲明瞭兩個內部類Contents、Destination
在ship方法中生成兩個內部類物件,並呼叫了內部類中宣告的一個方法

外部類的方法可以返回內部類的引用變數

public class Parcel2 {
   class Contents  {
       private int i = 11;
       public int value() { return i; }
    }
    class Destination {
        private String label;
        Destination(String whereTo) {  label = whereTo;  }
        String readLabel() { return label; }
     }
    public Destination to(String s)
        { return new Destination(s);  } 
    public Contents cont() { return new Contents();  }
    public void ship(String dest) {
        Contents c = cont();
        Destination d = to(dest);          
        System.out.println(d.readLabel());
    }  
    public static void main(String[] args) {
         Parcel2 p = new Parcel2();
         p.ship("Tanzania");
         Parcel2 q = new Parcel2();
          Parcel2.Contents c = q.cont();
          Parcel2.Destination d =q.to("Borneo");
     }
}
說明
to()方法返回內部類Destination的引用
cont()方法返回內部類Contents的引用

內部類實現介面(介面在下一節)
內部類實現介面

  • 可以完全不被看到,而且不能被呼叫
  • 可以方便實現“隱藏實現細則”。你所能得到的僅僅是指向基類(base class)或者介面的一個引用
abstract class Contents {
     abstract public int value();
}
interface Destination {
     String readLabel();
}
public class Parcel3 {
     private class PContents extends Contents {
          private int i = 11;
          public int value() { return i; }
     }
     protected class PDestination implements Destination {
          private String label;
          private PDestination(String whereTo) { label = whereTo;}
          public String readLabel() { return label; }
      }
     public Destination dest(String s) { return new PDestination(s); }
     public Contents cont() { return new PContents(); }
}
class Test {
    public static void main(String[] args) {
        Parcel3 p = new Parcel3();
        Contents c = p.cont();
        Destination d = p.dest("Tanzania");
   }
 } 
說明
內部類PContents實現了抽象了Contents
內部類PDenstination實現了介面Destination
外部類Test中不能宣告對private的內部類的引用

方法中的內部類
在方法內定義一個內部類

  • 為實現某個介面,產生並返回一個引用
  • 為解決一個複雜問題,需要建立一個類,而又不想它為外界所用
public class Parcel4 {
    public Destination dest(String s) {
        class PDestination implements Destination {
             private String label;
             private PDestination(String whereTo) {
             label = whereTo;
         }
         public String readLabel() { return label; }
         return new PDestination(s);
     }
     public static void main(String[] args) {
         Parcel4 p = new Parcel4();
         Destination d = p.dest("Tanzania");
     }
}
public class Parcel5 {
    private void internalTracking(boolean b) {
        if(b) {
            class TrackingSlip {
                private String id;
                TrackingSlip(String s) { id = s;   }
                String getSlip() { return id; }
             }
            TrackingSlip ts = new TrackingSlip("slip");
            String s = ts.getSlip();
          }
     }
     public void track() { internalTracking(true); }
     public static void main(String[] args)  {   
         Parcel5 p = new Parcel5();    
         p.track();  
     }
}
public class Parcel6 {
    public Contents cont() {
        return new Contents() {
           private int i = 11;
           public int value() { return i; }
        }; 
     }
     public static void main(String[] args) {
         Parcel6 p = new Parcel6();
         Contents c = p.cont();
     }
 }

匿名的內部類
基類需要一個含引數的構造方法

public class Parcel7 {
    public Wrapping wrap(int x) {
        return new Wrapping(x) { 
           public int value() { return super.value() * 47; }
        }; 
     }
    public static void main(String[] args) {
        Parcel7 p = new Parcel7();
        Wrapping w = p.wrap(10);
    }
}

匿名內部類物件的初始化

public class Parcel8 {
    public Destination dest(final String dest) {
        return new Destination() {
            private String label = dest;
            public String readLabel() { return label; }
        };
     }
    public static void main(String[] args) {
        Parcel8 p = new Parcel8();
        Destination d = p.dest("Tanzania");
    }
 } 

通過例項初始化構造匿名內部類

public class Parcel9 {
    public Destination dest(final String dest, final float price) {
        return new Destination
            
           

相關推薦

Java程式設計入門筆記

隨遇而安——多型 為什麼使用多型? 不用為每一增加的子類增加對應的麻煩,最重要又可以偷懶了~ 什麼是多型? 多型:同一個引用型別,使用不同的例項而執行不同操作 使用父類作為方法形參實現多型 使用父類作為

Java程式設計入門筆記

驀然回首——資料型別和運算子 分類 資料型 例如int,short,long,double等等 非資料型 String,char 變數命名規則 變數名首字母 字母,

Java程式設計入門筆記

你若安好——類和物件 萬物皆物件 屬性——物件具有的各種特徵 每個物件的每個屬性都擁有特定值 例如:每個學生的姓名、體重都不一樣 方法——物件執行的操作 物件:用來描述客觀事物的一個實體,由一組屬性

Java程式設計入門筆記十一

海納百川——物件陣列和集合 物件陣列 陣列 在Java提供的儲存及隨機訪問物件序列的各種方法中,陣列是效率最高的一種 型別檢查 邊界檢查 優點 陣列知道其元素的型別 編譯時的型別檢查 大小已知 代價 陣列物件的大小是固定的,在生存期內大小不可變 物件

java 併發程式設計學習筆記執行緒池

                                          &nb

java程式設計規範筆記

1. 命名風格     程式碼中的命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束     程式碼中的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式     類名使用UpperCamelCase風格,必須遵從駝峰形式     方法名、引數名

java程式設計規範筆記

(二)常量定義   不允許任何魔法值(即未經定義的常量)直接出現在程式碼中   long或者Long初始賦值時,使用大寫的L,不能是小寫的l,小寫容易跟數字1混淆,造成誤解   不要使用一個常量類維護所有常量,按常量功能進行歸類,分開維護 (三) 程式碼格式  

Java程式設計規範筆記

(四) OOP規約     避免通過一個類的物件引用訪問此類的靜態變數或靜態方法,無謂增加編譯器解析成本,直接用類名來訪問即可     所有的覆寫方法,必須加@Override註解     相同引數型別,相同業務含義,才可以使用Java的可變引數,避免使用Object(

ECMAScript 6 入門筆記Proxy,Reflect

Proxy proxy用於修改某些操作的預設行為,等同於在語言層面作出修改,屬於”超程式設計”。可以理解成架設一層“攔截”,外界對該物件訪問都必須通過這層攔截。 var obj = new Proxy({},{ get: function

JAVA程式設計思想學習筆記介面

介面 抽象類和抽象方法 抽象方法:這種方法不完整,僅有宣告而沒有方法體。所採用的語法如下: abstract void f(); 抽象類:包含抽象方法的類叫做抽象類,如果一個類包含一個或多個抽象方法,該類必須被限定為抽象的。 介面 關鍵字:interface 介面定

Java併發程式設計的藝術筆記——執行緒池

一.執行緒池的主要處理流程   ThreadPoolExecutor執行execute方法分下面4種情況。 1)如果當前執行的執行緒少於corePoolSize,則建立新執行緒來執行任務(注意,執行這一步需要獲取全域性鎖)。 2)如果執行的執行緒等於或多於corePoolSize,則將任

java學習筆記:繼承

this關鍵字 log implement java學習 方式 show 使用 類型 多繼承 繼承 子類擁有父類非private的屬性,方法。 子類可以擁有自己的屬性和方法,即子類可以對父類進行擴展。 子類可以用自己的方式實現父類的方法。 Java的繼承

Java框架spring Boot學習筆記:Spring相關概念

擴展 靜態 輕量級 想要 spring配置 核心 使用 oot 調用方法 Spring是開源、輕量級、一站式框架。 Spring核心主要兩部分 aop:面向切面編程,擴展功能不是修改源代碼實現 ioc:控制反轉,比如一個類,在類裏面有方法(不是靜態的方法),想要調用類

Elastic Stack 筆記Elasticsearch5.6 Java API

erl java api 編寫 ack apach fail row 擴展庫 都是 博客地址:http://www.moonxy.com 一、前言 Elasticsearch 底層依賴於 Lucene 庫,而 Lucene 庫完全是 Java 編寫的,前面的文章都是發送的

python | 爬蟲筆記 - Scrapy入門教程

RoCE yield ini 配置 自己 數據存儲 2.3 rom 提取數據 一、簡介 Scrapy是一個基於Twisted 的異步處理框架,是針對爬蟲過程中的網站數據爬取、結構性數據提取而編寫的應用框架。 可以應用在包括數據挖掘,信息處理或存儲歷史數據等一系列的程序中。

java學習筆記-- 異常

異常體系圖 Error:描述Java執行時內部錯誤與資源耗盡錯誤(OOM,StackOverflow)應用程式不丟擲此類異常。這種內部錯誤一旦出現,除了告知使用者並使用安全終止之外,再無能為力。 Exception(程式本身錯誤):Java應用程式丟擲異常。 IOExce

Java自學筆記

面向物件——繼承 繼承的思想其實很好理解,但是裡面有些東西需要記憶。 理解,繼承可以將之前的類沿襲下來,保留被繼承類的功能。 使用方法:class 類名稱 extends 父類名稱 { …… } 例項:

學習筆記:使用邏輯迴歸檢測JAVA溢位攻擊以及識別驗證碼

(1)檢測JAVA溢位攻擊 1.資料蒐集:載入ADFA-LD正常樣本資料,定義遍歷目錄下檔案的函式,從攻擊資料集中篩選和JAVA溢位攻擊相關的資料,原理同(四) 2.特徵化:與(四)一致,使用詞集模型 3.訓練樣本 logreg = linear_model.LogisticRegr

java丨事件驅動程式設計學習筆記

一、匿名監聽器 監聽器類是特意為建立一個GUI元件(例如,一個按鈕)而設計的監聽物件。監聽器類不被其他應用程式所共享,因此,正確的做法是將它作為一個內部類定義在框架中。 可以使用匿名內部類簡化內部類監聽器。匿名內部類時沒有名字的內部類。它進一步完成定義內部類和建立一個該類的例項。 內部類Enlarg

java基礎筆記構造方法

給成員變數賦值有倆種方式: setXxx(); 構造方法 構造方法: 給物件的資料進行初始化 格式: 方法名與類名一致 無資料型別,void都沒有 無返回型別 public class ConstructionMethodDemp {