看Java編程思想,頭暈,寫下點自己的理解
1 首先,參考文獻
- Java編程思想,14.2章節
- https://www.cnblogs.com/vamei/archive/2013/04/14/3013985.html (作者:Vamei )引用了這位博主的部分代碼
- http://www.matools.com/api/java8 Java8API
2 RTTI是什麼?
RTTI, Run-Time Type Identification,運行時類型信息。這個東西可以使你在程序運行時發現和使用類型信息(類名,類所在包,類方法…)
3 RTTI咋實現的?–Class對象
引用Vamei博主文章中的一句話,個人覺得很有道理。
Class類是"類的類"(class of classes)。如果說類是對象的抽象和集合的話,那麼Class類就是對類的抽象和集合。
這裏聽起來是有點繞哈,我們常說,Java裏面“萬物皆是類”,所有的東西都可以用類表示,這是面向對象中“抽象”的概念。那麼再用一個東西去描述一下所有的類,這就是Class類(這裏的Class類可以換一個詞描述,比如XXX類,這個類專門用來描述類的信息)
再舉個例子,在理解類對象之前,先說我們熟悉的對象之間的區別:
小敏和小嫺都是Human對象,她們的區別在於,各自有不同的名字,性別,愛好
然後說說類之間的區別
Human和Animal都是類,它們的區別在於有不同的方法,不同的屬性。類對象( Class 對象),就是用於描述這種類,都有什麼屬性,什麼方法的
----How2Java
4 Class對象實現的3種方法
4.1 通過一個已經存在的對象,調用.getClass()方法
4.2 Class.forName(“類全限定名”)
4.3 類字面常量 “xx.class”
舉個例子,上代碼
public class TestDemo
{
public static void main(String[] args) throws ClassNotFoundException {
Human aPerson = new Human();
Class c1 = aPerson.getClass();
System.out.println(c1.getName());
Class c2 = Class.forName("Human");
System.out.println(c2.getName());
Class c3 = Woman.class;
System.out.println(c3.getName());
}
}
class Human
{
/**
* accessor
*/
public int getHeight()
{
return this.height;
}
/**
* mutator
*/
public void growHeight(int h)
{
this.height = this.height + h;
}
private int height;
}
class Woman extends Human
{
/**
* new method
*/
public Human giveBirth()
{
System.out.println("Give birth");
return (new Human());
}
}
結果:
5 Class.forName 和類字面常量的區別
- Class.forName() 方法返回Class對象的引用,其作用是如果該類沒有被加載到JVM中,就將其加載,static初始化就是在類加載的時候執行的,執行後會自動執行類的初始化。
- “xx.class”創建Class對象引用,執行後不會執行類的初始化(初始化被延遲到了對靜態域的首次訪問)
- “xx.class”更安全,因爲它在編譯時候就會受到檢察。forName()是運行時檢查的,所有一般要套在try-catch語句中。
所有的類都是在對其第一次使用時,動態加載到JVM中的,當程序創建第一個對類的靜態成員引用時候,就會加載這個類。(new 操作符也會被當做對類靜態成員的引用)
6 Java中多態的本質
舉個多態的例子,animal是父類,有一個sing方法。cat是子類,繼承於animal,並且重寫了sing方法。如下例子
class Animal{
public void sing(){
System.out.println("animal sing");
}
}
class Cat extends Animal{
public void sing(){
System.out.println("cat sing");
}
}
當我們使用animal類指向一個cat對象,然後通過animal 去調用sing() 方法時,就像下面這樣
Animal animal = new Cat();
animal.sing()
實際的輸出應該是
cat sing
這是一個很簡單的多態的例子。那麼JVM是如何知道,anima實際指向的是一個cat對象的?答案就是RTTI。也就是剛剛說的class對象。不管cat向上轉型多少次,它的class對象(getClass)永遠是是cat類。所以,我們調用sing() 方法的時候,JVM會去調用Cat的sing()方法。這就是多態的原理。
7 Class對象常用的API
getFields() //返回所有的public數據成員
getMethods() //返回所有的public方法
getName() //返回類的名字
getPackage() //返回類所在的包
newInstance() //創建由此 類對象表示的類的新實例。
getSuperclass() // 返回父類的class對象
特別想說明下**newInstance()**這個函數,它在官方文檔上的說明是,
如果初始化時候,沒有使用泛型的話,是會報錯的。
加上泛型之後就可以正常使用了
關於爲什麼一般都要要加上泛型,官方的說法是,如果不指定泛型的話,那麼一個class引用可以多次指向不同的Class對象(也就是說可以指向Human可以指向Woman),like this
這樣有時候可能引起混淆吧~~