JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。java
新建測試類: public class Dog implements Animal { private String name; String color; @Override public void say() { System.out.println("dog..say.."); } public void run(){ System.out.println("dog..run.."); } public void eat(String S){ System.out.println("dog..eat.."+S); } //.... public Dog() { } public Dog(String name, String color) { this.name = name; this.color = color; } }
1.Class是一個類,封裝了當前對象所對應的類的信息
2.一個類中有屬性,方法,構造器等,好比說有一個Person類,一個Order類,這些都是不一樣的類,如今須要一個類,用來描述類,這就是Class,
它應該有類名,屬性,方法,構造器等。Class是用來描述類的類。
3.對於每一個類而言,JRE 都爲其保留一個不變的 Class 類型的對象。
4.Class 對象只能由系統創建對象,一個類(而不是一個對象)在 JVM 中只會有一個Class實例。bootstrap
@Test public void test5(){ Class clazz1=Dog.class; Class clazz2=Dog.class; System.out.println(clazz1); System.out.println(clazz2); System.out.println(clazz1==clazz2);//true }
獲取Class對象的三種方式:
1.經過類名獲取 類名.class
Class clazz=Dog.class;
2.經過對象獲取 對象名.getClass()
Dog dog=new Dog();
Class clazz=dog.getClass();
3.經過全類名獲取 Class.forName(全類名)
Class clazz=Class.forName("com.utils.Dog");數組
Class類的經常使用方法:ide
方法名函數 |
功能說明工具 |
static Class forName(String name)測試 |
返回指定類名 name 的 Class 對象ui |
Object newInstance()this |
調用缺省構造函數,返回該Class對象的一個實例spa |
Object newInstance(Object []args) |
調用當前格式構造函數,返回該Class對象的一個實例 |
getName() |
返回此Class對象所表示的實體(類、接口、數組類、基本類型或void)名稱 |
Class getSuperClass() |
返回當前Class對象的父類的Class對象 |
Class [] getInterfaces() |
獲取當前Class對象的接口 |
ClassLoader getClassLoader() |
返回該類的類加載器 |
Class getSuperclass() |
返回表示此Class所表示的實體的超類的Class |
類裝載器是用來把類(class)裝載進 JVM 的。JVM 規範定義了兩種類型的類裝載器:啓動類裝載器(bootstrap)和用戶自定義裝載器(user-defined class loader)。 JVM在運行時會產生3個類加載器組成的初始化加載器層次結構。
Reflection(反射)是Java被視爲動態語言的關鍵,反射機制容許程序在執行期藉助於Reflection API取得任何類的內部信息,並能直接操做任意對象的內部屬性及方法。
Java反射機制主要提供瞭如下功能:
在運行時構造任意一個類的對象
在運行時獲取任意一個類所具備的成員變量和方法
在運行時調用任意一個對象的方法(屬性)
生成動態代理
1.獲取對象中的method public void test() throws Exception { //獲取Dog.class的對象 Class dogClass=Dog.class; //獲取Dog.class全部的方法,包括父類方法,不包括私有方法 //Method[] methods=dogClass.getDeclaredMethods(); //獲取Dog.class全部的方法,包括私有方法,不包括父類方法 Method[] methods=dogClass.getDeclaredMethods(); for(Method method:methods){ System.out.println(method.getName()); } //返回該Class對象的一個實例 Object objects= dogClass.newInstance(); //獲取無參方法 say( ) Method method=dogClass.getDeclaredMethod("say"); //第一個參數表示執行哪一個對象的方法,剩下的參數是執行方法時須要傳入的參數 method.invoke(objects,null); //獲取帶參方法 eat( ),參數類型爲String.class method=dogClass.getDeclaredMethod("eat",String.class); method.invoke(objects,"骨頭"); }
2.獲取對象中的field public void test() throws Exception{ Class clazz=Dog.class; //獲取全部字段屬性,包括私有,不包括繼承 Field fields[]= clazz.getDeclaredFields(); for (Field field:fields){ System.out.println(field.getName()+"---"+field.getType()); } //獲取全部繼承字段屬性 fields = clazz.getFields(); for (Field field:fields){ System.out.println(field.getName()+"---"+field.getType()); } //獲取非私有字段屬性 Field field=clazz.getDeclaredField("color"); Object object=new Dog(); //設置字段屬性值 field.set(object,"red"); System.out.println("field.get(object)="+field.get(object)); //獲取私有字段屬性 field=clazz.getDeclaredField("name"); object=new Dog(); field.setAccessible(true); //設置字段屬性值 field.set(object,"tom"); System.out.println("field.get(object)="+field.get(object)); }
3.獲取對象的構造方法 public void test() throws Exception{ Class clazz=Dog.class; //獲取全部構造函數 Constructor[] constructors= clazz.getConstructors(); for (Constructor constructor:constructors){ System.out.println(constructor); } //獲取無參構造方法 Constructor constructor= clazz.getConstructor(new Class[]{}); System.out.println("無參構造 "+constructor); constructor=clazz.getConstructor(new Class[]{String.class,String.class}); System.out.println("帶參構造 "+constructor); }
5.看到這裏,咱們本身動手設計一個工具方法。 //自定義反射方法 類對象和類方法名做爲參數,執行方法 public Object myInvoke(Class object,String methodName,Object...args) throws Exception, InstantiationException { //把參數轉化爲對應的class對象 Class[] argsClass=new Class[args.length]; for (int i=0;i<args.length;i++){ argsClass[i]=args[i].getClass(); System.out.println(argsClass[i]); } //獲取方法 Method method=object.getDeclaredMethod(methodName,argsClass); //執行方法 return method.invoke(object.newInstance(),args); } 測試: public void test() throws Exception { Object args[]=new Object[]{}; Object result= myInvoke(Dog.class,"say",args); System.out.println("result="+result); }
6.咱們再設計一個工具方法,不但能訪問當前類的私有方法,還要能訪問父類的私有方法 通常使用getDeclaredMethod獲取方法(由於此方法能夠獲取類的私有方法,可是不能獲取父類方法),如何獲取父類方法呢? public Method getMethodForClass(Class clazz,String methodName,Class[] parameterTypes) throws NoSuchMethodException { for(;clazz != Object.class; clazz = clazz.getSuperclass()){ try { Method method = clazz.getDeclaredMethod(methodName, parameterTypes); if(method==null){ continue; } return method; } catch (Exception e) { System.out.println(e); } } return clazz.getDeclaredMethod(methodName, parameterTypes); }
第四步:文章小結 1. Class: 是一個類; 一個描述類的類.封裝了描述方法的 Method,描述字段的 Filed,描述構造器的 Constructor 等屬性. 2. 如何獲得 Class 對象: 2.1 Person.class 2.2 person.getClass() 2.3 Class.forName("com.atguigu.javase.Person") 3. 關於 Method: 3.1 如何獲取 Method: 1). getDeclaredMethods: 獲得 Method 的數組. 2). getDeclaredMethod(String methondName, Class ... parameterTypes) 3.2 如何調用 Method 1). 若是方法是 private 修飾的, 須要先調用 Method 的 setAccessible(true), 使其變爲可訪問 2). method.invoke(obj, Object ... args); 4. 關於 Field: 4.1 如何獲取 Field: getField(String fieldName) 4.2 如何獲取 Field 的值: 1). 若是Field是 private 修飾的, 須要先調用 Field 的 setAccessible(true),setAccessible(true) 2). field.get(Object obj) 4.3 如何設置 Field 的值: field.set(Obejct obj, Object val) 5. 瞭解 Constructor