當程式運行時,允許改變程式結構或變數類型,這種語言稱為動態語言。我們認為java並不是動態語言,但它有一個非常突出的動態相關機制,俗稱:反射。
IT產業裡這麼說,沒有反射也就沒有框架,現有的框架都是以反射為基礎。在實際專案開發中,用的最多的是框架,填的最多的是類,反射這個概念就是將框架和類揉在一起的調和劑。所以,反射才是接觸專案開發的敲門磚!
反射機制是什麼
反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態取得的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。
反射機制能做什麼
反射機制主要提供了以下功能:
在運作時判斷一個物件所屬的類;的物件;
在運行時判斷任意一個類別所具有的成員變數和方法;
在運行時呼叫任意一個物件的方法;
產生動態代理。
1,反射機制獲取類別有三種方法,我們來獲取Employee類型//第一种方式:
Classc1 = Class.forName("Employee");
//第二种方式:
//java中每个类型都有class 属性.
Classc2 = Employee.class;
//第三种方式:
//java语言中任何一个java对象都有getClass 方法
Employeee = new Employee();
Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)
2,創建對象:獲取類以後我們來創建它的對象,利用newInstance:獲取類3,取得屬性:分為所有的屬性和指定的屬性:
先看獲取所有的屬性的寫法:
Class c =Class.forName("Employee"); //创建此Class 对象所表示的类的一个新实例 Objecto = c.newInstance(); //调用了Employee的无参数构造方法.
獲取特定的屬性,對比著傳統的方法來學習:
//获取整个类 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);方法的反射
Class類別有一個最簡單的方法,getName():public static void main(String[] args) throws Exception{
<span style="white-space:pre"> </span>//以前的方式:
/*
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));
}
getName方法可以列印出該類別類型的類別名稱,我們也可以用getSimpleName()方法可以列印出不包含套件名稱的類別的名稱。從上面程式碼可以看出,基本的資料型別以及void關鍵字都是存在的類別類型。
案例:
public class Demo2 { public static void main(String[] args) { Class c1 = int.class;//int 的类类型 Class c2 = String.class;//String类的类类型 Class c3 = void.class; System.out.println(c1.getName()); System.out.println(c2.getName()); System.out.println(c2.getSimpleName()); System.out.println(c3.getName()); } }
總結思路:
透過方法的反射得到該類別的名稱步驟:1.取得該類別的類別類型
2.透過類別取得類別的方法(getMethods())3.循環遍歷所取得的方法
4.透過這些方法的getReturnType()得到回傳值類型的類別類型,又透過該類別類型得到傳回值類型的名字5.getName()得到方法的名稱,getParameterTypes()取得這個方法裡面的參數型別的類別類型。
成員變數的反射
首先我們需要認識到成員變數也是對象,是java.lang.reflect.Field類別的對象,那麼也就是說Field類別封裝了關於成員變數的操作。既然它封裝了成員變量,我們又該如何取得這些成員變數呢?它有這麼一個方法:
public class ClassUtil { public static void printClassMethodMessage(Object obj){ //要获取类的信息》》首先我们要获取类的类类型 Class c = obj.getClass(); //我们知道Object类是一切类的父类,所以我们传递的是哪个子类的对象,c就是该子类的类类型。 //接下来我们要获取类的名称System.out.println("类的名称是:"+c.getName()); /* *我们知道,万事万物都是对象,方法也是对象,是谁的对象呢? * 在java里面,方法是Method类的对象 *一个成员方法就是一个Method的对象,那么Method就封装了对这个成员 *方法的操作 *///如果我们要获得所有的方法,可以用getMethods()方法,这个方法获取的是所有的Public的函数,包括父类继承而来的。如果我们要获取所有该类自己声明的方法,就可以用getDeclaredMethods()方法,这个方法是不问访问权限的。 Method[] ms = c.getMethods();//c.getDeclaredMethods() //接下来我们拿到这些方法之后干什么?我们就可以获取这些方法的信息,比如方法的名字。 //首先我们要循环遍历这些方法 for(int i = 0; i < ms.length;i++){ //然后可以得到方法的返回值类型的类类型 Class returnType = ms[i].getReturnType(); //得到方法的返回值类型的名字 System.out.print(returnType.getName()+" "); //得到方法的名称 System.out.print(ms[i].getName()+"("); //获取参数类型--->得到的是参数列表的类型的类类型 Class[] paramTypes = ms[i].getParameterTypes(); for (Class class1 : paramTypes) { System.out.print(class1.getName()+","); } System.out.println(")"); } } }這裡的getFields()方法所獲得的所有的public的成員變數的資訊。和方法的反射那裡public的成員變量,也有一個獲取所有自己聲明的成員變量的信息:
public class ClassUtil { public static void printFieldMessage(Object obj){ Class c = obj.getClass(); //Field[] fs = c.getFields(); }我們得到它之後,可以進行遍歷(既然封裝了Field的信息,那麼我們就可以得到Field類型)
Field[] fs = c.getDeclaredFields();
建構子的反射
不論是方法的反射、成員變數的反射、建構子的反射,我們只需要知道:要取得類別的信息,首先得取得類別的類別類型。
for (Field field : fs) { //得到成员变量的类型的类类型 Class fieldType = field.getType(); String typeName = fieldType.getName(); //得到成员变量的名称 String fieldName = field.getName(); System.out.println(typeName+" "+fieldName); }