1. 程式人生 > 實用技巧 >輕量級鎖和偏向鎖等

輕量級鎖和偏向鎖等

反射的概念及作用
什麼是反射?

Java的反射(reflection)機制是指在程式的執行狀態中,可以構造任意一個類的物件,可以瞭解任意一個物件所屬的類,可以瞭解任意一個類的成員變數和方法,可以呼叫任意一個物件的屬性和方法。這種動態獲取程式資訊以及動態呼叫物件的功能稱為Java語言的反射機制。反射被視為動態語言的關鍵(來源於百度)

JAVA 反射機制是指在執行狀態中,

  1. 對於任意一個類,都能夠知道這個類的所有屬性和方法;

  2. 對於任意一個物件,都能夠呼叫它的任意方法和屬性;

  3. 在程式執行過程中,可以操作正在執行的物件

這種動態獲取程式資訊以及動態呼叫物件的功能稱為Java語言的反射機制

反射機制的作用

Java反射機制的作用是(百度):1)在執行時判斷任意一個物件所屬的類。2)在執行時構造任意一個類的物件。3)在執行時判斷任意一個類所具有的成員變數和方法。4)在執行時呼叫任意一個物件的方法

​ Class 類與 java.lang.reflect 類庫一起對反射的概念進行了支援,該類庫包含了Field,Method,Constructor 類 (每個類都實現了 Member 介面)。這些型別的物件是由 JVM 在執行時建立的,用以表示未知類裡對應的成員。

​ 這樣你就可以使用 Constructor 建立新的物件,用 get() 和 set() 方法讀取和修改與 Field 物件關聯的欄位,用 invoke()方法呼叫與 Method 物件關聯的方法。另外,還可以呼叫 getFields()、getMethods() 和getConstructors() 等便利的方法,以返回表示欄位,方法,以及構造器的物件的陣列。這樣匿名物件的資訊就能在執行時被完全確定下來,而在編譯時不需要知道任何事情。

通過反射檢視類資訊

Java 程式中許多物件在執行時都會出現兩種型別:編譯時型別和執行時型別

例如:Person p = new Student();

這行程式碼將會生成一個變數 p,該變數的編譯型別為 Person,但執行時型別為 Student,除此之外,還有更極端的情形,程式在執行時接收到外部傳入的一個物件,該物件的編譯型別是 Object,但程式又需要呼叫該物件執行時型別的方法,為了解決這個問題,程式需要在執行時發現物件和類的真實資訊,方法有兩種:

第一種是假設在編譯和執行時都完全知道型別的具體資訊,在這種情況下,我們可以直接先使用instance of 運算子進行判斷,再利用強制型別轉換將其轉換成執行時型別的變數即可

第二種是編譯時根本無法預知該物件和類的資訊,程式只依靠執行時資訊來發現該物件和類的真實資訊,這就必須使用反射

獲取Class物件

​ Java中每個類被載入之後,系統就會為該類生成一個對應的Class物件,通過Class物件就可以訪問到載入到JVM(Java虛擬機器)中的這個類的所有資訊,一旦獲得某個類所對應的 Class物件之後,程式就可以呼叫 Class 物件的方法來獲得該物件和該類的真實資訊了

Java程式獲得Class物件的三種方式:

  1. Class.forName( )方法。該方法需要傳入字串引數,這個字串引數的值是某個類的類名(必須新增完整包名)

  2. 呼叫某個類的 class 屬性來獲取對於的 Class 物件

  3. 呼叫某個物件(Object)的 getClass 方法。該方法將返回該物件所屬類對於的 Class 物件

public class Demo1 {
      public static void main(String[] args) throws ClassNotFoundException {
          //通過forName方法獲取class物件 forName需要丟擲一個異常
          Class aClass = Class.forName("com.gxy.java.entity.Student");
          System.out.println("forName方法獲取" + aClass);
          //通過class屬性獲取class物件
          Class<Student> studentClass = Student.class;
          System.out.println("class屬性獲取" + studentClass);
          //通過某個物件的 getClass 方法獲取對應的 Class 物件
          Student stu = new Student();
          Class class2 = stu.getClass();
          System.out.println("某個物件的getClass方法獲取" + class2);
      }
  }

執行結果:

forName方法獲取class com.gxy.java.entity.Student
class屬性獲取class com.gxy.java.entity.Student
某個物件的getClass方法獲取class com.gxy.java.entity.Student
從Class中獲取資訊

Class 類提供了大量方法,這些方法可以讓我們訪問 Class 物件對應類的詳細資訊

1. 訪問 Class 對應類所包含的構造器(Constructor):

  • Constructor getConstructor(Class...parameterTypes):返回 Class 物件對應類的指定引數的public 構造器。

  • Constructor[] getConstructors():返回 Class 物件對應類的所有 public 構造器。

  • Constructor getDeclaredConstructor(Class...parameterTypes):返回 Class 物件對應類的指定引數的構造器,與構造器訪問級別無關。

  • Constructor[] getDeclaredConstructors():返回 Class 物件對應類的所有構造器,與構造器訪問級別無關

 import java.lang.reflect.Constructor;
  ​
  public class Person {
      private Person(){
          System.out.println("這是無參構造器");
      }
      public Person(String name){
          System.out.println("這是一個有參構造器");
      }
      public Person(String name,int age){
          System.out.println("這是有參構造器二號");
      }
      public static void main(String[] args) throws NoSuchMethodException {
          //獲取class物件
          Class<Person> clazz = Person.class;
          //獲取person類的引數型別為String的public構造器
          Constructor<Person> con = clazz.getConstructor(String.class);
          System.out.println("person類的引數型別為String的public構造器是:\n" + con);
          System.out.println("-----------------------------------------");
          //獲取person類中所有的public構造器
          Constructor[] persons = clazz.getConstructors();
          //遍歷出集合中的所有資料
          for (Constructor c: persons) {
              System.out.println("person類public構造器是" + c);
          }
          System.out.println("-------------------------------------------");
          //獲取person類中的所有構造方法
          Constructor[] cons = clazz.getDeclaredConstructors();
          for (Constructor x: cons) {
              System.out.println("獲取person類中的所有構造方法有" + x);
          }
      }
  }

執行結果:

 person類的引數型別為String的public構造器是:
  public com.gxy.java.Person(java.lang.String)
  -----------------------------------------
  person類public構造器是public com.gxy.java.Person(java.lang.String,int)
  person類public構造器是public com.gxy.java.Person(java.lang.String)
  -------------------------------------------
  獲取person類中的所有構造方法有public com.gxy.java.Person(java.lang.String,int)
  獲取person類中的所有構造方法有public com.gxy.java.Person(java.lang.String)
  獲取person類中的所有構造方法有private com.gxy.java.Person()

2. 訪問class對應類所包含的方法(Method):

  • Method getMethod(String name, Class... parameterTypes) :返回 Class 對應類的指定 public 方法。

  • Method[] getMethods() :返回 Class 對應類的所有 public 方法。

  • Method getDeclaredMethod(String name, Class... parameterTypes) :返回 Class 對應類的指定方法,與訪問級別無關。

  • Method[] getDeclaredMethods() :返回 Class 對應類的所有方法,與訪問級別無關。

 import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;
  import java.lang.reflect.Method;
  ​
  public class Student {
      private Student(){
          System.out.println("這是一個無參構造器");
      }
      public Student(String name){
          System.out.println("這是一個有參構造器");
      }
      public void info(){
          System.out.println("執行無參info方法");
      }
      public void info(String name){
          System.out.println("執行有參info方法");
      }
      public static void main(String[] args) throws NoSuchMethodException {
          //獲取student類
          Class<Student> student = Student.class;
          //獲取類中的所有方法
          Constructor<?>[] students = student.getDeclaredConstructors();
          //遍歷方法
          for (Constructor c: students) {
              System.out.println("Student類中定義的方法有" + c);
          }
          //獲取Class對應類指定的public方法
          Method info = student.getMethod("info", String.class);
          System.out.println("student定義了帶字串型別引數的 info 方法:\n" + info);
      }
  }

執行結果:

Student類中定義的方法有private com.gxy.java.Student()
  Student類中定義的方法有public com.gxy.java.Student(java.lang.String)
  student定義了帶字串型別引數的 info 方法:
  public void com.gxy.java.Student.info(java.lang.String)

3. 訪問 Class 對應類所包含的欄位(Field):

➢ Filed getField(String name) :返回 Class 對應類的指定 public 屬性。

➢ Filed[] getFields() :返回 Class 對應類的所有 public 屬性。

➢ Field getDeclaredField(String name) :返回 Class 對應類的指定屬性,與訪問級別無關。

➢ Field[] getDeclaredField s() :返回 Class 對應類的所有屬性,與訪問級別無關

import lombok.AllArgsConstructor;
  import lombok.Data;
  import lombok.NoArgsConstructor;
  ​
  import java.lang.reflect.Field;
  ​
  @AllArgsConstructor
  @NoArgsConstructor
  @Data
  public class Student {
      private Integer id;
      public String name;
      public static void main(String[] args) throws NoSuchFieldException {
          //獲取class類
          Class student = Student.class;
          //獲取class對應類中的所有屬性返回 與訪問級別無關
          Field[] fields = student.getDeclaredFields();
          for (Field f: fields) {
              System.out.println("student的屬性有 " + f);
          }
          //獲取class對應類指定的public屬性
          Field field = student.getField("name");
          System.out.println("student類中屬性為public的為" + field);
          //獲取所有屬性為public的值
          Field[] fields1 = student.getFields();
          for (Field f1: fields1) {
              System.out.println("類中屬性為public的有" + f1);
          }
          //返回 Class 對應類的指定屬性,與訪問級別無關
          Field id = student.getDeclaredField("id");
          System.out.println("student類中id的值為" + id);
      }
  }

4. 訪問 Class 對應類所包含的註解(Annotation)

<A extends Annotation> A getAnnotation(Class<A> annotationClass):試圖獲取該 Class 對應類指定型別的註解,如果該型別的註解不存在則返回 null。

➢ Annotation [] getAnnotations():返回此元素上存在的所有註解。

➢ Annotation [] getDeclaredAnnotations():返回直接存在於此元素上的所有註解

//宣告一個簡單的controller
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RestController;
  //告訴編譯器忽略指定的警告,不用在編譯完成後出現警告資訊
  @SuppressWarnings("unchecked")
  @RestController
  public class HelloWordController {
      @RequestMapping("/sayHello")
      public String sayHello(){
          return "歡迎來到Java反射機制的學習";
      }
  }
  
  //test測試類
  package com.gxy.java;
  import org.junit.Test;
  import java.lang.annotation.Annotation;
  ​
  public class Demo2_test {
      //來自junit包 要匯入對應的依賴
      @Test
      public void test(){
          //獲取到HelloWordController類
          Class hello = HelloWordController.class;
          //獲取HelloWordController類在執行時的註解
          Annotation[] annotations = hello.getAnnotations();
          //遍歷拿出所有的註解
          for (Annotation a: annotations) {
              System.out.println("HelloWorldController 類上存在的註解有:" + a);
          }
          //獲取 Class 對應類指定型別的註解
          Annotation annotation = hello.getAnnotation(HelloWordController.class);
          System.out.println("HelloWorldController 類 Property 型別的註解是:\n" + annotation);
      }
  }
  /**
  * 上面的程式訪問 HelloController 類上存在的所有註解資訊時,沒有訪問到@SuppressWarnings,
  * 因為這個註解並不是執行註解,所以無法通過反射訪問
  */

執行結果:

 HelloWorldController 類上存在的註解有:@org.springframework.stereotype.Controller(value=)
  HelloWorldController 類 Property 型別的註解是:
  null

5. 訪問 Class 對應類所包含的其他成員

➢ Class[] getDeclaredClasses():返回 Class 對應類的全部內部類。

➢ Class[] getClasses():返回 Class 對應類的全部 public 內部類。

➢ Class<?> getDeclaringClass():返回 Class 對應類的外部類。

➢ Class[] getInterfaces():返回 Class 對應類所實現的全部介面。

➢ int getModifiers():返回 Class 對應類或介面的所有修飾符。修飾符由 public、protected、private、final、static、abstract 等對應的常量組成,返回的整數應使用 Modifier 工具類的方法來解碼,才可以獲得真實的修飾符。

➢ Package getPackage():獲取此類的包。

➢String getName():返回 Class 對應類的名稱。

➢ String getSimpleName():返回 Class 對應類的簡稱。

➢ Class<? super T> getSuperClass():返回 Class 對應類的父類的對應 Class 物件。


使用反射生成物件並操作物件

Class 物件可以獲得該類裡包括的方法(Method)、構造器(Constructor)、屬性(Field)等成員,這就意味著程式可以通過 Method 物件來執行對應的方法,通過 Constructor 物件來呼叫對應的構造器建立物件,通過 Field 物件直接訪問並修改物件的屬性值

import java.lang.reflect.Constructor;
  ​
  public class Demo3{
      //異常直接丟擲頂級父類 不用多次丟擲
      public static void main(String[] args) throws Exception {
          Class aClass = Class.forName("java.lang.StringBuffer");
          //獲取StringBuffer中帶字串引數的構造器
          Constructor constructor = aClass.getConstructor(String.class);
          //通過構造器的newInstance方法建立物件
          Object instance = constructor.newInstance("這是一個初始化字元");
          System.out.println(instance);
      }
  }

1. 建立物件

反射機制生成物件有兩種方式:通過第一種方式來建立物件是比較常見的情形,因為在很多 Java EE 框架中都需要根據配置檔案資訊來建立 Java 物件,從配置檔案讀取的只是某個類的字串類名,程式通過反射來建立對應例項

​ ➢ 使用 Class 物件的 newInstance()方法來建立該 Class 物件對應類的例項,這種方式要求該 Class 物件的對應類有預設構造器,而執行 newInstance()方法時實際上是利用預設構造器來建立該類例項。

​ ➢ 先使用 Class 物件獲取 Constructor 物件,再呼叫 Constructor 物件的 newInstance()方法來建立該Class 物件對應類的例項。通過這種方式可以選擇使用某個類的指定構造器來建立例項

import java.io.FileInputStream;
  import java.text.SimpleDateFormat;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Properties;
  /**
  * 這個程式根據配置檔案呼叫 Class 物件的 newInstance 方法建立 Java 物件,並將這些物件放入物件池中然  *後根據存入池中的 name 取出物件。這種使用配置檔案來配置物件,然後由程式根據配置檔案來建立物件的方式
  * 非常有用,鼎鼎大名的 Spring 框架就是採用這種方式大大簡化了 JavaEE 應用的開發,當然,Spring 採用的
  *是資訊豐富的 XML 配置檔案。
   */
  public class ObjectPoolFactory {
      //定義一個map集合
      private Map<String,Object> map = new HashMap<String,Object>();
      //定義一個建立物件的方法,該方法只要傳入一個字串類名,程式可以根據該類名生成 Java 物件
      private Object createObject(String className) throws Exception{
          //根據字串來獲取對應的class物件
          Class aClass = Class.forName(className);
          //使用 aClass 對應類的預設構造器建立例項
          //newInstance依賴於構造方法,沒有構造方法不能建立成功
          return aClass.newInstance();
      }
      public void initPool(String fileName){
          // FileInputStream流被稱為檔案位元組輸入流
          // 意思指對檔案資料以位元組的形式進行讀取操作如讀取圖片視訊等
          FileInputStream fis = null;
          try {
              //需要讀取檔名稱
              fis = new FileInputStream(fileName);
              //新建一個Properties 用於讀取Java配置檔案
              Properties pro = new Properties();
              //從輸入流中讀取屬性列表
              pro.load(fis);
              for (String name:pro.stringPropertyNames()) {
                  //建立物件並新增到map集合中
                  map.put(name,createObject(pro.getProperty(name)));
              }
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
              try {
                  //如果當前的位元組流裡面存在資料
                  if(fis != null){
                      //關閉這個位元組流
                      fis.close();
                  }
              } catch (Exception e){
                  e.printStackTrace();
              }
          }
      }
      public Object getObject(String name){
          //從map集合中取出物件
          return map.get(name);
      }
      public static void main(String[] args) {
          //宣告一個物件池工廠
          ObjectPoolFactory pool = new ObjectPoolFactory();
          //給出要讀取檔案的路徑
          pool.initPool("src\\main\\resources\\obj.txt");
          //宣告要讀取配置檔案中的屬性
          Object a = pool.getObject("a");
          //格式化時間格式
          SimpleDateFormat sdf =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
          //輸入所讀取到的資料
          System.out.println("獲取當前時間為:" + sdf.format(a));
      }
  }
配值檔案:
a = java.util.Date
b = javax.swing.JFrame

執行結果:

  獲取當前時間為:2020-10-06 15:41:39

2. 呼叫方法

​ 當獲得某個類的 Class 物件後,就可以通過 Class 物件的 getMethods 方法或者 getMethod 方法來獲取全部方法(Method 物件陣列)或指定方法(Method 物件,獲得 Method 物件後,程式就可以通過 Method物件的 invoke()方法呼叫目標物件的方法

​ 下面程式對前面的物件池工廠進行加強,程式允許在配置檔案增加配置物件的屬性值,物件池工廠會讀取該物件的屬性值,並利用該物件的 setter 方法為對應屬性設定值

import com.sun.org.apache.xml.internal.utils.ObjectPool;
  ​
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.IOException;
  import java.lang.reflect.Method;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Properties;
  ​
  //通過反射實現對 Person 類的 setName 方法的呼叫
  public class ExtendedObjectPoolFactory {
      //初始化一個map集合
      private Map<String,Object> map = new HashMap<String, Object>();
      //從屬性檔案中初始化properties屬性
      Properties config = new Properties();
      //宣告一個方法
      public void init(String fileName){
          //初始化FileInputStream變數
          FileInputStream fis = null;
          try {
              fis = new FileInputStream(fileName);
              config.load(fis);
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
              try {
                  if(fis != null){
                      fis.close();
                  }
              } catch (Exception e){
                  e.printStackTrace();
              }
          }
      }
      public Object createObject(String className) throws Exception{
          //根據字串獲取對應class物件
          Class<?> aClass = Class.forName(className);
          //使用預設構造器建立物件
          return aClass.newInstance();
      }
      //根據配置檔案初始化物件池
      public void initPool() throws Exception {
          for (String name : config.stringPropertyNames()){
              //每取出一個屬性名-屬性值對時,如果屬性名中不包含%,就根據屬性值建立一個物件
              if(!name.contains("%")){
                  map.put(name,createObject(config.getProperty(name)));
              } else {
                  //將配置檔案中的屬性按照%分割
                  String[] split = name.split("%");
                  //取出要設定屬性的目標物件
                  Object target = getObject(split[0]);
                  //設定該屬性的對應的setter方法名
                 String setName = "set" + split[1].substring(0,1).toUpperCase()
                                   +split[1].substring(1);
                  //獲取target對應的class物件
                  Class<?> targetClass = target.getClass();
                  //獲取改屬性對應的setter方法
                  Method m = targetClass.getMethod(setName, String.class);
                  //呼叫 Method 物件的 invoke 方法執行 setter 方法
                  //invoke 的第一個引數表示目標物件,第二個引數表示呼叫時傳入的實參
                  m.invoke(target,config.getProperty(name));
              }
          }
      }
      public Object getObject(String name) {
          return map.get(name);
      }
      public static void main(String[] args) throws Exception {
          ExtendedObjectPoolFactory epf = new ExtendedObjectPoolFactory();
          epf.init("src\\main\\resources\\object.txt");
          epf.initPool();
          System.out.println("這是一個配置檔案" + epf.getObject("a"));
      }
  }
//測試類
  public class Demo4 {
  ​
      private String name;
      public String getName(){
          return name;
      }
      public void setName(String name) {
          this.name = name;
          System.out.println("setName方法呼叫了:" + name);
      }
  }
配置檔案:
#要寫自己的測試類所在位置
a = com.gxy.java.Demo4
#set the name of a
a%name = Test Name

執行結果:

  setName方法呼叫了:Test Name
這是一個配置檔案com.gxy.java.Demo4@4a574795

3. 訪問屬性值

通過 Class 物件的 getFields()和 getField()方法可以獲得該類所包含的全部 Filed 物件陣列或指定Filed 物件

Filed 提供了兩種方法來訪問屬性:

​ ➢ getXxx(Object obj):獲取 obj 物件的屬性值。此處 Xxx 對應 8 個基本型別,如果是 引用型別則取消get 後面的 Xxx。

​ ➢ setXxx(Object obj , Xxx val):將 obj 物件的屬性值設定成 val。此處 Xxx 表示 8 個基本型別,如果是引用型別則取消 set 後面的 Xxx。

  
import java.lang.reflect.Field;
  import java.lang.reflect.Method;
  ​
  class User {
      public String name;
      private int age;
      private void print(){
          System.out.println("姓名:"+name+"\n年齡:"+age);
      }
  }
  public class Demo5 {
      public static void main(String[] args) throws Exception {
          //通過User獲取對應的Class物件
          Class<User> userClass = User.class;
          //使用反射建立User例項
          User user = userClass.newInstance();
          //獲取user類的name
          Field name = userClass.getField("name");
          //通過例項修改
          name.set(user,"莫離歡");
          //獲取user類的private屬性age
          Field age = userClass.getDeclaredField("age");
          //通過反射訪問該屬性時取消訪問許可權檢查
          //true是關閉 false是開啟,預設是false開啟狀態
          age.setAccessible(true);
          //設定age屬性
          age.set(user,18);
          //獲取user類的私有方法print方法
          Method print = userClass.getDeclaredMethod("print");
          //設定通過反射訪問該屬性時取消許可權檢查
          print.setAccessible(true);
          //啟用方法 -- 類似於打點呼叫
          //引數:obj給哪個物件啟用方法 args:這個方法需要的引數
          print.invoke(user);
      }
  }

執行結果:

  姓名:莫離歡
  年齡:18
動態代理

1. 代理模式

​ 代理模式是常用的 java 設計模式,他的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等;代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物件關聯,代理類的物件本身並不真正實現服務,而是通過呼叫委託類的物件的相關方法,來提供特定的服務

​ 比如你要去銀行取錢,你就是委託人,你委託銀行的僱員(代理人)幫你辦理取錢的業務。你和銀行僱員的關聯關係是:表面上是銀行僱員取錢,但實際上是你在取錢,僱員只是為你提供取錢的服務

2.動態代理

​ 在 Java 的 java.lang.reflect 包下提供了一個 Proxy 類和一個 Invocationhandler 介面。這個類和介面是實現動態代理所必須用到的

1) Invocationhandler 介面:

​ 每一個動態代理類都必須要實現 InvocationHandler 介面,並且每個代理類的例項都關聯到了一個handler,當我們通過代理物件呼叫一個方法的時候,這個方法的呼叫就會被轉發為由 InvocationHandler這個介面的 invoke 方法來進行呼叫

  
Object invoke(Object proxy, Method method, Object[] args)

引數解析:

​ ➢ Object proxy:指被代理的物件

​ ➢ Method method:要呼叫的方法

​ ➢ Object[] args:方法呼叫時所需的實參

System.out.println("引數一:被指帶的物件:" + proxy.getClass()
                     + "\n引數二:呼叫的方法method" + method.getName()
                     + "\n引數三:所傳入的引數args" + args[0]);  
  引數一:被指帶的物件:class com.sun.proxy.$Proxy0
  引數二:呼叫的方法methodpay
  引數三:所傳入的引數args大房間

2) Proxy 類

​ Proxy 類提供了一個建立動態代理物件的方法,該方法定義如下:

  
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
                                      InvocationHandler h)

引數解析:

➢ ClassLoader loader:類載入器,定義了由哪個 ClassLoader 物件來對生成的代理物件進行載入。

➢ Class<?>[] interfaces:代理類要實現的全部介面。

➢ InvocationHandler h:表示代理物件要關聯的 InvocationHandler 物件。

  Object o = Proxy.newProxyInstance(
                  consumer.getClass().getClassLoader(),//類載入器 ClassLoader loader
                  consumer.getClass().getInterfaces(),//要實現的介面 Class<?>[] interfaces
                  new InvocationHandler()//關聯的 InvocationHandler 物件 {
                      @Override
                      public Object invoke(Object proxy, Method method, Object[] args){
                          return null;
                      }
                  }
          );

租房案例:

  1. 定義一個介面

public interface ZuFang {
      //付款方法
      String pay(String claim);
  }
  1. 寫這個介面的實現類

package com.gxy.java.dyx;
  ​
  public class Consumer implements ZuFang {
      @Override
      public String pay(String claim) {
          return "完成要求" + claim + "-----付款成功";
      }
  }
  1. 寫測試類

import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
  import java.lang.reflect.Proxy;
  ​
  public class Test {
      public static void main(String[] args) {
          final Consumer consumer = new Consumer();
  ​
          ZuFang o = (ZuFang) Proxy.newProxyInstance(
                  consumer.getClass().getClassLoader(),//類載入器
                  consumer.getClass().getInterfaces(),//介面
                  new InvocationHandler() {
                      @Override
                      public Object invoke(Object proxy, Method method, Object[] args)
                          throws Throwable {
                          
                          System.out.println("我是中介,我可以幫你選房....");
                          Object invoke = method.invoke(consumer, args);
                          System.out.println("房間已按照您的要求" + args[0] + "選擇完畢,請付款");
                          return invoke;
                      }
                  }
          );
          System.out.println(o.pay("大房間"));
      }
  }
本章總結
  1. 反射機制指的是程式在執行時能夠獲取自身的資訊。在 java 中,只要給定類的名字,那麼就可以通過反射機制來獲得類的所有資訊。

  1. 可以實現動態建立物件和編譯,體現出很大的靈活性,特別是在 J2EE 的開發中它的靈活性就表現的十分明顯,但是對效能有所影響。

  1. 反射機制就是專門幫我們做那些重複的有規則的事情,所以現在很多的自動生成程式碼的軟體就是運用反射機制來完成的。

  1. 代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等