什麼是反射
**Java反射就是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;並且能改變它的屬性。**而這也是Java被視爲動態(或準動態,爲啥要說是準動態,因爲一般而言的動態語言定義是程序運行時,允許改變程序結構或變量類型,這種語言稱爲動態語言。從這個觀點看,Perl,Python,Ruby是動態語言,C++,Java,C#不是動態語言。)語言的一個關鍵性質。
反射能做什麼?
我們知道反射機制允許程序在運行時取得任何一個已知名稱的class的內部信息,包括包括其modifiers(修飾符),fields(屬性),methods(方法)等,並可於運行時改變fields內容或調用methods。那麼我們便可以更靈活的編寫代碼,代碼可以在運行時裝配,無需在組件之間進行源代碼鏈接,降低代碼的耦合度;還有動態代理的實現等等;但是需要注意的是反射使用不當會造成很高的資源消耗!
反射的核心API:
在Class對象中可以獲取:Constructor、Field、Method
反射的作用:我們知道反射是通過Class對象動態的獲取某一個類的構造方法、成員變量、普通方法的方式。按照我們目前的能力,是無法通過私有的構造創建對象,無法給一個對象的私有的變量賦值、無法調用私有的方法。但是,通過反射就可以實現這種需求。
獲取Class的三種方式,推薦第三種:
測試對象:
public class User {
private String userName ;
private String password;
private String age;
//public修飾的無參構造
public User(){};
//public修飾的三個參數構造
public User(String userName,String password,String age){
this.userName=userName;
this.password=password;
this.age=age;
}
//private修飾的兩個參數構造
private User(String userName,String password){
this.userName=userName;
this.password=password;
}
public String getName(User user){
return user.getUserName();
}
private String showMethod(){
return "私有方法被調用";
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
Constructor介紹
獲取一個構造方法:
獲取多個的構造方法:
總結:當獲取一個構造方法時,調用不帶s的方法;當獲取私有的構造方法時,調用帶Declared的方法。
通過Constructor對象創建類的實例:
當通過Constructor對象類創建一個類的實例時,如果構造方法是非pubic修飾的,那麼就需要調用Constructor父類 AccessibleObject的setAccessible(true)方法打破訪問權限!!!
@Test
public void getConstructor() throws NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException, Exception {
// 獲取User類的Class對象
Class<User> userClass = (Class<User>) Class.forName("com.Lambda.test.User");
// 通過無參構造方法,獲取User類的Constructor(構造方法)對象
Constructor<User> ConsUser1 = userClass.getConstructor();
// 通過Constructor創建User實例對象
User user1 = ConsUser1.newInstance();
System.out.println("無參構造獲取對象內存地址:" + user1 + "====用戶名:" + user1.getUserName());
System.out.println("----------------------------------------");
// 通過有參構造方法,獲取User類的Constructor(構造方法)對象
Constructor<User> ConsUser2 = userClass.getConstructor(String.class, String.class, String.class);
User user2 = ConsUser2.newInstance("張三", "123", "18");
System.out.println("有參構造獲取對象內存地址:" + user2 + "====用戶名:" + user2.getUserName());
System.out.println("----------------------------------------");
// 獲取非public修飾的構造方法對象,通過Constructor父類 AccessibleObject的setAccessible(true)方法打破訪問權限
Constructor<User> ConsUser3 = userClass.getDeclaredConstructor(String.class, String.class);
// 是否越界訪問(無視私有化)
ConsUser3.setAccessible(true);
User user3 = ConsUser3.newInstance("李四", "123");
System.out.println("私有帶參構造獲取對象內存地址:" + user3 + "====用戶名:" + user3.getUserName());
System.out.println("----------------------------------------");
// 獲取
Constructor<?>[] constructors = userClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("獲取User類所有的公開構造方法:" + constructor);
}
System.out.println("----------------------------------------");
Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
for (Constructor<?> constructor : declaredConstructors) {
System.out.println("獲取User類所有的構造方法(包含非public修飾的):" + constructor);
}
}
運行結果:
Field介紹
獲取一個Field對象的方法:
獲取多個Field對象的方法:
給Field設置值以及獲取Field的值:找Field的api
@Test
public void getFiled() throws ClassNotFoundException, NoSuchFieldException, SecurityException,
InstantiationException, IllegalAccessException {
// 獲取User類的class對象
Class<?> userClass = Class.forName("com.Lambda.test.User");
// 獲取私有化修飾的成員變量對象
Field field = userClass.getDeclaredField("userName");
// 是否越界訪問(無視私有化)
field.setAccessible(true);
// 通過class對象實例化user對象
User user = (User) userClass.newInstance();
// 參數賦值:參數1:實例化對象,參數2:值
field.set(user, "王五");
System.out.println("獲取user成員變量:" + user.getUserName());
System.out.println("----------------------------------------");
//獲取field屬性值(userName)
Object uname = field.get(user);
System.out.println("獲取userName的值"+uname);
}
運行結果:
注:
獲取對象的class類型,通過getDeclaredField(“id”)獲取的是變量的對象,返回的Field就相當於是這個變量
field.set(user,“王五”):可以理解爲設置user對象中field(“userName”)的值爲"王五"
同理field.get(user):可以理解爲獲取user對象中field(“userName”)的值
Method獲取介紹
獲取一個Method對象的方法
獲取多個Method對象的方法:
@Test
public void getMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
// 獲取User類的class對象
Class<?> userClass = Class.forName("com.Lambda.test.User");
// 通過class對象實例化user對象
User user = (User) userClass.newInstance();
user.setUserName("趙六");
//獲取方法的method對象,參數1:方法名,參數2:方法的參數類型
Method method = userClass.getMethod("getName",userClass);
//method代表方法對象;invoke方法參數1:執行方法的對象,參數2:方法的參數
Object resule1 = method.invoke(user, user);
System.out.println("public修飾的方法返回結果:"+resule1);
System.out.println("-------------------------------------------");
//獲取非public方法的method對象,參數1:方法名,參數2:方法的參數類型
Method showMethod = userClass.getDeclaredMethod("showMethod");
//越界訪問,無視私有化
showMethod.setAccessible(true);
//showMethod代表方法對象;invoke方法參數1:執行方法的對象,參數2:方法的參數
Object result2 = showMethod.invoke(user);
System.out.println("非public修飾的方法返回結果:"+result2);
}