国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

胖哥說反射 上卷

hedzr / 1320人閱讀

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

我來學習反射 1.為什么我們要學習反射?

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

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

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

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

我個人認為:一切的操作都是講使用Object完成,類或者數組的引用是可以用Object進行接收。

也就是我們之前說Java中的我認為很重要的多態,對象的多態:Object object= 任何引用類型的實例對象

3.類的加載過程

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

Class對象的由來是將class文件讀入內存,并為之創建一個Class對象,那么Class對象在反射中起到什么作用?

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

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虛擬機都會初始化出一個Class類型的實例,每當我們編寫并且編譯一個新創建的類就會產生一個對應Class對象,并且這個Class對象會被保存在同名.class文件里。當我們new一個新對象或者引用靜態成員變量時,Java虛擬機(JVM)中的類加載器系統會將對應Class對象加載到JVM中,然后JVM再根據這個類型信息相關的Class對象創建我們需要實例對象或者提供靜態變量的引用值。

如上圖所示,比如創建編譯一個Student類,那么,JVM就會創建一個Student對應Class類的Class實例,該Class實例保存了Student類相關的類型信息,包括屬性,方法,構造方法等等,通過這個Class實例可以在運行時訪問Student對象的屬性和方法等。另外通過Class類還可以創建出一個新的Student對象。這就是反射能夠實現的原因,可以說Class是反射操作的基礎。

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

4.Class API簡要說明

跟我們之前學習查看Math、String類一樣的過程

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

Class 沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的defineClass 方法自動構造的。也就是這不需要我們自己去處理創建,JVM已經幫我們創建好了。

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

5.反射的使用

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

Class:表示類或者接口

Field:表示類中的成員變量

Method:表示類中的方法

Constructor:表示類的構造方法

Array:該類提供了動態創建數組和訪問數組元素的靜態方法

先自己設置一個Student類來完成對應的測試,代碼如下:

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;
    }

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

說Class是反射能夠實現的基礎的另一個原因是:Java反射包java.lang.reflect中的所有類都沒有public構造方法,要想獲得這些類實例,只能通過Class類獲取。所以說如果想使用反射,必須得獲得Class對象。

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

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

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

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

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

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

class 語法

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

// 類
Class clazz = Integer.class;
// 數組
Class clazz2 = int [][].class;

包裝類的 TYPE 靜態屬性

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

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

生成 Class 類實例的方法:

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

Class.forName() 方法

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

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

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

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

對于數組比較特殊:

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

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

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

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

該類已經被某個類加載器加載到 JVM 內存中,另外一個類加載器又嘗試從同一個包中加載

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
代碼說明:在運行期間,一個類,只有一個Class對象產生。三種方式常用第三種,第一種對象都有了還要反射干什么。第二種需要導入類的包,依賴太強,不導包就拋編譯錯誤。一般都選第三種,一個字符串可以傳入也可寫在配置文件中等多種方法。
5.3 Member & AccessibleObject

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

5.4 獲取構造方法

Constructor 提供了有關類的構造方法的信息,以及對它的動態訪問的能力。

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

方法返回值 方法名稱 方法說明
Constructor getConstructor(Class... parameterTypes) 返回指定參數類型、具有public訪問權限的構造函數對象
Constructor[] getConstructors() 返回所有具有public訪問權限的構造函數的Constructor對象數組
Constructor getDeclaredConstructor(Class... parameterTypes) 返回指定參數類型、所有聲明的(包括private)構造函數對象
Constructor[] getDeclaredConstructor() 返回所有聲明的(包括private)構造函數對象
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構造方法************");
        Constructor[] constructors = stuClass.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        /*
         * Output:
         * ************返回所有public構造方法************
         *    public com.pangsir.model.Student()
         *    public com.pangsir.model.Student(java.lang.String,int)
         */
    
        System.out.println("************所有的構造方法(包括:私有、受保護、默認、公有)***************");  
        Constructor[] constructors2 = stuClass.getDeclaredConstructors();
        for (Constructor constructor : constructors2) {
            System.out.println(constructor);
        }
        /*
         * Output:
         * ************所有的構造方法(包括:私有、受保護、默認、公有)***************
         *    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構造器************");
        try {
            constructor = stuClass.getConstructor(String.class, int.class);
            System.out.println(constructor);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        /*
         * Output:
         * ************返回指定類型的 public構造器************
         * public com.pangsir.model.Student(java.lang.String,int)
         * 
         * 如果指定參數的構造器是非public類型的 則拋出java.lang.NoSuchMethodException異常
         */
          
        System.out.println("************返回指定類型的構造器************");
        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:
         * ************返回指定類型的構造器************
         * public com.pangsir.model.Student(java.lang.String,int)
         * protected com.pangsir.model.Student(char)
         * private com.pangsir.model.Student(int)
         */
        System.out.println("********獲取私有構造方法,并調用**********");  
        constructor = clazz.getDeclaredConstructor(char.class);  
        System.out.println(con);  
        //調用構造方法  
        con.setAccessible(true);//暴力訪問(忽略掉訪問修飾符)  
        obj = con.newInstance("男");  
         /*
         * Output:
         * ************返回指定類型的構造器************
         * public com.pangsir.model.Student(char)  
         * 姓名:男 
         */
    }
}
5.5 獲取變量

Field 提供了有關類或接口的單個屬性的信息,以及對它的動態訪問的能力。

可以通過 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;  
/* 
 * 獲取成員變量并調用: 
 *  
 * 1.批量的 
 *      1).Field[] getFields():獲取所有的"公有字段" 
 *      2).Field[] getDeclaredFields():獲取所有字段,包括:私有、受保護、默認、公有; 
 * 2.獲取單個的: 
 *      1).public Field getField(String fieldName):獲取某個"公有的"字段; 
 *      2).public Field getDeclaredField(String fieldName):獲取某個字段(可以是私有的) 
 *  
 *   設置字段的值: 
 *      Field --> public void set(Object obj,Object value): 
 *                  參數說明: 
 *                  1.obj:要設置的字段所在的對象; 
 *                  2.value:要為字段設置的值; 
 *  
 */  
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("******獲取所有的字段(包括私有、受保護、默認的)***********");  
            fieldArray = stuClass.getDeclaredFields();  
            for(Field f : fieldArray){  
                System.out.println(f);  
            }  
             /*
             * Output:
             ************獲取所有的字段(包括私有、受保護、默認的)********************  
             *  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("******獲取公有字段并調用*********");  
            Field f = stuClass.getField("name");  
            System.out.println(f);  
            //獲取一個對象  
            Object obj = stuClass.getConstructor().newInstance();//產生Student對象--》Student stu = new Student();  
            //為字段設置值  
            f.set(obj, "劉德華");//為Student對象中的name屬性賦值--》stu.name = "劉德華"  
            //驗證  
            Student stu = (Student)obj;  
            System.out.println("驗證姓名:" + stu.name);  
            /*
             * Output:
             *************獲取公有字段**并調用***********************************  
             * public java.lang.String com.pangsir.model.Student.name  
             * 驗證姓名:劉德華 
             */
              
            System.out.println("*****獲取私有字段****并調用***************");  
            f = stuClass.getDeclaredField("phoneNum");  
            System.out.println(f);  
            f.setAccessible(true);//暴力反射,解除私有限定  
            f.set(obj, "12345768901");  
            System.out.println("驗證電話:" + stu);  
            /*
             * Output:
             **************獲取私有字段****并調用********************************  
             * private java.lang.String fanshe.field.Student.phoneNum  
             * 驗證電話:Student [name=劉德華, age=0, sex= ,  phoneNum=12345768901]
             */
              
        }  
    }
代碼分析:調用字段時:需要傳遞兩個參數:
Object obj = stuClass.getConstructor().newInstance();

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

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

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

5.6 獲取方法

Method 提供了有關類或接口的單個方法的信息,以及對它的動態訪問的能力。

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

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

Student類:

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

測試類:

package com.pangsir.method;  
  
import java.lang.reflect.Method;  
  
/* 
 * 獲取成員方法并調用: 
 *  
 * 1.批量的: 
 *      public Method[] getMethods():獲取所有"公有方法";(包含了父類的方法也包含Object類) 
 *      public Method[] getDeclaredMethods():獲取所有的成員方法,包括私有的(不包括繼承的) 
 * 2.獲取單個的: 
 *      public Method getMethod(String name,Class... parameterTypes): 
 *                  參數: 
 *                      name : 方法名; 
 *                      Class ... : 形參的Class類型對象 
 *      public Method getDeclaredMethod(String name,Class... parameterTypes) 
 *  
 *   調用方法: 
 *      Method --> public Object invoke(Object obj,Object... args): 
 *                  參數說明: 
 *                  obj : 要調用方法的對象; 
 *                  args:調用方式時所傳遞的實參; 
 
): 
 */  
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);  
        //實例化一個Student對象  
        Object obj = stuClass.getConstructor().newInstance();  
        m.invoke(obj, "劉德華");  
         /*
         * Output:
         ***************獲取公有的show1()方法*******************  
        public void om.pangsir.model.Student.show1(java.lang.String)  
        調用了:公有的,String參數的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);//需要兩個參數,一個是要調用的對象(獲取有反射),一個是實參  
        System.out.println("返回值:" + result);
        /*
         * Output:
         ***************獲取私有的show4()方法******************  
        private java.lang.String om.pangsir.model.Student.show4(int)  
        調用了,私有的,并且有返回值的,int參數的show4(): age = 20  
        返回值:abcd 
         */
          
          
    }  
}  
代碼分析:由此可見:
m = stuClass.getDeclaredMethod("show4", int.class);//調用制定方法(所有包括私有的),需要傳入兩個參數,第一個是調用的方法名稱,第二個是方法的形參類型,切記是類型。
System.out.println(m);
m.setAccessible(true);//解除私有限定
Object result = m.invoke(obj, 20);//需要兩個參數,一個是要調用的對象(獲取有反射),一個是實參
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方法執行了。。。");  
    }  
}

測試類:

package fanshe.main;  
  
import java.lang.reflect.Method;  
  
/** 
 * 獲取Student類的main方法、不要與當前的main方法搞混了 
 */  
public class Main {  
      
    public static void main(String[] args) {  
        try {  
            //1、獲取Student對象的字節碼  
            Class clazz = Class.forName("fanshe.main.Student");  
              
            //2、獲取main方法  
             Method methodMain = clazz.getMethod("main", String[].class);//第一個參數:方法名稱,第二個參數:方法形參的類型,  
            //3、調用main方法  
            // methodMain.invoke(null, new String[]{"a","b","c"});  
             //第一個參數,對象類型,因為方法是static靜態的,所以為null可以,第二個參數是String數組,這里要注意在jdk1.4時是數組,jdk1.5之后是可變參數  
             //這里拆的時候將  new String[]{"a","b","c"} 拆成3個對象。。。所以需要將它強轉。  
             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;  
 
/* 
* 通過反射越過泛型檢查 
*  
* 例如:有一個String泛型的集合,怎樣能向這個集合中添加一個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對象,反向的調用add()方法,添加數據  
       Class listClass = strList.getClass(); //得到 strList 對象的字節碼 對象  
       //獲取add()方法  
       Method m = listClass.getMethod("add", Object.class);  
       //調用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 通過反射運行配置文件內容

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;  
  
/* 
 * 我們利用反射和配置文件,可以使:應用程序更新時,對源碼無需進行任何修改 
 * 我們只需要將新類發送給客戶端,并修改配置文件即可 
 */  
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.調用show()方法  
        m.invoke(stuClass.getConstructor().newInstance());  
          
    }  
      
    //此方法接收一個key,在配置文件中獲取相應的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);//返回根據key獲取的value值  
    }  
}  
  /*
  *Output:
  * is show()
  */

需求:
當我們升級這個系統時,不要Student類,而需要新寫一個Student2的類時,這時只需要更改pro.txt的文件內容就可以了。代碼就一點不用改動

Student2類:

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

修改配置文件如下

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

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

@SuppressWarnings("unchecked")
public class Person {
    private Class clazz;
    public Person() {
        // 使用反射技術得到T的真實類型
        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); // 獲取當前new的對象的 泛型的父類 類型
        this.clazz = (Class) pt.getActualTypeArguments()[0]; // 獲取第一個類型參數的真實類型
        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.反射的缺點

沒有任何一項技術是十全十美的,Java反射擁有強大功能的同時也帶來了一些副作用。

性能開銷
反射涉及類型動態解析,所以JVM無法對這些代碼進行優化。因此,反射操作的效率要比那些非反射操作低得多。我們應該避免在經常被執行的代碼或對性能要求很高的程序中使用反射。

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

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

使用反射的一個原則:如果使用常規方法能夠實現,那么就不要用反射。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72580.html

相關文章

  • 為什么鳥哥說 int 再怎么隨機也申請不到奇數地址

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

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

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

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

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

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

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

    趙春朋 評論0 收藏0
  • jQuery動畫特效

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

    張遷 評論0 收藏0

發表評論

0條評論

hedzr

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<