亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

胖哥說反射 上卷

hedzr / 1388人閱讀

摘要:可以通過提供的方法,獲取對象,具體如下方法返回值方法名稱方法說明返回一個(gè)指定參數(shù)的對象,該對象反映此對象所表示的類或接口的指定已聲明方法。

我來學(xué)習(xí)反射 1.為什么我們要學(xué)習(xí)反射?

通過反射機(jī)制可以獲取到一個(gè)類的完整信息,例如:所有(包含private修飾)屬性和方法,包信息等。

換句話說,Class本身表示一個(gè)類的本身,通過Class可以完整獲取一個(gè)類中的完整結(jié)構(gòu),包含此類中的方法定義,屬性定義等。

反射就是把Java類中的各種成分映射成一個(gè)個(gè)的Java對象

例如:一個(gè)類有:成員變量、方法、構(gòu)造方法、包等等信息,利用反射技術(shù)可以對一個(gè)類進(jìn)行解剖,把個(gè)個(gè)組成部分映射成一個(gè)個(gè)對象。
2.反射的核心是什么?

我個(gè)人認(rèn)為:一切的操作都是講使用Object完成,類或者數(shù)組的引用是可以用Object進(jìn)行接收。

也就是我們之前說Java中的我認(rèn)為很重要的多態(tài),對象的多態(tài):Object object= 任何引用類型的實(shí)例對象

3.類的加載過程

類的正常加載過程:反射的原理在與Class對象

Class對象的由來是將class文件讀入內(nèi)存,并為之創(chuàng)建一個(gè)Class對象,那么Class對象在反射中起到什么作用?

我們用圖片已經(jīng)說明了很清楚了,我們在來看一下官方的解釋

For every type of object, the Java virtual machine instantiates an immutable instance of java.lang.Class which provides methods to examine the runtime properties of the object including its members and type information. Class also provides the ability to create new classes and objects. Most importantly, it is the entry point for all of the Reflection APIs.

對于每一種類,Java虛擬機(jī)都會初始化出一個(gè)Class類型的實(shí)例,每當(dāng)我們編寫并且編譯一個(gè)新創(chuàng)建的類就會產(chǎn)生一個(gè)對應(yīng)Class對象,并且這個(gè)Class對象會被保存在同名.class文件里。當(dāng)我們new一個(gè)新對象或者引用靜態(tài)成員變量時(shí),Java虛擬機(jī)(JVM)中的類加載器系統(tǒng)會將對應(yīng)Class對象加載到JVM中,然后JVM再根據(jù)這個(gè)類型信息相關(guān)的Class對象創(chuàng)建我們需要實(shí)例對象或者提供靜態(tài)變量的引用值。

如上圖所示,比如創(chuàng)建編譯一個(gè)Student類,那么,JVM就會創(chuàng)建一個(gè)Student對應(yīng)Class類的Class實(shí)例,該Class實(shí)例保存了Student類相關(guān)的類型信息,包括屬性,方法,構(gòu)造方法等等,通過這個(gè)Class實(shí)例可以在運(yùn)行時(shí)訪問Student對象的屬性和方法等。另外通過Class類還可以創(chuàng)建出一個(gè)新的Student對象。這就是反射能夠?qū)崿F(xiàn)的原因,可以說Class是反射操作的基礎(chǔ)。

需要特別注意的是,每個(gè)class(注意class是小寫,代表普通類)類,無論創(chuàng)建多少個(gè)實(shí)例對象,在JVM中都對應(yīng)同一個(gè)Class對象。

4.Class API簡要說明

跟我們之前學(xué)習(xí)查看Math、String類一樣的過程

Class 類的實(shí)例表示正在運(yùn)行的 Java 應(yīng)用程序中的類和接口。也就是JVM中有N多的實(shí)例每個(gè)類都有該Class對象。(包括基本數(shù)據(jù)類型)

Class 沒有公共構(gòu)造方法。Class 對象是在加載類時(shí)由 Java 虛擬機(jī)以及通過調(diào)用類加載器中的defineClass 方法自動(dòng)構(gòu)造的。也就是這不需要我們自己去處理創(chuàng)建,JVM已經(jīng)幫我們創(chuàng)建好了。

沒有公共的構(gòu)造方法,方法共有64個(gè)太多了。下面用到哪個(gè)就詳解哪個(gè)吧

5.反射的使用

Java 提供反射機(jī)制,依賴于 Class 類和 java.lang.reflect 類庫。其主要的類如下:

Class:表示類或者接口

Field:表示類中的成員變量

Method:表示類中的方法

Constructor:表示類的構(gòu)造方法

Array:該類提供了動(dòng)態(tài)創(chuàng)建數(shù)組和訪問數(shù)組元素的靜態(tài)方法

先自己設(shè)置一個(gè)Student類來完成對應(yīng)的測試,代碼如下:

package com.pangsir.model;

public class Student {
    public int no;
    public String sex;

    private String name;
    private int age;
    
    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;
    }

    /*
     * 構(gòu)造方法
     */
    
   Student(String str){  
       System.out.println("(默認(rèn))的構(gòu)造方法 s = " + str);  
   }  
     
   //無參構(gòu)造方法  
   public Student(){  
       System.out.println("調(diào)用了公有、無參構(gòu)造方法執(zhí)行了。。。");  
   }  
     
   //有一個(gè)參數(shù)的構(gòu)造方法  
   protected Student(char name){  
       System.out.println("姓名:" + name);  
   }  
     
   //有多個(gè)參數(shù)的構(gòu)造方法  
   public Student(String name ,int age){  
       System.out.println("姓名:"+name+"年齡:"+ age);//這的執(zhí)行效率有問題,以后解決。  
   }  
     
   //私有構(gòu)造方法  
   private Student(int age){  
       System.out.println("私有的構(gòu)造方法   年齡:"+ age);  
   }
    
}
5.1 獲取Class對象的三種方式

說Class是反射能夠?qū)崿F(xiàn)的基礎(chǔ)的另一個(gè)原因是:Java反射包java.lang.reflect中的所有類都沒有public構(gòu)造方法,要想獲得這些類實(shí)例,只能通過Class類獲取。所以說如果想使用反射,必須得獲得Class對象。

/*
 * Constructor. Only the Java Virtual Machine creates Class
 * objects.
 */
private Class() {}

Object.getClass() 方法(對象.getClass())

如果我們有一個(gè)類的對象,那么我們可以通過 Object.getClass 方法獲得該類的 Class 對象。

// String 對象的 getClass 方法
Class clazz1 = "hello".getClass();
// 數(shù)組對象的 getClass 方法
Class clazz2 = (new byte[1024]).getClass();
System.out.println(class2) // 會輸出 [B, [ 代表是數(shù)組, B 代表是 byte。即 byte 數(shù)組的類類型

然而對于基本類型無法使用這種方法:

boolean b;
Class c = b.getClass();   // compile-time error

class 語法

任何數(shù)據(jù)類型(包括基本數(shù)據(jù)類型)都有一個(gè)“靜態(tài)”的class屬性,若我們知道要獲取的類類型的名稱時(shí),我們可以使用 class 語法獲取該類類型的對象

// 類
Class clazz = Integer.class;
// 數(shù)組
Class clazz2 = int [][].class;

包裝類的 TYPE 靜態(tài)屬性

對于基本類型和 void 都有對應(yīng)的包裝類。在包裝類中有一個(gè)靜態(tài)屬性 TYPE,保存了該來的類類型。以 Integer 類為例,其源碼中定義了如下的靜態(tài)屬性:

@SuppressWarnings("unchecked")
public static final Class TYPE = (Class) Class.getPrimitiveClass("int");

生成 Class 類實(shí)例的方法:

Class clazz1 = Integer.TYPE;
Class clazz2 = Void.TYPE;

Class.forName() 方法

通過Class類的靜態(tài)方法:forName(String className)(常用)

可以通過 Class 的 forName 方法獲取 Class 實(shí)例,其中類的名稱要寫類的完整路徑。

該方法只能用于獲取引用類型的類類型對象。

// 這種方式會使用當(dāng)前的類的加載器加載,并且會將 Class 類實(shí)例初始化
Class clazz = Class.forName("java.lang.String");
// 上面的調(diào)用方式等價(jià)于
Class clazz = Class.forName("java.lang.String", true, currentLoader);

對于數(shù)組比較特殊:

Class cDoubleArray = Class.forName("[D");    //相當(dāng)于double[].class

Class cStringArray = Class.forName("[[Ljava.lang.String;");   //相當(dāng)于String[][].class

使用該方法可能會拋出 ClassNotFoundException 異常,這個(gè)異常發(fā)生在類的加載階段,原因如下:

類加載器在類路徑中沒有找到該類(檢查:查看所在加載的類以及其所依賴的包是否在類路徑下)

該類已經(jīng)被某個(gè)類加載器加載到 JVM 內(nèi)存中,另外一個(gè)類加載器又嘗試從同一個(gè)包中加載

5.2 Student類獲取Class
package com.pangsir;

import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        Student student = new Student();
        
        /*
         * JAVA反射--獲取Class對象的三種方式
         */
        
        // 通過對象名.getClass()方法獲取
        Class stuClass = student.getClass();
        System.out.println("stuClass is "+stuClass.getName());        
        
        // 通過類名.class方式獲得
        Class stuClass1 = Student.class;
        System.out.println("stuClass1 is "+stuClass1.getName());
        System.out.println(stuClass == stuClass1);
        
        // 通過Class.forName()方法獲得
        Class stuClass2 = Class.forName("com.pangsir.model.Student");
        System.out.println("stuClass2 is "+stuClass2);
        System.out.println(stuClass1 == stuClass2);
    }
}

Output:
stuClass is com.pangsir.model.Student
stuClass1 is com.pangsir.model.Student
true
stuClass2 is class com.pangsir.model.Student
true
代碼說明:在運(yùn)行期間,一個(gè)類,只有一個(gè)Class對象產(chǎn)生。三種方式常用第三種,第一種對象都有了還要反射干什么。第二種需要導(dǎo)入類的包,依賴太強(qiáng),不導(dǎo)包就拋編譯錯(cuò)誤。一般都選第三種,一個(gè)字符串可以傳入也可寫在配置文件中等多種方法。
5.3 Member & AccessibleObject

在講 Field、Method、Constructor 之前,先說說 Member 和 AccessibleObject。Member 是一個(gè)接口,表示 Class 的成員,前面的三個(gè)類都是其實(shí)現(xiàn)類。
AccessibleObject 是 Field、Method、Constructor 三個(gè)類共同繼承的父類,它提供了將反射的對象標(biāo)記為在使用時(shí)取消默認(rèn) Java 語言訪問控制檢查的能力。通過 setAccessible 方法可以忽略訪問級別,從而訪問對應(yīng)的內(nèi)容。并且 AccessibleObject 實(shí)現(xiàn)了 AnnotatedElement 接口,提供了與獲取注解相關(guān)的能力。

5.4 獲取構(gòu)造方法

Constructor 提供了有關(guān)類的構(gòu)造方法的信息,以及對它的動(dòng)態(tài)訪問的能力。

可以通過 Class 提供的方法,獲取 Constructor 對象,具體如下:

方法返回值 方法名稱 方法說明
Constructor getConstructor(Class... parameterTypes) 返回指定參數(shù)類型、具有public訪問權(quán)限的構(gòu)造函數(shù)對象
Constructor[] getConstructors() 返回所有具有public訪問權(quán)限的構(gòu)造函數(shù)的Constructor對象數(shù)組
Constructor getDeclaredConstructor(Class... parameterTypes) 返回指定參數(shù)類型、所有聲明的(包括private)構(gòu)造函數(shù)對象
Constructor[] getDeclaredConstructor() 返回所有聲明的(包括private)構(gòu)造函數(shù)對象
package com.pangsir.test;

import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {

        // 通過Class.forName()方法獲得Class對象
        Class stuClass = Class.forName("com.pangsir.model.Student");
        
        
        System.out.println("************返回所有public構(gòu)造方法************");
        Constructor[] constructors = stuClass.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        /*
         * Output:
         * ************返回所有public構(gòu)造方法************
         *    public com.pangsir.model.Student()
         *    public com.pangsir.model.Student(java.lang.String,int)
         */
    
        System.out.println("************所有的構(gòu)造方法(包括:私有、受保護(hù)、默認(rèn)、公有)***************");  
        Constructor[] constructors2 = stuClass.getDeclaredConstructors();
        for (Constructor constructor : constructors2) {
            System.out.println(constructor);
        }
        /*
         * Output:
         * ************所有的構(gòu)造方法(包括:私有、受保護(hù)、默認(rèn)、公有)***************
         *    private com.pangsir.model.Student(int)
         *    public com.pangsir.model.Student()
         *    protected com.pangsir.model.Student(char)
         *    public com.pangsir.model.Student(java.lang.String,int)
         *    com.pangsir.model.Student(java.lang.String)
         */
        
        
        Constructor constructor;

        System.out.println("************返回指定類型的 public構(gòu)造器************");
        try {
            constructor = stuClass.getConstructor(String.class, int.class);
            System.out.println(constructor);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        /*
         * Output:
         * ************返回指定類型的 public構(gòu)造器************
         * public com.pangsir.model.Student(java.lang.String,int)
         * 
         * 如果指定參數(shù)的構(gòu)造器是非public類型的 則拋出java.lang.NoSuchMethodException異常
         */
          
        System.out.println("************返回指定類型的構(gòu)造器************");
        try { 
            constructor = stuClass.getDeclaredConstructor(int.class);
            System.out.println(constructor);            // char.class
        } catch (NoSuchMethodException e) {             // String.class, int.class
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        /*
         * Output:
         * ************返回指定類型的構(gòu)造器************
         * public com.pangsir.model.Student(java.lang.String,int)
         * protected com.pangsir.model.Student(char)
         * private com.pangsir.model.Student(int)
         */
        System.out.println("********獲取私有構(gòu)造方法,并調(diào)用**********");  
        constructor = clazz.getDeclaredConstructor(char.class);  
        System.out.println(con);  
        //調(diào)用構(gòu)造方法  
        con.setAccessible(true);//暴力訪問(忽略掉訪問修飾符)  
        obj = con.newInstance("男");  
         /*
         * Output:
         * ************返回指定類型的構(gòu)造器************
         * public com.pangsir.model.Student(char)  
         * 姓名:男 
         */
    }
}
5.5 獲取變量

Field 提供了有關(guān)類或接口的單個(gè)屬性的信息,以及對它的動(dòng)態(tài)訪問的能力。

可以通過 Class 提供的方法,獲取 Field 對象,具體如下:

方法返回值 方法名稱 方法說明
Field getDeclaredField(String name) 獲取指定name名稱的(包含private修飾的)字段,不包括繼承的字段
Field[] getDeclaredField() 獲取Class對象所表示的類或接口的所有(包含private修飾的)字段,不包括繼承的字段
Field getField(String name) 獲取指定name名稱、具有public修飾的字段,包含繼承字段
Field[] getField() 獲取修飾符為public的字段,包含繼承字段
public class Student {  
    public Student(){  
          
    }  
    //**********字段*************//  
    public String name;  
    protected int age;  
    char sex;  
    private String phoneNum;  
      
    @Override  
    public String toString() {  
        return "Student [name=" + name + ", age=" + age + ", sex=" + sex  
                + ", phoneNum=" + phoneNum + "]";  
    }  
      
      
}

測試類

package com.pangsir.field;  
import java.lang.reflect.Field;  
/* 
 * 獲取成員變量并調(diào)用: 
 *  
 * 1.批量的 
 *      1).Field[] getFields():獲取所有的"公有字段" 
 *      2).Field[] getDeclaredFields():獲取所有字段,包括:私有、受保護(hù)、默認(rèn)、公有; 
 * 2.獲取單個(gè)的: 
 *      1).public Field getField(String fieldName):獲取某個(gè)"公有的"字段; 
 *      2).public Field getDeclaredField(String fieldName):獲取某個(gè)字段(可以是私有的) 
 *  
 *   設(shè)置字段的值: 
 *      Field --> public void set(Object obj,Object value): 
 *                  參數(shù)說明: 
 *                  1.obj:要設(shè)置的字段所在的對象; 
 *                  2.value:要為字段設(shè)置的值; 
 *  
 */  
public class Fields {  
  
        public static void main(String[] args) throws Exception {  
            //1.獲取Class對象  
            Class stuClass = Class.forName("com.pangsir.model.Student");  
            //2.獲取字段  
            System.out.println("************獲取所有公有的字段********************");  
            Field[] fieldArray = stuClass.getFields();  
            for(Field f : fieldArray){  
                System.out.println(f);  
            }
            /*
             * Output:
             * ***********獲取所有公有的字段********************  
             * public java.lang.String com.pangsir.model.Student.name  
             */
            
            System.out.println("******獲取所有的字段(包括私有、受保護(hù)、默認(rèn)的)***********");  
            fieldArray = stuClass.getDeclaredFields();  
            for(Field f : fieldArray){  
                System.out.println(f);  
            }  
             /*
             * Output:
             ************獲取所有的字段(包括私有、受保護(hù)、默認(rèn)的)********************  
             *  public java.lang.String com.pangsir.model.Student.name  
             *  protected int com.pangsir.model.Student.age  
             *  char com.pangsir.model.Student.sex  
             *  private java.lang.String com.pangsir.model.Student.phoneNum 
             */
            System.out.println("******獲取公有字段并調(diào)用*********");  
            Field f = stuClass.getField("name");  
            System.out.println(f);  
            //獲取一個(gè)對象  
            Object obj = stuClass.getConstructor().newInstance();//產(chǎn)生Student對象--》Student stu = new Student();  
            //為字段設(shè)置值  
            f.set(obj, "劉德華");//為Student對象中的name屬性賦值--》stu.name = "劉德華"  
            //驗(yàn)證  
            Student stu = (Student)obj;  
            System.out.println("驗(yàn)證姓名:" + stu.name);  
            /*
             * Output:
             *************獲取公有字段**并調(diào)用***********************************  
             * public java.lang.String com.pangsir.model.Student.name  
             * 驗(yàn)證姓名:劉德華 
             */
              
            System.out.println("*****獲取私有字段****并調(diào)用***************");  
            f = stuClass.getDeclaredField("phoneNum");  
            System.out.println(f);  
            f.setAccessible(true);//暴力反射,解除私有限定  
            f.set(obj, "12345768901");  
            System.out.println("驗(yàn)證電話:" + stu);  
            /*
             * Output:
             **************獲取私有字段****并調(diào)用********************************  
             * private java.lang.String fanshe.field.Student.phoneNum  
             * 驗(yàn)證電話:Student [name=劉德華, age=0, sex= ,  phoneNum=12345768901]
             */
              
        }  
    }
代碼分析:調(diào)用字段時(shí):需要傳遞兩個(gè)參數(shù):
Object obj = stuClass.getConstructor().newInstance();

//產(chǎn)生Student對象--》Student stu = new Student();

//為字段設(shè)置值
f.set(obj, "劉德華");

//為Student對象中的name屬性賦值--》stu.name = "劉德華"
第一個(gè)參數(shù):要傳入設(shè)置的對象,第二個(gè)參數(shù):要傳入實(shí)參

5.6 獲取方法

Method 提供了有關(guān)類或接口的單個(gè)方法的信息,以及對它的動(dòng)態(tài)訪問的能力。

可以通過 Class 提供的方法,獲取 Field 對象,具體如下:

方法返回值 方法名稱 方法說明
Method getDeclaredMethod(String name, Class... parameterTypes) 返回一個(gè)指定參數(shù)的Method對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。
Method[] getDeclaredMethod() 返回 Method 對象的一個(gè)數(shù)組,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護(hù)、默認(rèn)(包)訪問和私有方法,但不包括繼承的方法。
Method getMethod(String name, Class... parameterTypes) 返回一個(gè) Method 對象,它反映此 Class 對象所表示的類或接口的指定公共成員方法。
Method[] getMethods() 返回一個(gè)包含某些 Method 對象的數(shù)組,這些對象反映此 Class 對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。

Student類:

public class Student {  
    //**************成員方法***************//  
    public void show1(String s){  
        System.out.println("調(diào)用了:公有的,String參數(shù)的show1(): s = " + s);  
    }  
    protected void show2(){  
        System.out.println("調(diào)用了:受保護(hù)的,無參的show2()");  
    }  
    void show3(){  
        System.out.println("調(diào)用了:默認(rèn)的,無參的show3()");  
    }  
    private String show4(int age){  
        System.out.println("調(diào)用了,私有的,并且有返回值的,int參數(shù)的show4(): age = " + age);  
        return "abcd";  
    }  
} 

測試類:

package com.pangsir.method;  
  
import java.lang.reflect.Method;  
  
/* 
 * 獲取成員方法并調(diào)用: 
 *  
 * 1.批量的: 
 *      public Method[] getMethods():獲取所有"公有方法";(包含了父類的方法也包含Object類) 
 *      public Method[] getDeclaredMethods():獲取所有的成員方法,包括私有的(不包括繼承的) 
 * 2.獲取單個(gè)的: 
 *      public Method getMethod(String name,Class... parameterTypes): 
 *                  參數(shù): 
 *                      name : 方法名; 
 *                      Class ... : 形參的Class類型對象 
 *      public Method getDeclaredMethod(String name,Class... parameterTypes) 
 *  
 *   調(diào)用方法: 
 *      Method --> public Object invoke(Object obj,Object... args): 
 *                  參數(shù)說明: 
 *                  obj : 要調(diào)用方法的對象; 
 *                  args:調(diào)用方式時(shí)所傳遞的實(shí)參; 
 
): 
 */  
public class MethodClass {  
  
    public static void main(String[] args) throws Exception {  
        //1.獲取Class對象  
        Class stuClass = Class.forName("fanshe.method.Student");  
        //2.獲取所有公有方法  
        System.out.println("***************獲取所有的”公有“方法*******************");   
        Method[] methodArray = stuClass.getMethods();  
        for(Method m : methodArray){  
            System.out.println(m);  
        }
        /*
         * Output:
         ***************獲取所有的”公有“方法*******************  
            public void com.pangsir.model.Student.show1(java.lang.String)  
            public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException  
            public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException  
            public final void java.lang.Object.wait() throws java.lang.InterruptedException  
            public boolean java.lang.Object.equals(java.lang.Object)  
            public java.lang.String java.lang.Object.toString()  
            public native int java.lang.Object.hashCode()  
            public final native java.lang.Class java.lang.Object.getClass()  
            public final native void java.lang.Object.notify()  
            public final native void java.lang.Object.notifyAll() 
         */
        System.out.println("***************獲取所有的方法,包括私有的*******************");  
        methodArray = stuClass.getDeclaredMethods();  
        for(Method m : methodArray){  
            System.out.println(m);  
        }  
        /*
         * Output:
         ***************獲取所有的方法,包括私有的*******************  
        public void om.pangsir.model.Student.show1(java.lang.String)  
        private java.lang.String om.pangsir.model.Student.show4(int)  
        protected void om.pangsir.model.Student.show2()  
        void om.pangsir.model.Student.show3()  
         */
        System.out.println("***************獲取公有的show1()方法*******************");  
        Method m = stuClass.getMethod("show1", String.class);  
        System.out.println(m);  
        //實(shí)例化一個(gè)Student對象  
        Object obj = stuClass.getConstructor().newInstance();  
        m.invoke(obj, "劉德華");  
         /*
         * Output:
         ***************獲取公有的show1()方法*******************  
        public void om.pangsir.model.Student.show1(java.lang.String)  
        調(diào)用了:公有的,String參數(shù)的show1(): s = 劉德華 
         */
          
        System.out.println("***************獲取私有的show4()方法******************");  
        m = stuClass.getDeclaredMethod("show4", int.class);  
        System.out.println(m);  
        m.setAccessible(true);//解除私有限定  
        Object result = m.invoke(obj, 20);//需要兩個(gè)參數(shù),一個(gè)是要調(diào)用的對象(獲取有反射),一個(gè)是實(shí)參  
        System.out.println("返回值:" + result);
        /*
         * Output:
         ***************獲取私有的show4()方法******************  
        private java.lang.String om.pangsir.model.Student.show4(int)  
        調(diào)用了,私有的,并且有返回值的,int參數(shù)的show4(): age = 20  
        返回值:abcd 
         */
          
          
    }  
}  
代碼分析:由此可見:
m = stuClass.getDeclaredMethod("show4", int.class);//調(diào)用制定方法(所有包括私有的),需要傳入兩個(gè)參數(shù),第一個(gè)是調(diào)用的方法名稱,第二個(gè)是方法的形參類型,切記是類型。
System.out.println(m);
m.setAccessible(true);//解除私有限定
Object result = m.invoke(obj, 20);//需要兩個(gè)參數(shù),一個(gè)是要調(diào)用的對象(獲取有反射),一個(gè)是實(shí)參
System.out.println("返回值:" + result);
5.7 反射main(主方法)

Student類

package com.pangsir.main;  
  
public class Student {  
  
    public static void main(String[] args) {  
        System.out.println("main方法執(zhí)行了。。。");  
    }  
}

測試類:

package fanshe.main;  
  
import java.lang.reflect.Method;  
  
/** 
 * 獲取Student類的main方法、不要與當(dāng)前的main方法搞混了 
 */  
public class Main {  
      
    public static void main(String[] args) {  
        try {  
            //1、獲取Student對象的字節(jié)碼  
            Class clazz = Class.forName("fanshe.main.Student");  
              
            //2、獲取main方法  
             Method methodMain = clazz.getMethod("main", String[].class);//第一個(gè)參數(shù):方法名稱,第二個(gè)參數(shù):方法形參的類型,  
            //3、調(diào)用main方法  
            // methodMain.invoke(null, new String[]{"a","b","c"});  
             //第一個(gè)參數(shù),對象類型,因?yàn)榉椒ㄊ莝tatic靜態(tài)的,所以為null可以,第二個(gè)參數(shù)是String數(shù)組,這里要注意在jdk1.4時(shí)是數(shù)組,jdk1.5之后是可變參數(shù)  
             //這里拆的時(shí)候?qū)? new String[]{"a","b","c"} 拆成3個(gè)對象。。。所以需要將它強(qiáng)轉(zhuǎn)。  
             methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一  
            // methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二  
              
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
          
          
    }  
}
5.8 通過反射越過泛型檢查

泛型用在編譯期,編譯過后泛型擦除(消失掉)。所以是可以通過反射越過泛型檢查的

import java.lang.reflect.Method;  
import java.util.ArrayList;  
 
/* 
* 通過反射越過泛型檢查 
*  
* 例如:有一個(gè)String泛型的集合,怎樣能向這個(gè)集合中添加一個(gè)Integer類型的值? 
*/  
public class Demo {  
   public static void main(String[] args) throws Exception{  
       ArrayList strList = new ArrayList<>();  
       strList.add("aaa");  
       strList.add("bbb");  
         
   //  strList.add(100);  
       //獲取ArrayList的Class對象,反向的調(diào)用add()方法,添加數(shù)據(jù)  
       Class listClass = strList.getClass(); //得到 strList 對象的字節(jié)碼 對象  
       //獲取add()方法  
       Method m = listClass.getMethod("add", Object.class);  
       //調(diào)用add()方法  
       m.invoke(strList, 100);  
         
       //遍歷集合  
       for(Object obj : strList){  
           System.out.println(obj);
           System.out.println(obj.getClass());
       }  
        /*
         *Output:
         * aaa
         * class java.lang.String
         * bbb
         * class java.lang.String
         * 100
         * class java.lang.Integer
         */
   }  
}
5.9 通過反射運(yùn)行配置文件內(nèi)容

Student類

public class Student {  
    public void show(){  
        System.out.println("is show()");  
    }  
} 

配置文件以txt文件為例子(os.properties):

className = com.pangsir.model.Student  
methodName = show 

測試類:

import java.io.FileNotFoundException;  
import java.io.FileReader;  
import java.io.IOException;  
import java.lang.reflect.Method;  
import java.util.Properties;  
  
/* 
 * 我們利用反射和配置文件,可以使:應(yīng)用程序更新時(shí),對源碼無需進(jìn)行任何修改 
 * 我們只需要將新類發(fā)送給客戶端,并修改配置文件即可 
 */  
public class Demo {  
    public static void main(String[] args) throws Exception {  
        //通過反射獲取Class對象  
        Class stuClass = Class.forName(getValue("className"));//"cn.fanshe.Student"  
        //2獲取show()方法  
        Method m = stuClass.getMethod(getValue("methodName"));//show  
        //3.調(diào)用show()方法  
        m.invoke(stuClass.getConstructor().newInstance());  
          
    }  
      
    //此方法接收一個(gè)key,在配置文件中獲取相應(yīng)的value  
    public static String getValue(String key) throws IOException{  
        Properties pro = new Properties();//獲取配置文件的對象  
        FileReader in = new FileReader("os.properties");//獲取輸入流  
        pro.load(in);//將流加載到配置文件對象中  
        in.close();  
        return pro.getProperty(key);//返回根據(jù)key獲取的value值  
    }  
}  
  /*
  *Output:
  * is show()
  */

需求:
當(dāng)我們升級這個(gè)系統(tǒng)時(shí),不要Student類,而需要新寫一個(gè)Student2的類時(shí),這時(shí)只需要更改pro.txt的文件內(nèi)容就可以了。代碼就一點(diǎn)不用改動(dòng)

Student2類:

public class Student2 {  
    public void show2(){  
        System.out.println("is show2()");  
    }  
} 

修改配置文件如下

className = com.pangsir.model.Student2  
methodName = show2  
5.10 利用ParameterizedType獲取java泛型參數(shù)類
//超類
package test;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

@SuppressWarnings("unchecked")
public class Person {
    private Class clazz;
    public Person() {
        // 使用反射技術(shù)得到T的真實(shí)類型
        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); // 獲取當(dāng)前new的對象的 泛型的父類 類型
        this.clazz = (Class) pt.getActualTypeArguments()[0]; // 獲取第一個(gè)類型參數(shù)的真實(shí)類型
        System.out.println("clazz ---> " + clazz);
    }

}
//子類
package test;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class Student extends Person {
}
//測試類
package test;

public class TestGetClass {

    /**
     * @param args
     */
    public static void main(String[] args) {

          Student student = new Student();
    }

}
6.反射的缺點(diǎn)

沒有任何一項(xiàng)技術(shù)是十全十美的,Java反射擁有強(qiáng)大功能的同時(shí)也帶來了一些副作用。

性能開銷
反射涉及類型動(dòng)態(tài)解析,所以JVM無法對這些代碼進(jìn)行優(yōu)化。因此,反射操作的效率要比那些非反射操作低得多。我們應(yīng)該避免在經(jīng)常被執(zhí)行的代碼或?qū)π阅芤蠛芨叩某绦蛑惺褂梅瓷洹?/p>

安全限制
使用反射技術(shù)要求程序必須在一個(gè)沒有安全限制的環(huán)境中運(yùn)行。如果一個(gè)程序必須在有安全限制的環(huán)境中運(yùn)行,如Applet,那么這就是個(gè)問題了。

內(nèi)部曝光
由于反射允許代碼執(zhí)行一些在正常情況下不被允許的操作(比如訪問私有的屬性和方法),所以使用反射可能會導(dǎo)致意料之外的副作用--代碼有功能上的錯(cuò)誤,降低可移植性。反射代碼破壞了抽象性,因此當(dāng)平臺發(fā)生改變的時(shí)候,代碼的行為就有可能也隨著變化。

使用反射的一個(gè)原則:如果使用常規(guī)方法能夠?qū)崿F(xiàn),那么就不要用反射。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/72580.html

相關(guān)文章

  • 為什么鳥哥說 int 再怎么隨機(jī)也申請不到奇數(shù)地址

    摘要:棧上各個(gè)變量申請的內(nèi)存,返回的地址是這段連續(xù)內(nèi)存的最小的地址。為什么用一個(gè)位的十六進(jìn)制來呢因?yàn)閭€(gè)字節(jié),一個(gè)字節(jié)有位,每位有兩個(gè)狀態(tài),那么就是,也就是。為什么用,純屬演示方便。結(jié)構(gòu)體里的字節(jié)對齊以成員中自身對齊值最大的那個(gè)值為標(biāo)準(zhǔn)。 原文:我的個(gè)人博客 https://mengkang.net/1046.html初中級 phper 有多久沒給自己充電了呢,安利一波我的直播 PHP 進(jìn)階之...

    klinson 評論0 收藏0
  • 你不知道的JavaScript上卷之作用域與閉包·讀書筆記

    摘要:的分句會創(chuàng)建一個(gè)塊作用域,其聲明的變量僅在中有效。而閉包的神奇作用是阻止此事發(fā)生。依然持有對該作用域的引用,而這個(gè)引用就叫做閉包。當(dāng)然,無論使用何種方式對函數(shù)類型的值進(jìn)行傳遞,當(dāng)函數(shù)在別處被調(diào)用時(shí)都可以觀察到閉包。 date: 16.12.8 Thursday 第一章 作用域是什么 LHS:賦值操作的目標(biāo)是誰? 比如: a = 2; RHS:誰是賦值操作的源頭? 比如: conso...

    Raaabbit 評論0 收藏0
  • 你不知道的javascript(上卷)讀后感(一)

    摘要:遮蔽效應(yīng)作用域查找會在找到第一個(gè)匹配的標(biāo)識符時(shí)停止,不會繼續(xù)往上層作用域查找,這就會產(chǎn)生遮蔽效應(yīng)。會發(fā)現(xiàn)每一次輸出的都是為啥勒所有的回調(diào)函數(shù)回在循環(huán)結(jié)束后才會執(zhí)行事件循環(huán)。 三劍客 編譯,顧名思義,就是源代碼執(zhí)行前會經(jīng)歷的過程,分三個(gè)步驟, 分詞/詞法分析,將我們寫的代碼字符串分解成多個(gè)詞法單元 解析/語法分析,將詞法單元集合生成抽象語法樹(AST) 代碼生成,抽象語法樹(AST)轉(zhuǎn)...

    zhaofeihao 評論0 收藏0
  • 十分鐘快速了解《你不知道的 JavaScript》(上卷

    摘要:最近剛剛看完了你不知道的上卷,對有了更進(jìn)一步的了解。你不知道的上卷由兩部分組成,第一部分是作用域和閉包,第二部分是和對象原型。附錄詞法這一章并沒有說明機(jī)制,只是介紹了中的箭頭函數(shù)引入的行為詞法。第章混合對象類類理論類的機(jī)制類的繼承混入。 最近剛剛看完了《你不知道的 JavaScript》上卷,對 JavaScript 有了更進(jìn)一步的了解。 《你不知道的 JavaScript》上卷由兩部...

    趙春朋 評論0 收藏0
  • jQuery動(dòng)畫特效

    摘要:可選的參數(shù)規(guī)定效果的時(shí)長,它可以取以下值,或毫秒。五其他核心方法中停止動(dòng)畫方法用于停止動(dòng)畫或效果,在它們完成之前。默認(rèn)是,即僅停止活動(dòng)的動(dòng)畫,運(yùn)行任何排入隊(duì)列的動(dòng)畫向后執(zhí)行。這些動(dòng)畫不會開始,知道第一個(gè)完成。 本文主要跟大家分享jQuery隱藏與顯示(hide,show,toggle) 上卷與下拉(slideDown,slideUp,slideToggle) 淡入淡出(fadeOut,...

    張遷 評論0 收藏0

發(fā)表評論

0條評論

hedzr

|高級講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<