反射

Prerequisites:

反射有包含以下四種。

  • java.lang.Class 代表類別物件
  • java.lang.reflect.Method 成員方法
  • java.lang.reflect.Constructor 建構子
  • java.lang.reflect.Field 成員變數(屬性)

使用反射建立物件

  • newInstance(): 呼叫沒有參數的「public」建構子。
    Object obj1 = fish_clz.newInstance();
    
  • getConstructor(Class… clazz): 參數是Class類別,呼叫類型與數量對映「public」有參數的建構子,參數…是可變參數。
    Constructor constructor = fish_clz.getConstructor(String.class);
    Object obj2 = constructor.newInstance("Bill");
    
  • getDecalaredConstructor(Class… clazz): 參數是Class類別,呼叫類型與數量對映「public 或 private」有參數的建構子,參數…是可變參數。
    // 使用private私有 有參數 建構子
    Constructor constructor1 = fish_clz.getDeclaredConstructor(String.class, int.class);
    // 修改存取權限變成public
    constructor1.setAccessible(true);
    Object obj3 = constructor1.newInstance("Mary", 10);
    

魚的類別

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Fish {
  public String name;
  private int age;

  public Fish() {}

  public Fish(String name) {
    this.name = name;
  }

  // 私有
  private Fish(String name, int age) {
    this.age = age;
    this.name = name;
  }

  @Override
  public String toString() {
    return "Fish{" +
        "name='" + name + '\'' +
        ", age=" + age +
        '}';
  }
}

完整程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectTest4 {
  public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    // 取得class
    Class fish_clz = Class.forName("reflect.Fish");
    // 使用public 無參數 建構子 建立物件
    Object obj1 = fish_clz.newInstance();
    System.out.println("obj1 = " + obj1);
    // 使用public 有參數 建構子 建立物件
    Constructor constructor = fish_clz.getConstructor(String.class);
    Object obj2 = constructor.newInstance("Bill");
    System.out.println("obj2 = " + obj2);
    // 使用private私有 有參數 建構子
    Constructor constructor1 = fish_clz.getDeclaredConstructor(String.class, int.class);
    // 修改存取權限變成public
    constructor1.setAccessible(true);
    Object obj3 = constructor1.newInstance("Mary", 10);
    System.out.println("obj3 = " + obj3);
  }
}
obj1 = Fish{name='null', age=0}
obj2 = Fish{name='Bill', age=0}
obj3 = Fish{name='Mary', age=10}

反射取得成員變數

以下有public、private、static成員變數。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Fish {
  // public
  public String name = "Default";
  // private
  private int age = 0;
  // private + static
  private static int weight = 0;
  public Fish() {
  }

  public Fish(String name) {
    this.name = name;
  }

  private Fish(String name, int age) {
    this.age = age;
    this.name = name;
  }

  @Override
  public String toString() {
    return "Fish{" +
        "name='" + name + '\'' +
        ", age=" + age +
        '}';
  }
}

取得成員變數的方法:

  • getField(): 取得public的成員變數。
  • getDeclaredField(): 取得public 與 private成員變數。

設定屬性

屬性名.set(物件,值);
age.set(obj1, 30);

取得屬性

屬性名.get(物件);
age.get(obj1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class ReflectTest4 {
  public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
    // 取得class
    Class fish_clz = Class.forName("reflect.Fish");
    // 使用public 無參數 建構子 建立物件
    Object obj1 = fish_clz.newInstance();

    // public
    Field name = fish_clz.getField("name");
    System.out.println("name = " + name.get(obj1));
    name.set(obj1, "Alice");
    System.out.println("After changed name = " + name.get(obj1));
    // private
    Field age = fish_clz.getDeclaredField("age");
    age.setAccessible(true);
    System.out.println("age = " + age.get(obj1));
    age.set(obj1, 30);
    System.out.println("After changed age = " + age.get(obj1));
    // private + static
    Field weight = fish_clz.getDeclaredField("weight");
    weight.setAccessible(true);
    System.out.println("weight = " + weight.get(null));
    weight.set(null, 100);
    System.out.println("After changed weight = " + weight.get(null));
  }
}
name = Default
After changed name = Alice
age = 0
After changed age = 30
weight = 0
After changed weight = 100

反射呼叫成員方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Fish {
  public Fish() {
  }
  // public 方法
  public String method1(String name, int age) {
    return "public method = " + name + age;
  }
  // private 方法
  private String method2(String name, int age) {
    return "private method = " + name + age;
  }
  // static 方法
  private static int method3(int age) {
    return age;
  }
}

取得public method 無參數

Method 方法變數 = class物件.getMethod("方法名");
Method method1 = fish_clz.getMethod("method1");

呼叫方法

Object 變數 = 方法變數.invoke(物件);
Object rtn1 = method1.invoke(obj1);
1
2
3
4
class Fish {
  public void method1_public() {
    System.out.println("method1_public");
  }
1
2
3
4
5
// 取得class
Class clazz = Class.forName("reflect.Fish");
Object obj1 = clazz.newInstance();
Method method1 = clazz.getMethod("method1_public");
method1.invoke(obj1);
method1_public

取得public method

Method 方法變數 = class物件.getMethod("方法名", 參數Class物件);
Method method1 = fish_clz.getMethod("method1", String.class, int.class);

呼叫方法

Object 變數 = 方法變數.invoke(物件, "參數1", 參數2);
Object rtn1 = method1.invoke(obj1, "Mary", 10);

Object是return的類型,固定傳回Object父類別。
但執行時期的類型是真正方法定義的類型,以本例來說,對傳回值使用getClass(),會取得傳回值實際執行的類型。

System.out.println(rtn1.getClass());

執行結果為class java.lang.String

完整程式碼

1
2
3
4
5
6
7
8
9
10
11
12
// 取得class
Class fish_clz = Class.forName("reflect.Fish");
// 使用public 無參數 建構子 建立物件
Object obj1 = fish_clz.newInstance();
// 取得public 方法
Method method1 = fish_clz.getMethod("method1", String.class, int.class);
// 呼叫方法 取得傳回值,傳回值固定Object類型
Object rtn1 = method1.invoke(obj1, "Mary", 10);
// getClass取得傳回值實際類型
System.out.println(rtn1.getClass());
// 輸出結果
System.out.println(rtn1);
class java.lang.String
public method = Mary10

取得private method

Method 方法變數 = class物件.getDeclaredMethod("方法名", 參數Class物件);
Method method2 = fish_clz.getDeclaredMethod("method2", String.class, int.class);

使用方法前,要先把private存取權限設為public。

method2.setAccessible(true);

再如之前一樣,呼叫方法。

完整程式碼

1
2
3
4
5
6
7
8
9
// 取得class
Class fish_clz = Class.forName("reflect.Fish");
// 使用public 無參數 建構子 建立物件
Object obj1 = fish_clz.newInstance();
Method method2 = fish_clz.getDeclaredMethod("method2", String.class, int.class);
method2.setAccessible(true);
Object rtn = method2.invoke(obj1, "Mary", 10);
System.out.println(rtn.getClass());
System.out.println(rtn);
class java.lang.String
private method = Mary10

取得staic method

語法,呼叫方法的時候,可以把物件變成null,因為static方法是類別方法,不用使用物件也可以呼叫。

Object 變數 = 方法變數.invoke(null, "參數1", 參數2);
Object rtn1 = method1.invoke(null, "Mary", 10);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ReflectTest4 {
  public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
    // 取得class
    Class fish_clz = Class.forName("reflect.Fish");
    // public
    Object obj1 = fish_clz.newInstance();
    Method method3 = fish_clz.getDeclaredMethod("method3", int.class);
    method3.setAccessible(true);
    // 呼叫static方法
    Object rtn = method3.invoke(null,  10);
    System.out.println(rtn.getClass());
    System.out.println(rtn);
  }
}
class java.lang.Integer
10

透過反射取得類別的結構

使用先前的Fish類別。

取得package套件路徑 與 類別名

1
2
3
4
5
6
7
8
// 取得class
Class clazz = Class.forName("reflect.Fish");
// 取得package
System.out.println(clazz.getPackage());
// 取得package + 類別名
System.out.println(clazz.getName());
// 取得類別名
System.out.println(clazz.getSimpleName());
reflect
reflect.Fish
Fish

共用方法

  • getName() 可以取得屬性名、方法名、建構子名
  • getType() 取得屬性的類型
  • getModifiers() 取得存取權限
存取權限 編號
public 1
private 2
protected 4
static 8
final 16

若有二個存取權限,則是相加,以下public是1 + staic 8 = 9

public static String name;

取得屬性

父類別是Animal,子類別是Fish。

1
2
3
4
5
6
7
8
9
10
class Animal {
  public String type;
  private String color;
}
class Fish extends Animal{
  public String name;
  private String age;
  public Fish() {
  }
}

取得public屬性,包含父類別

除了獲取本身的public成員變數(屬性),也可以獲取父類別public的成員屬性。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ReflectTest4 {
  public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
    // 取得class
    Class clazz = Class.forName("reflect.Fish");
    Field[] fields = clazz.getFields();
    for (Field field : fields) {
      System.out.println("===================");
      System.out.println("屬性名 = " + field.getName());
      System.out.println("屬性類別 = " + field.getType());
      System.out.println("屬性權限 = " + field.getModifiers());
    }
  }
}
===================
屬性名 = name
屬性類別 = class java.lang.String
屬性權限 = 1
===================
屬性名 = type
屬性類別 = class java.lang.String
屬性權限 = 1

取得類別public private全部屬性 不包含父類別

1
2
3
4
5
6
7
8
9
// 取得class
Class clazz = Class.forName("reflect.Fish");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
  System.out.println("===================");
  System.out.println("屬性名 = " + field.getName());
  System.out.println("屬性類別 = " + field.getType());
  System.out.println("屬性權限 = " + field.getModifiers());
}
===================
屬性名 = name
屬性類別 = class java.lang.String
屬性權限 = 1
===================
屬性名 = age
屬性類別 = class java.lang.String
屬性權限 = 2

取得方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Animal {
  public String type;
  private String color;

  public void fmethod1_public() {}

  public void fmethod2_prive() {}
}

class Fish extends Animal {
  public String name;
  private String age;

  public void method1_public() {}

  public void method2_prive() {}
}

取得public方法(包含父類別)

  • getReturnType() 取得方法傳回值類型
  • getParameterTypes() 參數類型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ReflectTest4 {
  public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
    // 取得class
    Class clazz = Class.forName("reflect.Fish");
    Method[] methods = clazz.getMethods();
    for (Method method : methods) {
      System.out.println("===================");
      System.out.println("方法名 = " + method.getName());
      System.out.println("傳回類別 = " + method.getReturnType());
      System.out.println("存取權限 = " + method.getModifiers());
      Class<?>[] parameterTypes = method.getParameterTypes();
      for (Class<?> parameterType : parameterTypes) {
        System.out.println("參數類型 = " +parameterType);
      }
    }
  }
}
===================
方法名 = method1_public
傳回類別 = void
存取權限 = 1
===================
方法名 = method2_prive
傳回類別 = void
存取權限 = 1
===================
方法名 = fmethod1_public
傳回類別 = void
存取權限 = 1
===================
方法名 = fmethod2_prive
傳回類別 = void
存取權限 = 1
===================
方法名 = equals
傳回類別 = boolean
存取權限 = 1
參數類型 = class java.lang.Object
===================
方法名 = toString
傳回類別 = class java.lang.String
存取權限 = 1
===================
方法名 = hashCode
傳回類別 = int
存取權限 = 257
===================
方法名 = getClass
傳回類別 = class java.lang.Class
存取權限 = 273
===================
方法名 = notify
傳回類別 = void
存取權限 = 273
===================
方法名 = notifyAll
傳回類別 = void
存取權限 = 273
===================
方法名 = wait
傳回類別 = void
存取權限 = 17
參數類型 = long
===================
方法名 = wait
傳回類別 = void
存取權限 = 17
參數類型 = long
參數類型 = int
===================
方法名 = wait
傳回類別 = void
存取權限 = 17

取得類別public private方法(不包含父類別)

1
2
3
4
5
6
7
8
9
10
11
12
13
// 取得class
Class clazz = Class.forName("reflect.Fish");
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
  System.out.println("===================");
  System.out.println("方法名 = " + method.getName());
  System.out.println("傳回類別 = " + method.getReturnType());
  System.out.println("存取權限 = " + method.getModifiers());
  Class<?>[] parameterTypes = method.getParameterTypes();
  for (Class<?> parameterType : parameterTypes) {
    System.out.println("參數類型 = " +parameterType);
  }
}
===================
方法名 = method1_public
傳回類別 = void
存取權限 = 1
===================
方法名 = method2_prive
傳回類別 = void
存取權限 = 1

取得建構子(不包含父類別)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Animal {
  public String type;
  private String color;

  public void fmethod1_public() {}

  public void fmethod2_prive() {}

  public Animal() {}

  public Animal(String type) {}
}

class Fish extends Animal {
  public String name;
  private String age;

  public Fish() {}

  public Fish(String name) {}

  private Fish(String name, int age) {}

  public void method1_public() {}

  public void method2_prive() {}
}

取得public建構子(不包含父類別)

1
2
3
4
5
6
7
8
9
10
11
Class clazz = Class.forName("reflect.Fish");
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
  System.out.println("===================");
  System.out.println("建構子名 = " + constructor.getName());
  System.out.println("存取權限 = " + constructor.getModifiers());
  Class<?>[] parameterTypes = constructor.getParameterTypes();
  for (Class<?> parameterType : parameterTypes) {
    System.out.println("參數類型 = " +parameterType);
  }
}
===================
建構子名 = reflect.Fish
存取權限 = 1
參數類型 = class java.lang.String
===================
建構子名 = reflect.Fish
存取權限 = 1

取得public private 建構子(不包含父類別)

存取權限,1 是public, 2 是private。

1
2
3
4
5
6
7
8
9
10
11
Class clazz = Class.forName("reflect.Fish");
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
  System.out.println("===================");
  System.out.println("建構子名 = " + constructor.getName());
  System.out.println("存取權限 = " + constructor.getModifiers());
  Class<?>[] parameterTypes = constructor.getParameterTypes();
  for (Class<?> parameterType : parameterTypes) {
    System.out.println("參數類型 = " +parameterType);
  }
}
===================
建構子名 = reflect.Fish
存取權限 = 2
參數類型 = class java.lang.String
參數類型 = int
===================
建構子名 = reflect.Fish
存取權限 = 1
參數類型 = class java.lang.String
===================
建構子名 = reflect.Fish
存取權限 = 1

取得父類別

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Animal {
  public String type;
  private String color;

  public Animal() {}

  public Animal(String type) {}
}

interface IA {}

interface IB {}

class Fish extends Animal implements IA, IB {
  public String name;
  private String age;

  public Fish() {}

  public Fish(String name) {}

  private Fish(String name, int age) {}

}
1
2
3
4
// 取得class
Class clazz = Class.forName("reflect.Fish");
Class super_clazz = clazz.getSuperclass();
System.out.println(super_clazz);
class reflect.Animal

取得Interface

1
2
3
4
5
6
// 取得class
Class clazz = Class.forName("reflect.Fish");
Class[] interfaces = clazz.getInterfaces();
for (Class anInterface : interfaces) {
  System.out.println(anInterface);
}
interface reflect.IA
interface reflect.IB

取得Annoations

1
2
3
4
@Deprecated
class Fish {
  public Fish() {}
}
1
2
3
4
5
Class clazz = Class.forName("reflect.Fish");
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
  System.out.println(annotation);
}
@java.lang.Deprecated(forRemoval=false, since="")

測試的程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
interface Fly {
  void fly();
}

interface Swim {
  void swim();
}

public class Duck extends Animal implements Fly, Swim{
  public String name;
  private String info;

  static {
    System.out.println("Duck 被classloader載入");
  }

  public Duck() {
    System.out.println("物件被jvm建立");
  }

  private Duck(String name) {
    this.name = name;
  }

  @Override
  public void eat() {
    System.out.println("鴨子吃");
  }

  @Override
  public void fly() {
    System.out.println("鴨子飛");
  }

  @Override
  public void swim() {
    System.out.println("鴨子游泳");
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getInfo() {
    return info;
  }

  public void setInfo(String info) {
    this.info = info;
  }
}

Class.forName

forName(““)的參數是package名字.類別名組成,用點來區隔。

由執行結果發現,會執行到 Initialization 初始化

1
2
Class class1 = Class.forName("reflect.Duck");
System.out.println(class1);
Duck 被classloader載入
class reflect.Duck

類別名.class 取得 Class 物件

static 區塊:

static {
    System.out.println("Duck 被classloader載入");
}

實際上是在 初始化階段 執行的,而不是載入階段。

Duck.class 只做「載入」,不做「初始化」

Duck.class

類別檔被 class loader 載入

類別資訊被讀取

Class 物件被建立

但 不會執行 static 區塊。

因為 JVM 規範明確說:

類別名.class 取得 Class 物件並不會觸發 class initialization。
1
2
Class class2 = Duck.class;
System.out.println(class2);
class reflect.Duck

getClass()

由執行結果發現,會執行到 Initialization 初始化

1
2
3
Duck duck = new Duck();
Class class3 = duck.getClass();
System.out.println(class3);
Duck 被classloader載入
物件被jvm建立
class reflect.Duck

取得父類別

1
2
3
4
5
6
7
public class Test {
  public static void main(String[] args) throws Exception {
    Class class1 = Duck.class;
    Class superclass = class1.getSuperclass();
    System.out.println(superclass);
  }
}
class reflect.Animal

取得介面

1
2
3
4
5
6
7
8
9
public class Test {
  public static void main(String[] args) throws Exception {
    Class class1 = Duck.class;
    Class[] interfaces = class1.getInterfaces();
    for (Class cls : interfaces) {
      System.out.println(cls);
    }
  }
}
interface reflect.Fly
interface reflect.Swim

取得public屬性

1
2
3
4
5
  Class class1 = Duck.class;
  Field[] fields = class1.getFields();
  for (Field field : fields) {
    System.out.println(field);
  }
public java.lang.String reflect.Duck.name

取得所有屬性

1
2
3
4
  Field[] dfields = class1.getDeclaredFields();
  for (Field field : dfields) {
    System.out.println(field);
  }
public java.lang.String reflect.Duck.name
private java.lang.String reflect.Duck.info

取得public方法與所有方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Test {
  public static void main(String[] args) throws Exception {
    Class class1 = Duck.class;
    // getMethods只有public的方法
    Method[] methods = class1.getMethods();
    for (Method method : methods) {
      System.out.println(method);
    }

    // getDeclaredMethods() 包含所有public,private方法
    Method[] dmethods = class1.getDeclaredMethods();
    for (Method method : dmethods) {
      System.out.println(method);
    }
  }
}
public java.lang.String reflect.Duck.getInfo()
public void reflect.Duck.eat()
public void reflect.Duck.fly()
public void reflect.Duck.swim()
public void reflect.Duck.setInfo(java.lang.String)

取得父類別所有方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Test3 {
  public static void main(String[] args) {
    Class<?> clazz = Dog.class;
    System.out.println("Methods in class: " + clazz.getName());
    for (Method method : clazz.getDeclaredMethods()) {
      System.out.println(method);
    }

    // parent
    Class<?> superclass = clazz.getSuperclass();
    System.out.println("Methods in Parent: " + clazz.getName());
    for (Method method : superclass.getDeclaredMethods()) {
      System.out.println(method);
    }
  }
}

class Animal {
  int i = 10;  // 父類欄位
  void speak() { System.out.println(i); }  // 印出 this.i
}

class Dog extends Animal {
  int i = 5;  // 子類同名欄位
  //void speak() { System.out.println(i); }
}
Methods in class: wrap.Dog
Methods in Parent: wrap.Dog
void wrap.Animal.speak()

將以上取得父類別方法改善如下,方便以後做測試,只要輸入「package.類別名」。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Test {
  public static void main(String[] args) throws ClassNotFoundException {
    // 參數是「package.類別名」
    getClzMethod(Class.forName("inherit.A"));
  }

  public static void getClzMethod(Class<?> clz) {
    Class<?> clazz = clz;
    System.out.println("Methods in class: " + clazz.getName());
    for (Method method : clazz.getDeclaredMethods()) {
      System.out.println(method);
    }
    System.out.println("------------------");
    // parent
    Class<?> superclass = clazz.getSuperclass();
    System.out.println("Methods in Parent: " + clazz.getName());
    for (Method method : superclass.getDeclaredMethods()) {
      System.out.println(method);
    }
  }
}

取得public建構子與private建構子

1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
  public static void main(String[] args) throws Exception {
    Class class1 = Duck.class;
    Constructor[] constructors = class1.getConstructors();

    // getDeclaredConstructors() 包含所有public,private
    Constructor[] dconstructors = class1.getDeclaredConstructors();
    for (Constructor constructor : dconstructors) {
      System.out.println(constructor);
    }
  }
}
public reflect.Duck()
private reflect.Duck(java.lang.String)

使用private建構子建立物件並呼叫私有方法

先把public建構子

1
2
3
  public Duck() {
    System.out.println("物件被jvm建立");
  }

改成

1
2
3
  private Duck() {
    System.out.println("物件被jvm建立");
  }

增加private 方法

1
2
3
  private void getAddress() {
    System.out.println("private getAddress() test");
  }

呼叫private建構子與private方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) throws Exception {
  Class class1 = Duck.class;
  // 呼叫private建構子建立物件
  Constructor dc = class1.getDeclaredConstructor();
  // 把private改成public
  dc.setAccessible(true);
  Object instance = dc.newInstance();
  // 呼叫私有方法
  Method dm1 = class1.getDeclaredMethod("getAddress");
  // 設置成public
  dm1.setAccessible(true);
  // 參數代入instance
  dm1.invoke(instance);
}
Duck 被classloader載入
物件被jvm建立
private getAddress() test

使用public建構子與參數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.lang.reflect.Method;
import java.util.Scanner;
public class Test {
  public static void main(String[] args) throws Exception {
    Scanner  sc= new Scanner(System.in);
    System.out.println("輸入package.類別");
    String strName = sc.next();
    System.out.println("請輸入一個數");
    int a = sc.nextInt();
    System.out.println("請輸入另一個數");
    int b = sc.nextInt();
    Class class1 = Class.forName(strName);
    // 呼叫public建構子,建立物件
    Object ins = class1.newInstance();
    // 取出方法與設定參數類型
    Method md = class1.getDeclaredMethod("sum", int.class, int.class);
    // 呼叫方法,第1個參數是物件,a與b是方法參數
    md.invoke(ins, a, b);
  }
}

編譯,並執行

在另一個Project,跟上一個程式碼同一個package下寫以下程式碼,並編譯

1
2
3
4
5
6
public class Cal {
  public void sum(int a, int b) {
    System.out.println("result = ");
    System.out.println(a + b);
  }
}

熱部署

熱部署(英:Hot deployment)是,伺服器不需要重新啟動的情況下,修改軟體或者軟體。 將上面的程式碼產生出來的class檔放在已經正在運行的class目錄下

回到剛才執行”使用public建構子與參數”,輸入package name與類別

輸入package.類別
reflect.Cal
請輸入一個數
5
請輸入另一個數
3
result = 
8

results matching ""

    No results matching ""