1 參考資料
- https://how2j.cn/k/reflection/reflection-class/108.html 一個比較全面的Java學習教程(這裏用下人家的代碼)
- Java編程思想
2 反射的由來
假設自己從磁盤文件或者網絡獲取了一串字節,且被告知這串字節代表了一個類。然後,我們如何去使用這樣的一個類?
解決辦法----反射(Class類和java.lang.reflect類對反射概念進行了描述)
3 反射和RTTI的區別
很簡單,RTTI是在編譯時打開和檢查.class文件,反射是在運行時打開和檢查.class文件。
4 反射能幹嘛
4.1 獲取Class對象
這個就是三種方法獲取Class對象。
點它進去看詳細介紹
不點這也有圖( ̄▽ ̄)
4.2 創建對象
首先我們這裏得現有一個定義好的Hero類。
public class Hero {
public String name;
public float hp;
public int damage;
public int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Hero(){
}
public Hero(String string) {
name =string;
}
@Override
public String toString() {
return "Hero [name=" + name + "]";
}
public boolean isDead() {
// TODO Auto-generated method stub
return false;
}
public void attackHero(Hero h2) {
System.out.println(this.name+ " 正在攻擊 " + h2.getName());
}
}
然後我們來測試下,用反射方法創建新的Hero對象
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectDemo {
public static void main(String[] args) throws IllegalAccessException,
InstantiationException,
NoSuchMethodException,
InvocationTargetException {
// Class 直接創建實例,但是該類必須要有一個無參的默認構造函數
//只能反射無參的構造器,需要構造器可見;
Class<Hero> heroClass = Hero.class;
Hero hero = heroClass.newInstance();
// 通過類的構造器創建實例,可以反射任何構造器,可以反射私有構造器
Constructor<Hero> heroConstructor = heroClass.getConstructor(String.class);
Hero hero1 = heroConstructor.newInstance("CC");
System.out.println(hero.toString());
System.out.println(hero1.toString());
}
}
瞅瞅結果
4.3 修改屬性值
Class<Hero> heroClass = Hero.class;
Hero hero = heroClass.newInstance();
hero.setName("CC");
System.out.println("hero's Name is "+hero.getName());
Field field = heroClass.getField("name");
field.set(hero,"GG");
System.out.println("hero's Name is "+hero.getName());
結果,
PS:getField 只能獲取public的,包括從父類繼承來的字段。
getDeclaredField 可以獲取本類所有的字段,包括private的,但是不能獲取繼承來的字段。
(注: 這裏只能獲取到private的字段,但並不能訪問該private字段的值,除非加上setAccessible(true))
4.4 調用方法
同理,這邊也很簡單了
Class<Hero> heroClass = Hero.class;
Hero h = heroClass.newInstance();
// 獲取這個名字叫做setName,參數類型是String的方法
Method m = heroClass.getMethod("setName", String.class);
// 對h對象,調用這個方法
m.invoke(h, "蓋倫");
// 使用傳統的方式,調用getName方法
System.out.println("hero's name is "+h.getName());
結果