最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java中的反射及其優(yōu)點(diǎn)說明

 更新時(shí)間:2022年05月11日 14:34:03   作者:TimeTDIT  
這篇文章主要介紹了java中的反射及其優(yōu)點(diǎn)說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

java反射及優(yōu)點(diǎn)

反射是java的一大特性,而且是有些框架實(shí)現(xiàn)了IoC/DI的原理,本文就來探討下java中的反射及其優(yōu)點(diǎn)。

首先是普通的java靜態(tài)類加載,java靜態(tài)類是通過new實(shí)現(xiàn)的,在編譯時(shí)刻就要加載所有可能用到的類,這樣實(shí)際上存在一些缺點(diǎn)的,比如只要有一個(gè)類沒有找到或者出現(xiàn)重大的問題編譯便不會(huì)通過,導(dǎo)致其他存在的類也無法使用。另一方面,如果要加載其他的類就要重新進(jìn)行編譯,有的時(shí)候是非常不方便的。下面就引入反射機(jī)制來動(dòng)態(tài)加載類來解決這個(gè)問題。

首先創(chuàng)建一個(gè)ClassInterface接口,放在com.classTest包下:

package com.classTest;?
public interface ClassInterface {
? ? public void start(); ? ? ? //接口約定start()方法
}

然后分別使用Class1Impl和Class2Impl類去實(shí)現(xiàn)這個(gè)接口,也放在com.classTest包下:

package com.classTest;?
public class Class1Impl implements ClassInterface {
?
? ? @Override
? ? public void start() {
? ? ? ? // TODO Auto-generated method stub
? ? ? ? System.out.println("This is Class1Impl"); ? //實(shí)現(xiàn)start()
? ? }
}
package com.classTest;?
public class Class2Impl implements ClassInterface {
?
? ? @Override
? ? public void start() {
? ? ? ? // TODO Auto-generated method stub
? ? ? ? System.out.println("This is Class2Impl"); ? //實(shí)現(xiàn)start()
? ? }?
}

下面先用正常的類加載來說明正常類加載的缺點(diǎn):

package com.test;?
import java.util.Scanner;?
import com.classTest.ClassInterface;
?
public class LoadClassTest {
? ? ClassInterface c1 = new Class1Impl();
? ? ClassInterface c2 = new Class2Impl();
? ? c1.start();
? ? c2.start();
}

上面是正常的new方法生成的對象,然后調(diào)用接口里的方法,但是一旦Class1Impl類或者Class2Impl類沒有,那有的哪個(gè)類也就無法使用,而且想要使用新的ClassInterface接口下的方法還是需要重新寫類,重新寫測試方法,重新生成測試對象,重新編譯...

下面介紹利用反射機(jī)制動(dòng)態(tài)加載類來解決這個(gè)問題:

package com.test;?
import java.util.Scanner;?
import com.classTest.ClassInterface;
?
public class LoadClassTest {
? ? public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
? ? ? ? //new 創(chuàng)建對象是靜態(tài)加載類,在編譯時(shí)刻就需要加載所有可能用到的類
? ? ? ? //動(dòng)態(tài)記載類可以解決這個(gè)問題
? ? ? ? Scanner sc = new Scanner(System.in);
? ? ? ? String className = sc.nextLine();
? ? ? ? //動(dòng)態(tài)加載類,在運(yùn)行的時(shí)刻進(jìn)行加載
? ? ? ? //使用類類型(class type) 通過Class這個(gè)類的forName(className)方法動(dòng)態(tài)創(chuàng)建類對象
? ? ? ? Class c = Class.forName(className);
? ? ? ? //通過類類型 用newInstance()方法創(chuàng)建該類對象
? ? ? ? ClassInterface ci = (ClassInterface) c.newInstance();
? ? ? ? ci.start();//動(dòng)態(tài)加載類 調(diào)用其方法
? ? }
}

有沒有看出這其中的差異,想要加載其他類只需要輸入另外的類名即可(這里的類名是包含包的),forName()方法可以通過類名動(dòng)態(tài)創(chuàng)建類類型的對象,然后用類類型的對象的newInstance()方法創(chuàng)建該類類型對象(也就是一個(gè)類)的對象(調(diào)用newInstance()方法的類類型對象需要進(jìn)行轉(zhuǎn)化),之后就可以用生成對象調(diào)用接口下的方法了。

那這時(shí)候可能就會(huì)有人問了,要是在我們不知道接口名稱為ClassInterface的情況下,我們該如何訪問className這個(gè)類類型生成的c這個(gè)類對象下面的方法呢?我們來實(shí)現(xiàn)一下:

Class c = Class.forName("com.classTest.Foo");//創(chuàng)建一個(gè)類對象c
Method m1 = c.getMethod("fun1", int.class,int.class);//通過getMethod方法獲取c的方法,第一個(gè)參數(shù)表示想要獲取的方法名稱fun1,之后的參數(shù)列表表示fun1這個(gè)函數(shù)的所有參數(shù)的類類型。
Object o = m1.invoke(foo1,new Object[]{10,20} );//通過invoke方法來調(diào)用我們前面通過getMethod()獲得的方法,第一個(gè)參數(shù)表示執(zhí)行我們所獲得方法的對象,第二個(gè)參數(shù)表示我們所獲取方法的參數(shù),這里是兩個(gè)int類型。如果沒有返回值返回null,有返回值則返回具體的返回值,這里將返回結(jié)果保存在o對象里。

這樣的優(yōu)點(diǎn)是顯而易見的,類無需在編譯前全部加載,而且修改接口實(shí)現(xiàn)類的時(shí)候也不用重新編譯。

這只是反射的一小部分,但是也是很重要的一部分,也是Spring中IoC/DI的實(shí)現(xiàn)基礎(chǔ)。

(另外告訴大家一個(gè)小tip:所謂的泛型數(shù)據(jù)容器的數(shù)據(jù)類型(也就是HashMap<String,String>中的<String,String>)不能寫入其他數(shù)據(jù)類型實(shí)際上只是存在于編譯層面的,是為了防止開發(fā)者往里面誤寫入自己不想寫入的東西,然而通過泛型可以跳過編譯層面實(shí)現(xiàn)往這個(gè)泛型數(shù)據(jù)容器里存入和這個(gè)泛型數(shù)據(jù)容器數(shù)據(jù)類型不一樣的數(shù)據(jù),雖然這樣之后用foreach遍歷就會(huì)報(bào)錯(cuò)...)

java反射機(jī)制(Reflection)

1.什么是反射?反射有什么作用?

能夠分析類能力的程序稱為反射。反射機(jī)制允許程序在運(yùn)行狀態(tài)借助Reflection API取得任何類的內(nèi)部信息,并能直接操作任意對象的內(nèi)部屬性及方法。

反射機(jī)制的作用

  • 在運(yùn)行時(shí)判斷任意一個(gè)對象所屬的類
  • 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對象
  • 在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法
  • 在運(yùn)行時(shí)調(diào)用任意一個(gè)對象的成員變量和方法
  • 在運(yùn)行時(shí)獲取泛型信息
  • 在運(yùn)行時(shí)處理注解
  • 生成 動(dòng)態(tài)代理

2.反射相關(guān)的主要API

  • java.lang.Class:代表一個(gè)類
  • java.lang.reflect.Method:代表類的方法
  • java.lang.reflect. Field:代表類的成員變量
  • java.lang.reflect.Constructor:代表類的構(gòu)造器

3.什么是Class類

對Class類的深入理解

  • Class本身也是一個(gè)類
  • Class 對象只能由系統(tǒng)建立對象(Class 對象是在加載類時(shí)由Java 虛擬機(jī)以及通過調(diào)用類加載器中的 defineClass 方法自動(dòng)構(gòu)造的)
  • 一個(gè)類在 JVM 中只會(huì)有一個(gè)Class實(shí)例
  • 一個(gè)Class對象對應(yīng)的是一個(gè)加載到JVM中的一個(gè).class文件
  • 每個(gè)類的實(shí)例都會(huì)記得自己是由哪個(gè) Class 實(shí)例所生成
  • 通過Class可以完整地得到一個(gè)類中的完整結(jié)構(gòu)

類的加載過程:

程序經(jīng)過javac.exe命令以后,會(huì)生成一 個(gè)或多個(gè)字節(jié)碼文件(.class結(jié)尾)。

接著我們使用java.exe命令對某個(gè)字節(jié)碼文件進(jìn)行解釋運(yùn)行。相當(dāng)于將某個(gè)字節(jié)碼文件加載到內(nèi)存中。此過程就稱為類的加載。加載到內(nèi)存中的類,我們就稱為運(yùn)行時(shí)類,此運(yùn)行時(shí)類,就作為CLass的一個(gè)實(shí)例。

java.Lang.Class實(shí)例的獲?。ㄋ姆N方式) 

package package03;
import org.junit.Test;
public class ReflectiveTeat01 {
    //獲取 Class 類的實(shí)例
    @Test
    public void test01() throws Exception {
        //方式一:通過調(diào)用運(yùn)行時(shí)類得屬性:.class
        Class clazz1 = Person.class;
        System.out.println(clazz1);//class package03.Person
        //方式二:通過運(yùn)行時(shí)類的對象,調(diào)用 getClass() 方法
        Person p1 = new Person();
        Class clazz2 = p1.getClass();
        System.out.println(clazz2);//class package03.Person
        //方式三:調(diào)用 Class 的靜態(tài)方法:forName(String classPath)
        Class clazz3 = Class.forName("package03.Person");
        System.out.println(clazz3);//class package03.Person
        //方法四:使用類的加載器:ClassLoader
        ClassLoader classLoader = ReflectiveTeat01.class.getClassLoader();
        Class clazz4 = classLoader. loadClass("package03.Person") ;
        System. out . println(clazz4);//class package03.Person
    }
}

4.調(diào)用運(yùn)行時(shí)類的指定結(jié)構(gòu)

如何操作運(yùn)行時(shí)類中指定的屬性

@Test
    public void testField() throws Exception {
        Class clazz = Person.class;
        //創(chuàng)建運(yùn)行時(shí)類的對象 P
        Person p = (Person) clazz.newInstance();
        //獲取指定的屬性
        Field fieldName = clazz.getDeclaredField("id");
        //fieldName 要操作的屬性名賦值給 fieldName 變量名
        
        //保證當(dāng)前屬性是可訪問的
        fieldName .setAccessible(true);
        /*
        設(shè)置當(dāng)前屬性的值
        set():參數(shù)1:指明設(shè)置哪個(gè)對象的屬性
              參數(shù)2:將此屬性值設(shè)置為多少
         */
        fieldName.set(p,1001);
        /*
        獲取當(dāng)前屬性的值
        get():參數(shù)1:獲取哪個(gè)對象的當(dāng)前屬性值
         */
        int intName = (int) fieldName.get(p);
        System.out.println(intName );
    }

操作運(yùn)行時(shí)類的方法

已調(diào)用 show 方法例子:該方法有 注解,參數(shù),返回值,權(quán)限?。╬rivate)

@MyAnonotation//自定義注解
? ? private String show(String nation) {
? ? ? ? System.out.println("我的國籍是:" + nation);
? ? ? ? return nation;
? ? }
 @Test
    public void testMethod() throws Exception {
        Class clazz = Person.class;
        //創(chuàng)建運(yùn)行時(shí)類對象
        Person p = (Person) clazz.newInstance();
       /* 1.獲取指定的某個(gè)方法
       getDeclaredMethod():參數(shù)1:指明獲取的方法的名稱
                           參數(shù)2:指明獲取的方法的形參列表
       * */
        Method show = clazz.getDeclaredMethod("show", String.class);
        //2.保證當(dāng)前方法時(shí)可訪問的
        show.setAccessible(true);
        /*
        3.調(diào)用方法的invoke():參數(shù)1:方法的調(diào)用者
                            參數(shù)2:給方法形參賦值的實(shí)參
          invoke()方法的返回值即為對應(yīng)類中調(diào)用的方法的返回值
         */
        show.invoke(p, "CHN");
        
        //調(diào)用靜態(tài)方法時(shí):
        //private static void showDesc()
        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        //如果調(diào)用的運(yùn)行時(shí)類中的方法沒有返回值,則 invoke() 返回 null
        Object invoke = showDesc.invoke(Person.class);
        System.out.println(invoke);
    }

上面代碼用到的 Person 類

public class Person {
    private String name;
    private int age;
    public int id;
    //空參構(gòu)造器
    public Person() {
    }
    //全參構(gòu)造器
    public Person(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.id = id;
    }
    @MyAnonotation
    private String show(String nation) {
        System.out.println("我的國籍是:" + nation);
        return nation;
    }
    //靜態(tài)方法
    private static void showDesc(){
        System.out.println("我是一個(gè)可愛的人");
    }
    // get、set 方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論

湘潭县| 巴林右旗| 饶阳县| 八宿县| 繁峙县| 云和县| 湘阴县| 扶沟县| 临沭县| 微山县| 全椒县| 万盛区| 屯昌县| 枝江市| 龙泉市| 隆尧县| 保山市| 普安县| 汶川县| 永顺县| 枣庄市| 常山县| 松溪县| 阿克苏市| 会昌县| 上高县| 葫芦岛市| 华安县| 隆林| 静宁县| 定远县| 陵水| 福泉市| 大宁县| 潮州市| 山东| 嘉禾县| 石柱| 龙口市| 陆良县| 孙吴县|