1. 程式人生 > >JAVA筆記三:繼承

JAVA筆記三:繼承

一、超類與子類

  1. 繼承格式
    public class Manager extends Emplyee{...}
  2. 呼叫同名超類方法
    super.getSalary()
  3. 子類構造器
    由於子類不能訪問超類的私有域,所以需要呼叫超類的構造器對這部分私有域初始化,如下所示。注意呼叫超類的構造器語句必須是子類構造器的第一條語句。倘若沒有顯示呼叫超類構造器,將自動呼叫超類無引數構造器(也可是是預設),如果超類沒有無引數構造器,編譯器將報錯。(很像this)
    super(name,...)
  4. 多型
    在java程式設計語言中,物件變數是多型的。一個超類物件變數可以引用子類物件,但不能通過該物件變數呼叫子類方法;子類物件變數不能引用超類物件。但存在欺騙現象:
    Manager[] managers = new Manager[10];//超類
    Employee[] staff = managers; //OK
    staff[0] = new Employee("Harry Hacker" ...);//接納
    managers[0].setBonus(1000)//會引發異常
    
  5. 類方法呼叫(x.f(args) x為C類物件)
    • 編譯器檢視物件的宣告型別和方法名。一一列舉C類物件的名為f的方法和超類中訪問屬性為public的名為f的方法。
    • 編譯器將檢視呼叫方法時提供的引數型別。
    • 如果是private方法,static方法,final方法,或者構造器,編譯器將準確知道應該呼叫哪個方法,稱為靜態繫結。
    • 當程式執行,並且採用動態繫結呼叫方法是,虛擬機器一定呼叫與X所引用物件的實際型別最合適的那個類的方法。虛擬機器會預先給每個類建立一個方法表。
  6. 阻止繼承:final類和方法
    public final class Executive extends Manager{} // 不允許被繼承

    public fianl String getName(){}//不允許被覆蓋
  7. 將一個超類的引用賦給一個子類變數,必須進行型別轉換,在轉換之前應該使用instanceof進行檢查
    boss = (Manager) staff[1];// ERROR
    if(staff[1] instanceof Manager){
    	boss = (Manager) staff[1];
    }
    
  8. 抽象類abstract,不可以有例項。但可以定義抽象類的物件變數來引用非抽象子類的物件。抽象類還可以包含具體資料和具體方法。
    public abstract class Person{}
    public abstract String getDescription();//不能有實體
  9. 受保護訪問
  • 僅對本類可見——private
  • 對所有類可見——public
  • 對本包和所有子類可見——protected
    但是Manager類中的方法只能訪問Manager物件中的hireDay域(protected)而不能訪問其他Employee物件的這個域。
  • 對本包可見——預設,不需要修飾符
    JAVA靜態方法是否可以被繼承?
    靜態屬性、靜態方法和非靜態的屬性都可以被繼承和隱藏而不能被重寫,因此不能實現多型,不能實現父類的引用可以指向不同子類的物件。

二、object:所有類的超類

  1. 如果沒有明確指出超類,object就被認為是這個類的超類,除了基本型別不是物件,其他的都是物件,包括陣列,也就是說陣列型別也拓展了超類。
  2. equals方法
  • 顯式引數明名為otherObject,稍後需要將它轉換成另一個叫做other的變數
  • 檢測this與otherObject是否引用同一個物件 if(this == otherObject) return true;
  • 檢測otherObject是否為空
  • 比較this與otherObject是否屬於同一個類if(getClass() != otherObject.getClass() return false;
    如果所有子類都具有統一的語義 if(!(otherObject instanceof ClassName)) return false;
  • 將otherObject轉換為相應的類型別變數ClassName other = (ClassName) otherObject
  • 最後比較所有需要比較的域,使用==比較基本型別,使用equals比較物件域。
    對於陣列型別的域可以使用靜態的Arrays.equals()方法。
    注:@Override 對覆蓋方法進行標記,如果沒有覆蓋父類函式,則會報錯。
  1. hashcode方法
    返回物件的雜湊碼。雜湊碼可以是任意的整數,包括整數或負數。兩個相等的物件要求返回相等的雜湊碼。
  2. toString方法
    getClass().getName()

三、泛型陣列列表

  1. ArrayList
ArrayList<Employee> staff = new ArrayList<>(); //java SE7 ,之前需要用 new ArrayList<Employee>();
ArrayList<E> ()// E型別需要是包裝型別,ie. int -> Interger
ArrayList<E>(int initialCapacity) // 與宣告initialCapacity大小陣列不一樣,size = 0;
boolean add(E obj) //永遠返回true
void add(int index, E obj)
int size()
void ensureCapacity(int capacity) //確保陣列列表在不重新分配儲存空間的情況下就能夠儲存給定數量的元素。
void trimToSize()//將陣列列表的儲存容量削減到當前尺寸。
void set(int index, E obj);
E get(int index)
E remove(int index)

四、物件包裝器與自動裝箱

  1. Integer類對應基本型別int,這些類稱為包裝器.包裝器型別類似於String,不可變。
    (Integer,Long,Float,Double,Short,Byte,Character,Void,Boolean)這些類屬於final
  2. 自動裝箱,自動拆箱(從新解綁和繫結新的值)
list.add(3)等價於 list.add(Integer.valueOf(3)
int n = list.get(i) 等價於int n = list.get(i).intValue();
Integer n = 3;
n ++;

五、列舉

public enum Size{
	SMALL("S"), MEDIUM("M")...
	private String abbreviation;
	private Size(String abbreviation) {this.abbreviation = abbreviation;}
}
API
stativ Enum valueOf(Class enumClass, String name)
String toString()
int ordinal() 返回位置,從0開始
int compareTo(E other) 如果出現在other之前,返回一個負值。

六、反射

反射機制可以用來:

  • 在執行時分析類的能力
  • 在執行時檢視物件,例如,編寫一個toString方法供所有類使用
  • 實現通用的陣列操作程式碼
  • 利用Method物件,這個物件很像C++ 中的指標
  1. Class類 Object 類中的getClass()方法將會返回一個Class型別的例項
    獲得Class類物件有三個方法
    Employee e;// ---1
    Class cl = e.getClass();
    
    String className = "java.util.Random";//---2
    Class cl = Class.forName(className);
    
    Class cl1 = Random.class;//--- 3
    Class cl2 = int.class;
    Class cl3 = Double[].class;
    cl2.newInstance(); //呼叫預設構造器,如果沒有,丟擲異常
    
    void printStackTrace() // 將Throwable物件和棧的軌跡輸出到標準錯誤流
    e. printStackTrace()
    
  2. 利用反射分析類的能力
1). java.lang.Class 1.0
Field[] getFields() 1.1 //返回包含Field陣列,包含這個類和超類的公有域
Field[] getDeclaredFields() 1.1// 包含這個類的所有域和超類的公有域
Method[] getMethods()
Method[] getDeclaredMethods()//還有介面
Constructor[] getConstructors()
Constructor[] getDeclaredConstructors()

2)java.lang.reflect.Field ,java.lang.reflect.Method, java.lang.reflect.Constructor 1.1
int getModifiers()//返回一個描述構造器,方法或域的修飾符的整型數值。
String getName()// 返回名字
Class[] getParameterTypes()// constructor, method中返回描述引數的Class陣列
Class getReturnType() // Method類中

3) java.lang.reflect.Modifier 1.1
static String toString(int modifiers)//檢測修飾符
static boolean isAbatract(int modifiers)
static boolean isFinal(int modifiers)
static boolean isInterface(int modifiers)
static boolean isNative(int modifiers)
static boolean isPrivate(int modifiers)
static boolean isProtected(int modifiers)
static boolean isPublic(int modifiers)
static boolean isStatic(int modifiers)
static boolean isStrict(int modifiers)
static boolean isSynchronized(int modifiers)
static boolean isVolatile(int modifiers)
  1. 在執行時使用反射分析物件 p201
  2. 使用反射編寫泛型陣列程式碼
  3. 通過CLASS類的getMethod方法可以實現函式指標的作用(Method.invoke)

七、繼承的設計技巧

  1. 將公共操作和域放在超類
  2. 不要使用受保護的域
  3. 使用繼承實現"is-a"關係
  4. 除非所有繼承的方法都有意義,否則不要使用繼承
  5. 在覆蓋方法時,不要改變預期的行為
  6. 使用多型,而非型別資訊
  7. 不要過多地使用反射

八、疑問

  1. 反射為什麼不匯入包也可以分析它的能力