Class對象

Class對象:類型信息在運行時是如何表示的,包含了與類有關的信息,用于創(chuàng)建類的所有的“常規(guī)”對象的,Java使用Class對象來執(zhí)行其RTTI。

類是程序的一部分,每個類都有一個Class對象,被保存在一個同名的.class文件中,為了生存這個類的對象,JVM將使用“類加載器"。

所有類的都在在對其第一次使用時,動態(tài)加載到JVM中的。當程序創(chuàng)建第一個對類的靜態(tài)成員的引用時,就會加載這個類。這個證實構(gòu)造器也是類的靜態(tài)方法,即使在構(gòu)造器之前并沒有使用static關鍵字。因此,使用new操作符創(chuàng)建類的新對象也會被當作類的靜態(tài)成員的引用。

Class的API:###

    getName():全限定的類名

    getSimpleName():不包含包名的類名

    getCanonicalName():全限定的類名

    getInterfaces():返回所有接口的Class對象

    getClassLoader():返回該類的類加載器。

    getComponentType():返回表示數(shù)組組件類型的 Class

    getSuperclass():返回表示此 Class 所表示的實體的超類的 Class。    

    isArray():判定此 Class 對象是否表示一個數(shù)組類。

Class實例對象的newInstance()方法來創(chuàng)建的類,必須帶有默認構(gòu)造器。

Class對象的應用方法:###

1.Class.forName()

2.類字面常量:類型.class

簡單,安全,因為它在編譯時就會受到檢查,不需要try語句包圍,根除了對forName()方法的調(diào)用,所以也更高效。

類字面常量不僅可以應用于普通的類,也可以應用于接口,數(shù)組以及基本數(shù)據(jù)類型。

當使用“.class”來創(chuàng)建對Class對象的引用時,不會自動地初始化該Class對象。初始化被延遲到了對靜態(tài)方法(構(gòu)造器隱式地是靜態(tài)的)或者非常數(shù)靜態(tài)域進行首次引用時才執(zhí)行。

泛化的Class引用###

Class<?>與Class等價,但優(yōu)于平凡的Class,非具體的類引用

Class<? extends Number >:任何由Number派生的類

Class<? Super FancyToy>:某個類,它是FancyToy超類

instanceof與Class的等價性###

instanceof和isInstance()生成的結(jié)果完全一樣,且保持類型的概念
Class的equals()和==也一樣,比較實際的Class對象,沒有考慮繼承

注冊工廠###

靜態(tài)初始化器只有在類首先被加載的情況下才能被調(diào)用。
  使用工廠方法設計模式,將對象的創(chuàng)建工作交給類自己去完成。工廠方法可以被多態(tài)的調(diào)用,從而創(chuàng)建適當類型的對象。

精簡版(工廠方法就是Factory接口中的create()方法):

public interface Factory<T> { T create();}

泛型參數(shù)T使得create()在每種Factory是實現(xiàn)中返回不同的類型

反射:運行時的類信息(RTTI)

編譯時,編譯器必須知道所有要通過RTTI來處理的類

反射提供了一種機制——用來檢查可用的方法,并返回方法名。
運行時獲取類的信息的另一個動機:希望提供在跨網(wǎng)絡的遠程平臺上常見和運行對象的能力,即遠程方法調(diào)用(RMI)。允許一個java程序?qū)ο蠓植嫉蕉嗯_機器上。

Class類與java.lang.reflect類庫一起對反射的概念進行支持,該類庫包含了Field、Method以及Constructor類(每個類都是先了Member接口)。這些類型的對象是由JVM在運行時創(chuàng)建的,用以表示未知類里對應的成員。

Constructor->創(chuàng)建新對象
get()和set()->讀取和修改與Field對象關聯(lián)的字段
invoke()方法->調(diào)用與Method對象關聯(lián)的方法
getField(),getMethods()和getConstructors()->返回表示字段、方法以及構(gòu)造器的對象數(shù)組

匿名對象的類信息就能在運行時被完全確定下來,而在編譯時不需要知道任何信息。
詳見JDK文檔

對RTTI來說,編譯器在編譯時打開和檢查.class文件;而對于反射機制來說,.class文件在編譯時無法獲取,所以在運行時打開和檢查.class文件。

類方法提取器###

瀏覽實現(xiàn)了類定義的源代碼或者其JDK文檔,只能找到在這個類定義中被定義和被覆蓋的方法。反射機制提供了一種方法,使我們能夠編寫自動展示完整接口的簡單工具。

package typeinfo;
import static net.mindview.util.Print.print;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.regex.Pattern;

public class ShowMethod {
    private static Pattern p = Pattern.compile("\\w+\\.");
    public static void main(String[] args) {
        try {
            Class<?> c = Class.forName("typeinfo.ShowMethod");
            Method[] methods = c.getMethods();
            Constructor[] ctors = c.getConstructors();
            for (Method method : methods) {
            print(p.matcher(method.toString()).replaceAll(""));
            }
            for (Constructor constructor : ctors) {
                print(p.matcher(constructor.toString()).replaceAll(""));
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

動態(tài)代理###

代理是基本的設計模式之一。它是你為了聽過額外或不同的操作,而插入的用來替代“實際”對象的對象。這些操作通常涉及與“實際”對象的通信,因此代理通常充當中間人的角色。

package typeinfo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface Interface{
    void doSomething();
    void somethingElse(String arg);
}

class RealObject implements Interface{
public void doSomething() {
    System.out.println("doSomething");
}

public void somethingElse(String arg) {
    System.out.println("somethingElse " +arg);
}
}

class DynamicProxyHandler implements InvocationHandler{

private Object proxied;
public DynamicProxyHandler(Object proxied) {
    this.proxied = proxied;
}

public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
    System.out.println("*** proxy: " + proxy.getClass() + 
            ", method: " + method + ", args: " + args);
    if (args != null) {
        for (Object arg : args) {
                System.out.println(" " + arg);
            }
        }
            return method.invoke(proxied, args);
        }
    }

public class SimpleDynamicProxy {
    
    public static void consumer(Interface iface){
        iface.doSomething();
        iface.somethingElse("bonobo");
    }
    public static void main(String[] args) {
        RealObject real = new RealObject();
        consumer(real);
        Interface proxy = (Interface) Proxy.newProxyInstance(
    Interface.class.getClassLoader(),
                new Class[] {Interface.class},
                new DynamicProxyHandler(real));
        consumer(proxy);
    }
}

通過調(diào)用靜態(tài)方法Proxy.newProxyInstance()可以創(chuàng)建動態(tài)代理,這個方法需要一個類加載器(通常從已經(jīng)加載的對象中獲取其類加載器),一個希望該代理實現(xiàn)的接口列表(不是類或抽象類),以及InvocationHandler接口的一個實現(xiàn)。

動態(tài)代理可以將所有調(diào)用重定向到調(diào)用處理器,因此通常會向調(diào)用處理器的構(gòu)造器傳遞給一個“實際”對象的引用,從而使得調(diào)用處理器在執(zhí)行其中介任務時,可以將請求轉(zhuǎn)發(fā)。

在invoke()內(nèi)部,在代理上調(diào)用方法時需要格外小心,因為對接口的調(diào)用將被重定向為對代理的調(diào)用。
使用Method.invoke()將請求轉(zhuǎn)發(fā)給被代理對象,并傳入必須的參數(shù)。
注釋:內(nèi)容來自《Java 編程思想》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 1 Class對象 理解RTTI在Java中的工作原理,首先需要知道類型信息在運行時是如何表示的,這是由Class...
    luoxn28閱讀 529評論 0 0
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • Class對象是存放在堆區(qū)的,不是方法區(qū),這點很多人容易犯錯。類的元數(shù)據(jù)(元數(shù)據(jù)并不是類的Class對象。Clas...
    值得一看的喵閱讀 5,826評論 0 2
  • 感恩父母早上一早過來整理幫光寶起床,感恩阿姨一早打掃房間讓家中整潔,干凈,感恩黃建教我太極,種下健康的種子,感恩五...
    日精進_a07d閱讀 166評論 0 4
  • 有一場說走就走的旅行。 然而人生的話還是不太夠充實。 20歲來臨,有人說20歲一過30歲40歲都近了快了,一晃一生...
    亦戈夢閱讀 360評論 0 0

友情鏈接更多精彩內(nèi)容