1. 程式人生 > >[隨筆][Java][讀書筆記][thinking in java][第十四章 類型信息]

[隨筆][Java][讀書筆記][thinking in java][第十四章 類型信息]

found 構造 att main 數組 test 第一個 eating urn

  • 主要理解如何在運行時獲取類型信息。主要有兩種方式:一是RTTI,假定我們在編譯時已經知道了所有的類型;二是反射機制,允許在運行時發現和使用類的信息。

14.1 為什麽需要RTTI

  • 一個多態的例子
import java.util.*;

abstract class Shape {
    void draw() { System.out.println(this + ".draw()"); }
    abstract public String toString();
}

class Circle extends Shape {
    public String toString() { return "Circle"; }
}

class Square extends Shape {
    public String toString() { return "Square"; }
}


class Trianle extends Shape {
    public String toString() { return "Trianle"; }
}

public class Shapes{
    public static void main(String[] args) {
        List<Shape> shapeList = Arrays.asList(new Circle(), new Square(), new Trianle());
        for(Shape shape : shapeList) {
            shape.draw();
        }
    }
}
  • 當把創建的對象放入到List
  • 當從數組中把元素取出來的時候,會自動的將對象轉型回Shape。這是RTTI在java中最基本的使用形式。java中的所有的類型轉化都是在運行時進行正確性檢查
  • List容器在存儲元素的時候,將所有的元素當作Object看待,在取出的時候向下轉型成為對應的類型。但是這種轉型並不徹底,並不能向下轉型成Circle等類型,因為在容器定義的時候,只知道List中存儲的是Shape類型。

14.2 Class對象

  • Class對象---一種特殊的對象,用於在運行時表示類型信息,包含了與類有關的信息。
  • 每個類都有一個Class對象,每當編寫並編譯一個新類,就會產生一個Class對象(被保存在一個同名的.class文件中)
    。使用new操作符創建類的新對象也會被當作對類的靜態成員的引用。
  • 類加載器首先檢查這個類的Class對象是否已經加載,按照類名查找.class文件,一旦某個類的Class對象文件被載入到內存,它就被用來創建這個類的所有對象。
class Candy {
    static { System.out.println("loading candy"); }
}

class Gum {
    static { System.out.println("loading gum"); }
}

class Cookie {
    static { System.out.println("loading Cookie"); }
}

public class SweetShop {
    public static void main(String[] args) {
        System.out.println("inside main");
        new Candy();
        System.out.println("after creating candy");
        try {
            Class.forName("Gum");
        } catch(ClassNotFoundException e) {
            System.out.println("not fine gum");
        }
    }
}

//結果
![](https://images2018.cnblogs.com/blog/1034390/201808/1034390-20180831152652459-1698512495.png)
  • 類中的static子句在類第一個次被加載時執行。
  • Class.forName();這個是Class類的一個static方法,forName()可以獲取對應的Class對象的引用,返回值是一個Class對象的引用。
  • 只要想在運行時獲得對象的類型信息,就必須首先獲得對應的Class對象的引用。或者在某個具體的對象上調用getClass()方法得到對應的Class對象的引用,這個方法屬於Object的一部分。
  • 一個Class中各種方法的例子
interface HasBatteries {}
interface Waterproff {}
interface Shoots {}

class Toy {
    Toy() {}
    Toy(int i) {}
}

class FancyToy extends Toy implements HasBatteries, Waterproff, Shoots{
    FancyToy() { super(1); };
}

public class ToyTest {
    static void printInfo(Class cc) {
        System.out.println("Class name: " + cc.getName() + " is interface? " + cc.isInterface());
        System.out.println("Simple name: " + cc.getSimpleName()); 
        System.out.println("Canonical name: " + cc.getCanonicalName());
    }

    public static void main(String[] args) {
        Class c = null;
        try {
            c = Class.forName("FancyToy");
        } catch (ClassNotFoundException e) {
            System.out.println("not find FancyToy");
            System.exit(1);
        }
        printInfo(c);
        for(Class face : c.getInterfaces()) {
            printInfo(face);
        }
        Class up = c.getSuperclass();
        Object obj = null;
        try {
            obj = up.newInstance();
        } catch(InstantiationException e) {
            System.out.println("not instanceiate");
            System.exit(1);
        } catch (IllegalAccessException e) {
            System.out.println("not access");
            System.exit(1);
            
        }
        printInfo(obj.getClass());
    }
}

//輸出
D:\workspace\java>java ToyTest
Class name: FancyToy is interface? false
Simple name: FancyToy
Canonical name: FancyToy
Class name: HasBatteries is interface? true
Simple name: HasBatteries
Canonical name: HasBatteries
Class name: Waterproff is interface? true
Simple name: Waterproff
Canonical name: Waterproff
Class name: Shoots is interface? true
Simple name: Shoots
Canonical name: Shoots
Class name: Toy is interface? false
Simple name: Toy
Canonical name: Toy

D:\workspace\java>
![](https://images2018.cnblogs.com/blog/1034390/201808/1034390-20180831162939449-263513627.png)
  • 傳遞給forName()的字符串中,必須使用權限頂名(包含包名)。
  • Class.getInterfaces()方法返回的是Class對象,表示對象中所包含的接口。
  • newInstance()方法實現“虛擬構造器”的一種途徑,我不知道確切的類型,無論無何要正確的創建你自己?????
  • Class的對象代表的是一個類,可以使用newInstance()方法創建一個對象。

  • 類字面量:FancyToy.class;生成對Class對象的引用。在編譯的時候受到檢查,不需要放置到try語句中。如果使用forName(),必須放到try語句中。否則報錯
D:\workspace\java>javac ToyTest.java
ToyTest.java:24: 錯誤: 未報告的異常錯誤ClassNotFoundException; 必須對其進行捕獲或聲明以便拋出
            c = Class.forName("FancyToy");
                             ^
1 個錯誤

D:\workspace\java>
  • 使用".class"來創建對Class對象的引用時,不會自動的初始化該Class對象,為了使用類需要包含三個步驟:加載,鏈接,初始化。

[隨筆][Java][讀書筆記][thinking in java][第十四章 類型信息]