反射是一個(gè)很重要的技術(shù)难咕,通過反射技術(shù),能把多個(gè)成分構(gòu)建成一個(gè)Java類距辆,話不多說余佃,開始介紹。
Class類
Class類是一個(gè)比Object類還抽象的應(yīng)該東西跨算,在POJO里面咙冗,Object表示所有的東西,而Class表示這些所有定義對(duì)象的類文件漂彤,可以理解為Class的實(shí)例對(duì)象雾消,表示定義對(duì)象的字節(jié)碼灾搏,Class就是Java的類的抽象。
Class是不能用new來創(chuàng)建的立润,有三種獲得Class實(shí)例的方法狂窑,分別如下
Class a = String.class;
Class b = "abc".getClass();
Class c = Class.forName("java.lang.String");
特殊
有9個(gè)預(yù)定義的Class對(duì)象
byte.class == Byte.TYPE;
short.class == Short.TYPE;
int.class == Integer.TYPE;
long.class == Long.TYPE;;
float.class == Float.TYPE;
double.class == Double.TYPE;
char.class == Character.TYPE;
double.class == Double.TYPE;
boolean.class == Blooean.TYPE;
void.class == Void.TYPE;
原始類型都有各自的Class
Class中有 isPrimitive() 方法來判斷類是否為原始類型
isArray() 判斷是否為數(shù)組
Constructor類
代表類的構(gòu)造器
Class strcla = Class.forName("java.lang.String");
//獲取所有的類的構(gòu)造器
Constructor[] acs = strcla.getConstructors();
//獲取參數(shù)是StringBuffer的構(gòu)造器
Constructor ac = strcla.getConstructor(StringBuffer.class);
// 利用構(gòu)造器,創(chuàng)建對(duì)象
String a = (String) ac.newInstance(new StringBuffer("666"));
這些方法需要捕獲異常
有些構(gòu)造器是私有的桑腮,不能被直接獲取到泉哈,可以暴力反射
public class Demo02 {
private Demo02(){
System.out.println("hahaha");
}
}
public class Demo01 {
public static void main(String [] args) throws Exception {
//獲取字節(jié)碼
Class demo02 = Demo02.class;
//獲取私有構(gòu)造器
Constructor c = demo02.getDeclaredConstructor();
//取消訪問權(quán)限檢查
c.setAccessible(true);
//執(zhí)行構(gòu)造器
c.newInstance();
}
}
Method類
方法
public class Demo02 {
private String secretFunc(String name,String desc) {
System.out.println(name);
System.out.println(desc);
return name + "做了一把" + desc;
}
}
訪問Demo02實(shí)例的secretFunc方法
class Demo01 {
public static void main(String [] args) throws Exception {
Class dclass = Demo02.class;
//獲取secretFunc方法
Method method = dclass.getDeclaredMethod("secretFunc",String.class,String.class);
//實(shí)例一個(gè)demo02
Demo02 demo02 = new Demo02();
//去掉權(quán)限驗(yàn)證(暴力反射)
method.setAccessible(true);
//執(zhí)行demo02的secretFunc方法,并獲得返回值
String result = (String) method.invoke(demo02,"羅永浩","錘子");
//輸出結(jié)果
System.out.println(result);
}
}
有些方法只知道名字,不知道參數(shù)破讨,可以用getMethods()
先取出所有方法丛晦,再一一用,getParameters()
來獲得參數(shù)類型提陶。
具體可以去查閱API文檔
Field類
屬性(成員變量)
可以用來訪問私有變量烫沙,修改變量值
public class Demo02 {
private String XXX = "day day up";
}
修改私有成員變量
class Demo01 {
public static void main(String [] args) throws Exception {
Class dclass = Demo02.class;
//獲取XXX成員變量
Field xxx = dclass.getDeclaredField("XXX");
//實(shí)例一個(gè)demo
Demo02 demo02 = new Demo02();
//去掉權(quán)限驗(yàn)證(暴力反射)
xxx.setAccessible(true);
//獲取這個(gè)屬性的值
System.out.println(xxx.get(demo02));
//修改demo02的XXX屬性
if(xxx.getType()==String.class){
xxx.set(demo02,"good good study");
}
System.out.println(xxx.get(demo02));
}
}
使用場(chǎng)景
在搭建框架的時(shí)候,有時(shí)候不知道需要什么類隙笆,什么方法锌蓄,這個(gè)類有哪些屬性。比如查詢數(shù)據(jù)庫之后的數(shù)據(jù)撑柔,反射成對(duì)象瘸爽。
比如
- 現(xiàn)在在配置文件中,定義了要使用的類
com.User
- 我們?cè)跀?shù)據(jù)庫里查詢到了一個(gè)數(shù)據(jù)(這里用JSON字符串來代替)
- 我們根據(jù)配置铅忿,把這組數(shù)據(jù)剪决,轉(zhuǎn)換成配置中的對(duì)象
progress方法是框架定義好的方法,之前讀取配置和查詢數(shù)據(jù)庫分別被我簡(jiǎn)化了
/**
* 簡(jiǎn)化讀取配置
*/
public String getProfileData() {
return "com.User";
}
/**
* 簡(jiǎn)化數(shù)據(jù)庫查詢(用JSON代替了檀训,JDBC其實(shí)也可以)
*/
public String getDataFromDatabase() {
return "{\"address\":\"小米街道\",\"name\":\"雷軍\",\"sex\":\"unknown\"}\n";
}
@Test
public void progress() throws Exception {
//讀取配置得到對(duì)象配置
Class useClass = Class.forName(getProfileData());
//實(shí)例化對(duì)象
Object needObj = useClass.newInstance();
//讀取數(shù)據(jù)庫柑潦,獲得數(shù)據(jù)
JSONObject datas = JSON.parseObject(getDataFromDatabase());
//獲取參數(shù)名稱集合
Set<String> keys = datas.keySet();
for (String key : keys) {
//調(diào)用set方法
Method md = useClass.getMethod("set" + StringUtils.capitalize(key), String.class);
md.invoke(needObj, datas.get(key));
}
// 這就得到了需要的對(duì)象
System.out.println(needObj);
}
定義好User
package com;
/**
* Created by zing on 2016/11/10.
*/
public class User {
private String name;
private String address;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User對(duì)象:\n" +
"名字='" + name + "\'\n" +
"地址='" + address + "\'\n" +
"性別='" + sex + "\'\n" ;
}
}
這兩段代碼都搞定之后,執(zhí)行progress方法就可以了肢扯。
很明顯妒茬,接下來包裝一下的話担锤,就可以寫一個(gè)自己的持久層框架了蔚晨。
當(dāng)然反射的用處不止這些,我們還可以用這個(gè)來調(diào)用系統(tǒng)的私有方法肛循,Android要是讀過源碼的話铭腕,很多流氓的東西很容易就干出來了(我不是說C++層的),我就不細(xì)說了多糠。
回來
ps:別在意數(shù)據(jù)累舷,重點(diǎn)在技術(shù)
love&peace