1. 程式人生 > >sincerit java基礎之反射

sincerit java基礎之反射

看看這兩篇就更容易理解
https://www.zhihu.com/question/24304289
https://www.sczyh30.com/posts/Java/java-reflection-1/

JAVA反射機制是在執行狀態中,
對於任意一個實體類,都能夠知道這個類的所有屬性和方法;
對於任意一個物件,都能夠呼叫它的任意方法和屬性;
這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射機制。

簡而言之,通過反射,我們可以在執行時獲得程式或程式集中每一個型別的成員和成員的資訊。程式中一般的物件的型別都是在編譯期就確定下來的,而 Java 反射機制可以動態地建立物件並呼叫其屬性,這樣的物件的型別在編譯期是未知的。所以我們可以通過反射機制直接建立物件,即使這個物件的型別在編譯期是未知的。

1,反編譯:.class–>.java 從.class位元組碼到java原始碼
2,通過反射機制訪問java物件的屬性,方法,構造方法等;
在這裡先看一下sun為我們提供了那些反射機制中的類:
java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
很多反射中的方法,屬性等操作我們可以從這四個類中查詢。
三種獲得Employee型別(class型別)的方法

//第一種方式:
Class c1 = Class.forName("Employee"
); // c1是Employee的class物件一個類只有一個型別物件 //第二種方式: //java中每個型別都有class 屬性. Class c2 = Employee.class; //第三種方式: //java語言中任何一個java物件都有getClass 方法 Employee e = new Employee(); Class c3 = e.getClass(); //c3是執行時類 (e的執行時類是Employee)

你的類Employee載入到方法區中(jvm的方法區),建立了Employee類的class物件到堆中,注意這個不是new出來的物件,而是類的型別物件,每個類只有一個class物件,作為方法區類的資料結構的介面。

建立物件:獲取類以後我們來建立它的物件,利用newInstance:

    Class c =Class.forName("Employee");
    //建立此Class 物件所表示的類的一個新例項
    Object o = c.newInstance(); //呼叫了Employee的無引數構造方法

獲取屬性:分為所有的屬性和指定的屬性:
a,先看獲取所有的屬性的寫法:

//獲取整個類
			Class c = Class.forName("java.lang.Integer");
		    //獲取所有的屬性?
			Field[] fs = c.getDeclaredFields();
	        //定義可變長的字串,用來儲存屬性
			StringBuffer sb = new StringBuffer();
	        //通過追加的方法,將每個屬性拼接到此字串中
			//最外邊的public定義
			sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");
	        //裡邊的每一個屬性
			for(Field field:fs){
				sb.append("\t");//空格
				sb.append(Modifier.toString(field.getModifiers())+" ");//獲得屬性的修飾符,例如public,static等等
				sb.append(field.getType().getSimpleName() + " ");//屬性的型別的名字
				sb.append(field.getName()+";\n");//屬性的名字+回車
			}
			sb.append("}");
			System.out.println(sb);

b,獲取特定的屬性,對比著傳統的方法來學習:

public static void main(String[] args) throws Exception{	
	//以前的方式:
	/*
	User u = new User();
	u.age = 12; //set
	System.out.println(u.age); //get
	*/	
	//獲取類
	Class c = Class.forName("User");
	//獲取id屬性
	Field idF = c.getDeclaredField("id");
	//例項化這個類賦給o
	Object o = c.newInstance();
	//打破封裝
	idF.setAccessible(true); //使用反射機制可以打破封裝性,導致了java物件的屬性不安全。
	//給o物件的id屬性賦值"110"
	idF.set(o, "110"); //set
	//get
	System.out.println(idF.get(o));
}

4,獲取方法,和構造方法,不再詳細描述,只來看一下關鍵字:

方法關鍵字                                含義
getDeclaredMethods()                     獲取所有的方法
getReturnType()                          獲得方法的放回型別
getParameterTypes()                      獲得方法的傳入引數型別
getDeclaredMethod("方法名",引數型別.class,……)  獲得特定的方法
構造方法關鍵字                            含義
getDeclaredConstructors()                獲取所有的構造方法
getDeclaredConstructor(引數型別.class,……) 獲取特定的構造方法
父類和父介面                              含義
getSuperclass()                          獲取某類的父類
getInterfaces()                          獲取某類實現的接

這樣我們就可以獲得類的各種內容,進行了反編譯。對於JAVA這種先編譯再執行的語言來說,反射機制可以使程式碼更加靈活,更加容易實現面向物件。
內容來自 :https://blog.csdn.net/sinat_38259539/article/details/71799078

總結一下:反射就是可以在程式執行時動態的建立一個物件(建立哪個物件可以使用配置檔案),這個物件的型別在編譯期是未知的,我們可以使用這個物件去完成一些任務(現在還不知道怎麼使用這些東西)

舉個例子我們的專案底層有時是用mysql,有時用oracle,需要動態地根據實際情況載入驅動類,這個時候反射就有用了,假設 com.java.dbtest.myqlConnection,com.java.dbtest.oracleConnection這兩個類我們要用,這時候我們的程式就寫得比較動態化,通過Class tc = Class.forName(“com.java.dbtest.TestConnection”);通過類的全類名讓jvm在伺服器中找到並載入這個類(編譯時這個物件的型別是未知的,而在執行時動態的建立物件確定了),而如果是oracle則傳入的引數就變成另一個了。這時候就可以看到反射的好處了,這個動態性就體現出java的特性了

這有個完整的例子: https://www.jianshu.com/p/9be58ee20dee