33_反射(類載入、反射)_講義

来源:https://www.cnblogs.com/wanghui1234/archive/2018/09/09/9612484.html
-Advertisement-
Play Games

1、類載入器 2、反射構造方法 3、反射成員變數 4、反射成員方法 5、反射配置文件運行類中的方法 ...


今日內容介紹
1、類載入器
2、反射構造方法
3、反射成員變數
4、反射成員方法
5、反射配置文件運行類中的方法

01類載入器

  • A.類的載入
  •   當程式要使用某個類時,如果該類還未被載入到記憶體中,則系統會通過載入,連接,初始化三步來實現對這個類進行初始化。
      * a 載入 
          * 就是指將class文件讀入記憶體,併為之創建一個Class對象。
          * 任何類被使用時系統都會建立一個Class對象
      * b 連接
          * 驗證 是否有正確的內部結構,並和其他類協調一致
          * 準備 負責為類的靜態成員分配記憶體,並設置預設初始化值
          * 解析 將類的二進位數據中的符號引用替換為直接引用
      * c 初始化 
          * 就是我們以前講過的初始化步驟(new 對象)
      * 註:簡單的說就是:把.class文件載入到記憶體里,並把這個.class文件封裝成一個Class類型的對象。
  • B.類的載入時機
  •   以下的情況,會載入這個類。
      * a. 創建類的實例
      * b. 類的靜態變數,或者為靜態變數賦值
      * c. 類的靜態方法
      * d. 使用反射方式來強制創建某個類或介面對應的java.lang.Class對象
      * e. 初始化某個類的子類
      * f. 直接使用java.exe命令來運行某個主類
  • C: 類載入器(瞭解)
  •   負責將.class文件載入到內在中,併為之生成對應的Class對象。
      * a. Bootstrap ClassLoader 根類載入器
          * 也被稱為引導類載入器,負責Java核心類的載入
          * 比如System,String等。在JDK中JRE的lib目錄下rt.jar文件中
      * b. Extension ClassLoader 擴展類載入器
          * 負責JRE的擴展目錄中jar包的載入。
          * 在JDK中JRE的lib目錄下ext目錄
      * c. System ClassLoader 系統類載入器
          * 負責在JVM啟動時載入來自java命令的class文件,以及classpath環境變數所指定的jar包和類路徑。
          * 我們用的是System ClassLoader 系統類載入器

02反射

  • A. 反射定義

      * a. JAVA反射機制是在運行狀態中,
              對於任意一個類,都能夠知道這個類的所有屬性和方法;
              對於任意一個對象,都能夠調用它的任意一個方法和屬性;
          這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。
    
      * b.反射技術
          條件:運行狀態
          已知:一個類或一個對象(根本是已知.class文件)
          結果:得到這個類或對象的所有方法和屬性
    
      * 註: 要想解剖一個類,必須先要獲取到該類的位元組碼文件對象。而解剖使用的就是Class類中的方法.所以先要獲取到每一個位元組碼文件對應的Class類型的對象。
      * 
  • B. Class類

      * a. Class類及Class對象的瞭解
          要想解剖一個類,必須先瞭解Class對象。
          閱讀API的Class類得知,Class 沒有公共構造方法。Class 對象是在載入類時由 Java 虛擬機以及通過調用類載入器中的 defineClass 方法自動構造的。
      * b. 得到Class對象
          * 1. 有三個方法
              方式一: 通過Object類中的getClass()方法
                  Person person = new Person();
                  Class clazz = person.getClass();
              方式二: 通過 類名.class 獲取到位元組碼文件對象(任意數據類型都具備一個class靜態屬性,看上去要比第一種方式簡單)。
                  Class clazz = Person.class;
              方式三: 通過Class類中的方法(將類名作為字元串傳遞給Class類中的靜態方法forName即可)。
                  Class c3 = Class.forName("Person");
              註:第三種和前兩種的區別是:
                      前兩種你必須明確Person類型.
                      後面是指定這種類型的字元串就行.這種擴展更強.我不需要知道你的類.我只提供字元串,按照配置文件載入就可以了
    
          * 2. 得到Class對象的三個方法代碼演示:
              代碼演示
              /*
               * 獲取.class位元組碼文件對象的方式
               *      1:通過Object類中的getObject()方法
               *      2: 通過 類名.class 獲取到位元組碼文件對象
               *      3: 反射中的方法,
               *          public static Class<?> forName(String className) throws ClassNotFoundException
               *          返回與帶有給定字元串名的類或介面相關聯的 Class 對象 
               */
              public class ReflectDemo {
                  public static void main(String[] args) throws ClassNotFoundException {
                      // 1: 通過Object類中的getObject()方法
                      // Person p1 = new Person();
                      // Class c1 = p1.getClass();
                      // System.out.println("c1 = "+ c1);
    
                      // 2: 通過 類名.class 獲取到位元組碼文件對象
                      // Class c2 = Person.class;
                      // System.out.println("c2 = "+ c2);
    
                      // 3: 反射中的方法
                      Class c3 = Class.forName("cn.itcast_01_Reflect.Person");// 包名.類名
                      System.out.println("c3 = " + c3);
                  }
              }
              Person類
              package cn.itcast_01_Reflect;
              public class Person {
                  //成員變數
                  public String name;
                  public int age;
                  private String address;
    
                  //構造方法
                  public Person() {
                      System.out.println("空參數構造方法");
                  }
    
                  public Person(String name) {
                      this.name = name;
                      System.out.println("帶有String的構造方法");
                  }
                  //私有的構造方法
                  private Person(String name, int age){
                      this.name = name;
                      this.age = age;
                      System.out.println("帶有String,int的構造方法");
                  }
    
                  public Person(String name, int age, String address){
                      this.name = name;
                      this.age = age;
                      this.address = address;
                      System.out.println("帶有String, int, String的構造方法");
                  }
    
                  //成員方法
                  //沒有返回值沒有參數的方法
                  public void method1(){
                      System.out.println("沒有返回值沒有參數的方法");
                  }
                  //沒有返回值,有參數的方法
                  public void method2(String name){
                      System.out.println("沒有返回值,有參數的方法 name= "+ name);
                  }
                  //有返回值,沒有參數
                  public int method3(){
                      System.out.println("有返回值,沒有參數的方法");
                      return 123;
                  }
                  //有返回值,有參數的方法
                  public String method4(String name){
                      System.out.println("有返回值,有參數的方法");
                      return "哈哈" + name;
                  }
                  //私有方法
                  private void method5(){
                      System.out.println("私有方法");
                  }
    
                  @Override
                  public String toString() {
                      return "Person [name=" + name + ", age=" + age + ", address=" + address+ "]";
                  }
              }
          * 註: Class類型的唯一性
              因為一個.class文件在記憶體里只生成一個Class對象,所以無論那一種方法得到Class對象,得到的都是同一個對象。
  • C.通過反射獲取無參構造方法並使用

      * a. 得到無參構造方法
          public Constructor<?>[] getConstructors() 
              獲取所有的public 修飾的構造方法。
              選擇無參構造方法,不建議使用。
          public Constructor<T> getConstructor(Class<?>... parameterTypes) 
              獲取public修飾, 指定參數類型所對應的構造方法。
              不傳參數得到無參構造方法。
      * b. 運行無參構造方法
          public T newInstance(Object... initargs) 
              使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。 
              因為是無參構造,所以不傳參數。
      * c. 通過反射獲取無參構造方法並使用的代碼演示:
              package cn.itcast.demo1;
    
              import java.lang.reflect.Constructor;
    
              /*
               *  通過反射獲取class文件中的構造方法,運行構造方法
               *  運行構造方法,創建對象
               *    獲取class文件對象
               *    從class文件對象中,獲取需要的成員
               *    
               *  Constructor 描述構造方法對象類
               */
              public class ReflectDemo1 {
                  public static void main(String[] args) throws Exception {
    
                      Class c = Class.forName("cn.itcast.demo1.Person");
                      //使用class文件對象,獲取類中的構造方法
                      //  Constructor[]  getConstructors() 獲取class文件對象中的所有公共的構造方法
                      /*Constructor[] cons = c.getConstructors();
                      for(Constructor con : cons){
                          System.out.println(con);
                      }*/
                      //獲取指定的構造方法,空參數的構造方法
                      Constructor con =  c.getConstructor();
                      //運行空參數構造方法,Constructor類方法 newInstance()運行獲取到的構造方法
                      Object obj = con.newInstance();
                      System.out.println(obj.toString());
                  }
              }
  • D. 通過反射獲取有參構造方法並使用

      * a. 得到有參的構造方法
          public Constructor<T> getConstructor(Class<?>... parameterTypes) 
              獲取public修飾, 指定參數類型所對應的構造方法。
              傳相應的參數類型得到有參構造方法。
      * b. 運行無參構造方法
          public T newInstance(Object... initargs) 
              使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。 
              因為是有參構造,所以傳相應的參數值。
      * c. 通過反射獲取有參構造方法並使用的代碼演示:
          package cn.itcast.demo1;
    
          import java.lang.reflect.Constructor;
    
          /*
           *  通過反射,獲取有參數的構造方法並運行
           *  方法getConstructor,傳遞可以構造方法相對應的參數列表即可
           */
          public class ReflectDemo2 {
              public static void main(String[] args)throws Exception {
                  Class c = Class.forName("cn.itcast.demo1.Person");
                  //獲取帶有,String和int參數的構造方法
                  //Constructor<T> getConstructor(Class<?>... parameterTypes)  
                  //Class<?>... parameterTypes 傳遞要獲取的構造方法的參數列表
                  Constructor con = c.getConstructor(String.class,int.class);
                  //運行構造方法
                  // T newInstance(Object... initargs)  
                  //Object... initargs 運行構造方法後,傳遞的實際參數
                  Object obj = con.newInstance("張三",20);
                  System.out.println(obj);
              }
          }
    • E. 通過反射獲取有參構造方法並使用快捷方式
      • a. 使用的前提
        類有空參的公共構造方法。(如果是同包,預設許可權也可以)
      • b. 使用的基礎
        Class類的 public T newInstance() 方法
        創建此 Class 對象所表示的類的一個新實例。
      • c. 通過反射獲取有參構造方法並使用快捷方式的代碼演示:
        package cn.itcast.demo1;
        /*
        • 反射獲取構造方法並運行,有快捷點的方式
        • 有前提:
        • 被反射的類,必須具有空參數構造方法
        • 構造方法許可權必須public
          */
          public class ReflectDemo3 {
          public static void main(String[] args) throws Exception {
          Class c = Class.forName("cn.itcast.demo1.Person");
          // Class類中定義方法, T newInstance() 直接創建被反射類的對象實例
          Object obj = c.newInstance();
          System.out.println(obj);
          }
          }
  • F. 通過反射獲取私有構造方法並使用

      * a. 得到私有的構造方法
          public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 
              獲取指定參數類型所對應的構造方法(包含私有的)。
          public Constructor<?>[] getDeclaredConstructors() 
              獲取所有的構造方法(包含私有的)。
      * b. 運行私有構造方法
          public void setAccessible(boolean flag)
              將此對象的 accessible 標誌設置為指示的布爾值。
              設置為true,這個方法保證我們得到的私有構造方法的運行。(取消運行時期的許可權檢查。)
          public T newInstance(Object... initargs) 
              使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。 
      * c. 通過反射獲取私有構造方法並使用的代碼演示:
          package cn.itcast.demo1;
    
          import java.lang.reflect.Constructor;
    
          /*
           *  反射獲取私有的構造方法運行
           *  不推薦,破壞了程式的封裝性,安全性
           *  暴力反射
           */
          public class ReflectDemo4 {
              public static void main(String[] args) throws Exception{
                  Class c = Class.forName("cn.itcast.demo1.Person");
                  //Constructor[] getDeclaredConstructors()獲取所有的構造方法,包括私有的
                  /*Constructor[] cons = c.getDeclaredConstructors();
                  for(Constructor con : cons){
                      System.out.println(con);
                  }*/
                  //Constructor getDeclaredConstructor(Class...c)獲取到指定參數列表的構造方法
                  Constructor con = c.getDeclaredConstructor(int.class,String.class);
    
                  //Constructor類,父類AccessibleObject,定義方法setAccessible(boolean b)
                  con.setAccessible(true);
    
                  Object obj = con.newInstance(18,"lisi");
                  System.out.println(obj);
              }
          }
      * 註:不推薦,破壞了程式的封裝性,安全性。
      * 
  • G. 反射獲取成員變數並改值

      * a. 獲取成員變數
          * 得到公共的成員變數
              public Field getField(String name) 
                  返回一個 Field 對象,它反映此 Class 對象所表示的類或介面的指定公共成員欄位。 
              public Field[] getFields() 
                  返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或介面的所有可訪問公共欄位。 
          * 得到所有的成員變數(包括私有的,如果要進行修改私有成員變數,要先進行public void setAccessible(boolean flag) 設置。)
              public Field getDeclaredField(String name) 
                  返回一個 Field 對象,該對象反映此 Class 對象所表示的類或介面的指定已聲明欄位。 
              public Field[] getDeclaredFields() 
                  返回 Field 對象的一個數組,這些對象反映此 Class 對象所表示的類或介面所聲明的所有欄位。 
      * b. 修改成員變數(Field)的值
          * 修改公共的成員變數
              public void set(Object obj, Object value) 
                  將指定對象變數上此 Field 對象表示的欄位設置為指定的新值。 
                  obj指的是修改的是那個對象的這個成員變數值。
      * c. 反射獲取成員變數並改值的代碼演示
          package cn.itcast.demo1;
          import java.lang.reflect.Field;
          /*
           *  反射獲取成員變數,並修改值
           *  Person類中的成員String name
           */
          public class ReflectDemo5 {
              public static void main(String[] args) throws Exception{
                  Class c = Class.forName("cn.itcast.demo1.Person");
                  Object obj = c.newInstance();
                  //獲取成員變數 Class類的方法 getFields() class文件中的所有公共的成員變數
                  //返回值是Field[]    Field類描述成員變數對象的類
                  /*Field[] fields = c.getFields();
                  for(Field f : fields){
                      System.out.println(f);
                  }*/
    
                  //獲取指定的成員變數 String name
                  //Class類的方法  Field getField(傳遞字元串類型的變數名) 獲取指定的成員變數
                  Field field = c.getField("name");
    
                  //Field類的方法 void set(Object obj, Object value) ,修改成員變數的值
                  //Object obj 必須有對象的支持,  Object value 修改後的值
                  field.set(obj,"王五");
                  System.out.println(obj);
    
              }
          }
  • H. 反射獲取空參數成員方法並運行

      * a. 獲取空參數成員方法
          * 得到公共的成員方法
              public Method getMethod(String name, Class<?>... parameterTypes) 
                  返回一個 Method 對象,它反映此 Class 對象所表示的類或介面的指定公共成員方法。 
              public Method[] getMethods()
                  返回一個包含某些 Method 對象的數組,這些對象反映此 Class對象所表示的類或介面(包括那些由該類或介面聲明的以及從超類和超介面繼承的那些的類或介面)的公共 member 方法。
          * 得到全部的成員方法(包括私有的,如果要使用私有成員方法,要先進行public void setAccessible(boolean flag) 設置。)
              public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 
                  返回一個 Method 對象,該對象反映此 Class 對象所表示的類或介面的指定已聲明方法。 
              public Method[] getDeclaredMethods() 
                  返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或介面聲明的所有方法,包括公共、保護、預設(包)訪問和私有方法,但不包括繼承的方法。 
      * b. 使用Method方法對象
          public Object invoke(Object obj, Object... args) 
              對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。 
              obj 指的是調這個方法的對象。
              args 指的是調用這個方法所要用到的參數列表。
              返回值Object就是方法的返回對象。如果方法沒有返回值 ,返回的是null.
      * c. 反射獲取空參數成員方法並運行代碼演示
          package cn.itcast.demo1;
    
          import java.lang.reflect.Method;
    
          /*
           *  反射獲取成員方法並運行
           *  public void eat(){}
           */
          public class ReflectDemo6 {
              public static void main(String[] args) throws Exception{
                  Class c = Class.forName("cn.itcast.demo1.Person");
                  Object obj = c.newInstance();
                  //獲取class對象中的成員方法
                  // Method[] getMethods()獲取的是class文件中的所有公共成員方法,包括繼承的
                  // Method類是描述成員方法的對象
                  /*Method[] methods = c.getMethods();
                  for(Method m : methods){
                      System.out.println(m);
                  }*/
    
                  //獲取指定的方法eat運行
                  // Method getMethod(String methodName,Class...c)
                  // methodName獲取的方法名  c 方法的參數列表
                  Method method = c.getMethod("eat");
                  //使用Method類中的方法,運行獲取到的方法eat
                  //Object invoke(Object obj, Object...o)
                  method.invoke(obj);
              }
          }
  • I. 反射獲取有參數成員方法並運行

      * a. 獲取有參數成員方法
          * 得到公共的成員方法
              public Method getMethod(String name, Class<?>... parameterTypes) 
                  返回一個 Method 對象,它反映此 Class 對象所表示的類或介面的指定公共成員方法。 
              public Method[] getMethods()
                  返回一個包含某些 Method 對象的數組,這些對象反映此 Class對象所表示的類或介面(包括那些由該類或介面聲明的以及從超類和超介面繼承的那些的類或介面)的公共 member 方法。
          * 得到全部的成員方法(包括私有的,如果要使用私有成員方法,要先進行public void setAccessible(boolean flag) 設置。)
              public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 
                  返回一個 Method 對象,該對象反映此 Class 對象所表示的類或介面的指定已聲明方法。 
              public Method[] getDeclaredMethods() 
                  返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或介面聲明的所有方法,包括公共、保護、預設(包)訪問和私有方法,但不包括繼承的方法。 
      * b. 使用Method方法對象
          public Object invoke(Object obj, Object... args) 
              對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。 
              obj 指的是調這個方法的對象。
              args 指的是調用這個方法所要用到的參數列表。
              返回值Object就是方法的返回對象。如果方法沒有返回值 ,返回的是null.
      * c. 反射獲取有參數成員方法並運行代碼演示
          package cn.itcast.demo1;
          import java.lang.reflect.Method;
    
          /*
           *  反射獲取有參數的成員方法並執行
           *  public void sleep(String,int,double){}
           */
          public class ReflectDemo7 {
              public static void main(String[] args) throws Exception{
                  Class c = Class.forName("cn.itcast.demo1.Person");
                  Object obj = c.newInstance();
                  //調用Class類的方法getMethod獲取指定的方法sleep
                  Method method = c.getMethod("sleep", String.class,int.class,double.class);
                  //調用Method類的方法invoke運行sleep方法
                  method.invoke(obj, "休眠",100,888.99);
              }
          }
  • J. 反射泛型擦除

      * a. 使用情況
          例如:在泛型為String的集合里,添加Integer的數據
          ArrayList<String> list = new ArrayList<String>();
          list.add(100);
      * b. 能用泛型擦除的理論
          偽泛型:在編譯後的.class文件裡面是沒有泛型的。類型為Object。
          用反射的方法繞過編譯,得到Class文件對象,直接調用add方法。
      * c. 反射泛型擦除的代碼演示
          package cn.itcast.demo2;
          import java.lang.reflect.Method;
          import java.util.ArrayList;
    
          /*
           *   定義集合類,泛型String
           *   要求向集合中添加Integer類型
           *   
           *   反射方式,獲取出集合ArrayList類的class文件對象
           *   通過class文件對象,調用add方法
           *   
           *   對反射調用方法是否理解
           */
          public class ReflectTest {
              public static void main(String[] args)throws Exception {
                  ArrayList<String> array  = new ArrayList<String>();
                  array.add("a");
                  //反射方式,獲取出集合ArrayList類的class文件對象
                  Class c = array.getClass();
                  //獲取ArrayList.class文件中的方法add
                  Method method = c.getMethod("add",Object.class);
                  //使用invoke運行ArrayList方法add
                  method.invoke(array, 150);
                  method.invoke(array, 1500);
                  method.invoke(array, 15000);
                  System.out.println(array);
    
    
              }
          }
  • K. 反射通過配置文件來決定運行的步驟

      * a. 操作依據
              通過配置文件得到類名和要運行的方法名,用反射的操作類名得到對象和調用方法
      * b. 實現步驟:
           *    1. 準備配置文件,鍵值對
           *    2. IO流讀取配置文件  Reader
           *    3. 文件中的鍵值對存儲到集合中 Properties
           *        集合保存的鍵值對,就是類名和方法名
           *    4. 反射獲取指定類的class文件對象
           *    5. class文件對象,獲取指定的方法
           *    6. 運行方法
      * c. 代碼演示
          代碼:
          package cn.itcast.demo3;
    
          import java.io.FileReader;
          import java.lang.reflect.Method;
          import java.util.Properties;
    
          /*
           *  調用Person方法,調用Student方法,調用Worker方法
           *  類不清楚,方法也不清楚
           *  通過配置文件實現此功能
           *    運行的類名和方法名字,以鍵值對的形式,寫在文本中
           *    運行哪個類,讀取配置文件即可
           *  實現步驟:
           *    1. 準備配置文件,鍵值對
           *    2. IO流讀取配置文件  Reader
           *    3. 文件中的鍵值對存儲到集合中 Properties
           *        集合保存的鍵值對,就是類名和方法名
           *    4. 反射獲取指定類的class文件對象
           *    5. class文件對象,獲取指定的方法
           *    6. 運行方法
           */
          public class Test {
              public static void main(String[] args) throws Exception{
                  //IO流讀取配置文件
                  FileReader r = new FileReader("config.properties");
                  //創建集合對象
                  Properties pro = new Properties();
                  //調用集合方法load,傳遞流對象
                  pro.load(r);
                  r.close();
                  //通過鍵獲取值
                  String className = pro.getProperty("className");
                  String methodName = pro.getProperty("methodName");
                  //反射獲取指定類的class文件對象
                  Class c = Class.forName(className);
                  Object obj = c.newInstance();
                  //獲取指定的方法名
                  Method method = c.getMethod(methodName);
                  method.invoke(obj);
              }
          }
          配置文件:
          #className=cn.itcast.demo3.Student
          #methodName=study
          className=cn.itcast.demo3.Person
          methodName=eat
          #className=cn.itcast.demo3.Worker
          #methodName=job

    作業測試

1.ArrayList list = new ArrayList();

這個泛型為Integer的ArrayList中存放一個String類型的對象

2.用反射去創建一個對象,有2種方式,儘量用代碼去體現

  1. 編寫一個類,增加一個實例方法用於列印一條字元串。
  2. 並使用反射手段創建該類的對象, 並調用該對象中的方法。

4.編寫一個類A,增加一個實例方法showString,用於列印一條字元串,

在編寫一個類TestA ,作為客戶端,用鍵盤輸入一個字元串,該字元串就是類A的全名,使用反射機制創建該類的對象,
並調用該對象中的方法showString
  1. 寫一個方法,此方法可將obj對象中名為propertyName的屬性的值設置為value.

     public void setProperty(Object obj, String propertyName, Object value){   
     }

6.定義一個標準的JavaBean,名叫Person,包含屬性name、age。

使用反射的方式創建一個實例、調用構造函數初始化name、age,使用反射方式調用setName方法對名稱進行設置,
不使用setAge方法直接使用反射方式對age賦值。

7.已知一個類,定義如下:

package com.itheima; 
public class DemoClass { 
    public void run() { 
        System.out.println("welcome to heima!"); 
    } 
} 
(1)寫一個Properties格式的配置文件,配置類的完整名稱。
(2) 寫一個程式,讀取這個Properties配置文件,獲得類的完整名稱並載入這個類,
(3)用反射 的方式運行run方法。
  1. 寫一個方法,此方法可以獲取obj對象中名為propertyName的屬性的值

     public Object getProperty(Object obj, String propertyName, Object value){ 
    
     }

答案:

1.ArrayList<Integer> list = new ArrayList<Integer>(); 
    這個泛型為Integer的ArrayList中存放一個String類型的對象
    
    package com.itheima.tests;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.HashMap;

    /*
     * 1.ArrayList<Integer> list = new ArrayList<Integer>(); 
        為這個泛型為Integer的ArrayList中存放一個String類型的對象
     */
    public class Test01 {
        public static void main(String[] args) throws Exception {
            ArrayList<Integer> list = new ArrayList<Integer>(); 
            list.add(10);
            System.out.println(list);
            //通過反射獲取ArrayList集合的位元組碼對象
            Class clazz = Class.forName("java.util.ArrayList");
            //通過反射獲取add方法
            Method addMethod = clazz.getMethod("add", Object.class);
            //通過反射調用addMethod方法
            addMethod.invoke(list, "reflect is very good!");
            System.out.println(list);
    //      HashMap<Integer,Integer> hm = new HashMap<>();
        }
    }

2.用反射去創建一個對象,有2種方式,儘量用代碼去體現

package com.itheima.tests;
import java.lang.reflect.Constructor;
/**
 * 2.用反射去創建一個對象,有2種方式,儘量用代碼去體現
 * @author JX
 *
 */
public class Test02 {
    public static void main(String[] args) throws Exception {
        //獲取Student類的位元組碼對象
        Class clazz = Class.forName("com.itheima.tests.Student");
        //1.利用反射創建一個空的對象
        Student student = (Student)clazz.newInstance();
        /*//2.獲取欄位
        Field ageField = clazz.getDeclaredField("age");
        Field nameField = clazz.getDeclaredField("name");
        //取出私有屬性
        ageField.setAccessible(true);
        nameField.setAccessible(true);
        //3.給欄位設置值
        ageField.set(student, 30);
        nameField.set(student, "張三");
        System.out.println(student);*/
        
        /*Method setAgeMethod = clazz.getMethod("setAge", int.class);
        Method setNameMethod = clazz.getMethod("setName", String.class);
        setAgeMethod.invoke(student, 38);
        setNameMethod.invoke(student, "柳岩");
        System.out.println(student);*/
        //獲取有參構造
        Constructor constructor = clazz.getConstructor(int.class,String.class);
        
        Student stu = (Student)constructor.newInstance(30,"張亮");
        System.out.println(stu);
    }
}
class Student {
    private int age;
    private String name;
    public Student() {
    }
    public Student(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Student [age=" + age + ", name=" + name + "]";
    }   
}
  1. 編寫一個類,增加一個實例方法用於列印一條字元串。
    並使用反射手段創建該類的對象, 並調用該對象中的方法。

     package com.itheima.tests;
     import java.lang.reflect.Method;
    
     /*
      * 3. 編寫一個類,增加一個實例方法用於列印一條字元串。
         並使用反射手段創建該類的對象, 並調用該對象中的方法。
      */
     public class Test03 {
         public static void main(String[] args) throws Exception {
             //獲取Demo.java的位元組碼對象
             Class clazz = Class.forName("com.itheima.tests.Demo");//obj.getClass(); Student.class
             //利用反射創建對象
             Demo demo = (Demo)clazz.newInstance();
             //利用反射獲取print方法
             Method printMethod = clazz.getMethod("print",String.class);
             printMethod.invoke(demo,"Android");
         }
     }
     class Demo {
         public Demo() {
         }
         public void print(String str ){
             System.out.println("Hello "+str);
         }

    }

4.編寫一個類A,增加一個實例方法showString,用於列印一條字元串,
在編寫一個類TestA ,作為客戶端,用鍵盤輸入一個字元串,該字元串就是類A的全名,使用反射機制創建該類的對象,並調用該對象中的方法showString

package com.itheima.tests;
import java.lang.reflect.Method;
import java.util.Scanner;

/*
 * 4.編寫一個類A,增加一個實例方法showString,用於列印一條字元串,
    在編寫一個類TestA ,作為客戶端,用鍵盤輸入一個字元串,該字元串就是類A的全名,使用反射機制創建該類的對象,
    並調用該對象中的方法showString
 */
public class Test04 {
    public static void main(String[] args) throws Exception{
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入一個類的全類名,用.隔開:");
        String className = sc.nextLine();
        
        Class clazz = Class.forName(className);//obj.getClass(); Student.class
        //利用反射創建對象
        A a = (A)clazz.newInstance();
        //利用反射獲取print方法
        Method printMethod = clazz.getMethod("showString");
        printMethod.invoke(a);      
    }
}
class A {
    public void showString() {
        System.out.println(" e m t f 明天一定通過!");
    }
}
  1. 寫一個方法,此方法可將obj對象中名為propertyName的屬性的值設置為value.

     public void setProperty(Object obj, String propertyName, Object value){   
     }
    
     package com.itheima.tests;
     import java.lang.reflect.Field;
    
     /**
      * 5. 寫一個方法,此方法可將obj對象中名為propertyName的屬性的值設置為value.   
         public void setProperty(Object obj, String propertyName, Object value){   
    
         }
      * @author JX
      *
      */
     public class Test05 {
         public static void main(String[] args) throws Exception {
             Student student = new Student(30,"張三");
             setProperty(student, "age", 25);
             System.out.println(student);
    
             Object obj = getProperty(student, "name");
             System.out.println(obj);
         }
         //給對象obj的名字為propertyName的屬性設置為value
         public static void setProperty(Object obj, String propertyName, Object value) throws Exception{   
             //1.獲取obj的位元組碼對象
             Class clazz = obj.getClass();
             //2.獲取propertyName屬性對應的Field對象
             Field propertyNameField = clazz.getDeclaredField(propertyName);
             //3.設置成可訪問的
             propertyNameField.setAccessible(true);
             //4.調用set方法給對象賦值
             propertyNameField.set(obj, value);
    
         }
         //給對象obj的名字為propertyName的屬性設置為value
         public static Object getProperty(Object obj, String propertyName) throws Exception{   
             //1.獲取obj的位元組碼對象
             Class clazz = obj.getClass();
             //2.獲取propertyName屬性對應的Field對象
             Field propertyNameField = clazz.getDeclaredField(propertyName);
             //3.設置成可訪問的
             propertyNameField.setAccessible(true);
             //4.調用get方法獲取該對象對應屬性的值
             return propertyNameField.get(obj);
         }
     }

6.定義一個標準的JavaBean,名叫Person,包含屬性name、age。

    使用反射的方式創建一個實例、調用構造函數初始化name、age,使用反射方式調用setName方法對名稱進行設置,
    不使用setAge方法直接使用反射方式對age賦值。
    
    package com.itheima.tests;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;

    /*
     * 6.定義一個標準的JavaBean,名叫Person,包含屬性name、age。
        使用反射的方式創建一個實例、調用構造函數初始化name、age,使用反射方式調用setName方法對名稱進行設置,
        不使用setAge方法直接使用反射方式對age賦值。
     */
    public class Test06 {
        public static void main(String[] args) throws Exception, SecurityException {
            //1.獲取Person類的位元組碼對象
            Class clazz = Person.class;
            //2.利用反射獲取有參構造方法
            Constructor constructor  = clazz.getConstructor(int.class,String.class);
            //3.調用構造方法,給屬性初始化
            Person person =  (Person)constructor.newInstance(30,"滅絕師太");
            System.out.println(person);
            //4.使用反射方式調用setName方法對名稱進行設置
            Method setNameMethod = clazz.getMethod("setName", String.class);
            setNameMethod.invoke(person, "張三豐");
            //5.不使用setAge方法直接使用反射方式對age賦值。
            Field ageField = clazz.getDeclaredField("age");
            ageField.setAccessible(true);
            ageField.set(person, 50);
            System.out.println(person);
        }
    }
    class Person {
        private int age;
        private String name;
        public Person() {
        }
        public Person(int age, String name) {
            super();
            this.age = age;
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Person [age=" + age + ", name=" + name + "]";
        }   
    }

7.已知一個類,定義如下:

    package com.itheima; 
    public class DemoClass { 
        public void run() { 
            System.out.println("welcome to heima!"); 
        } 
    } 
    (1)寫一個Properties格式的配置文件,配置類的完整名稱。
    (2) 寫一個程式,讀取這個Properties配置文件,獲得類的完整名稱並載入這個類,
    (3)用反射 的方式運行run方法。
    
    package com.itheima.tests;
    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.FileReader;
    import java.lang.reflect.Method;
    import java.util.Properties;

    /**
     * 7.已知一個類,定義如下: 
        package com.itheima.tests; 
        public class DemoClass { 
            public void run() { 
                System.out.println("welcome to heima!"); 
            } 
        } 
        (1)寫一個Properties格式的配置文件,配置類的完整名稱。
        (2) 寫一個程式,讀取這個Properties配置文件,獲得類的完整名稱並載入這個類,
        (3)用反射 的方式運行run方法。
     * @author JX
     *
     */
    public class Test07 {
        public static void main(String[] args) throws Exception {
            /*Properties props = new Properties();
            props.load(new FileInputStream("src/config.properties"));
            String className = (String) props.get("className");*/
            //定義字元緩衝輸入流
            BufferedReader br = new BufferedReader(new FileReader("src/config.properties"));
            String line = br.readLine();
            String className = line.split("=")[1];
    //      System.out.println(className);
            Class clazz = Class.forName(className);
            //利用反射創建一個對象
            Object obj = clazz.newInstance();
            //利用反射獲取run方法
            Method runMethod = clazz.getMethod("run");
            //利用反射調用run方法
            runMethod.invoke(obj);      
        }
    }
  1. 寫一個方法,此方法可以獲取obj對象中名為propertyName的屬性的值

     public static Object getProperty(Object obj, String propertyName, Object value){ 
    
     }
    
     package com.itheima.tests2;
     import java.lang.reflect.Field;
     public class Test08 {
         public static void main(String[] args) throws Exception {
             Person person = new Person(20,"張三");
             String name = (String)getProperty(person, "name");
             System.out.println(name);
    
         }
         public static Object getProperty(Object obj, String propertyName) throws Exception{ 
             //獲取obj對象的位元組碼文件對象
             Class clazz = obj.getClass();
             //獲取propertyName屬性所對應的欄位
             Field field = clazz.getDeclaredField(propertyName);
             //去掉私有屬性
             field.setAccessible(true);
             return field.get(obj);
         }
    
     }

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 《一統江湖的大前端》系列是自己的學習筆記,旨在介紹javascript在非網頁開發領域的應用案例和發現各類好玩的js庫,不定期更新。如果你對前端的理解還是寫寫頁面綁綁事件,那你真的是有點OUT了,前端能做的事情已經太多了, , , , , , 甚至 ,什麼火就搞什麼,絕對是專業的 蹭熱點小能手 。 ...
  • 字元串的生成轉換 你可以將任何類型的數據都轉換為字元串,你可以用下麵三種方法的任何一種: 字元串轉化為其他類型 js提供了parseInt()和parseFloat()兩個轉換函數,Number也可以實現轉化 字元的操作 字元串增刪查改 字元串比較 比較兩個字元串,比較是規則是按照字母表順序比較的 ...
  • todoList 結合之前 Vuejs 基礎與語法 使用 v-model 雙向綁定 input 輸入內容與數據 data 使用 @click 和 methods 關聯事件 使用 v-for 進行數據迴圈展示 <!DOCTYPE html> <html lang="en"> <head> <meta ...
  • 剛開始學JQuery寫的如有錯誤歡迎批評指正 JQuery擁有的選擇器可以讓我們更快更方便找到想要的元素,然後對相應的元素進行操作 簡單介紹一下一些常用的選擇器: 1.基本選擇器: 2.層級選擇器: 層級函數 3.過濾選擇器: 4.內容選擇器: 5.屬性選擇器: 6.子元素選擇器: 7.表單選擇器: ...
  • 全棧工程師也可以叫web 前端 H5主要是網站 app 小程式 公眾號這一塊 HTML篇 html(超文本標記語言,標記通用標記語言下的一個應用。) “超文本”就是指頁面內可以包含圖片、鏈接,甚至音樂、程式等非文字元素。 超文本標記語言的結構包括“頭”部分(英語:Head)、和“主體”部分(英語:B ...
  • 我主要進行對日期數據進行查看使用,有數據的顯示顏色、沒有數據可以不選 更多可以查看官方網站:http://www.daterangepicker.com/#examples ...
  • 在js中,函數本身屬於對象的一種,因此可以定義、賦值,作為對象的屬性或者成為其他函數的參數。函數名只是函數這個對象類的引用。 函數定義 從技術上講,這是一個函數表達式。但不推薦使用,因為這種語法會導致解析兩次代碼。第一次是解析常規javascript代碼,第二次解析傳入構造函數中的字元串,影響性能。 ...
  • 王之泰201771010131《面向對象程式設計(java)》第二周學習總結 第一部分:理論知識學習部分 第三章 第三章內容主要為Java語言的基礎語法,主要內容如下 1.基礎知識 1.1標識符 a)標識符可用作類名、變數名、方法名、數組名、文件名等。 註:第一個符號不能為數字,即不能用數字開頭。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...