【Java Class對象】RTTI 和Class對象

看Java編程思想,頭暈,寫下點自己的理解

1 首先,參考文獻

  1. Java編程思想,14.2章節
  2. https://www.cnblogs.com/vamei/archive/2013/04/14/3013985.html (作者:Vamei )引用了這位博主的部分代碼
  3. 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 和類字面常量的區別

  1. Class.forName() 方法返回Class對象的引用,其作用是如果該類沒有被加載到JVM中,就將其加載,static初始化就是在類加載的時候執行的,執行後會自動執行類的初始化
  2. “xx.class”創建Class對象引用,執行後不會執行類的初始化(初始化被延遲到了對靜態域的首次訪問)
  3. “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
在這裏插入圖片描述
這樣有時候可能引起混淆吧~~

8 Ending 新手上路,如有謬誤,歡迎指出~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章