一:Class類的使用
在面向對象的世界裏,世間萬物皆對象。類也是對象,類是java.lang.Class類的實例對象
任何一個類都是Class類的實例對象,這個對象稱爲該類的類類型。這個實例對象有三種表達方式
public class Demo1 {
public static void main(String[] args) {
//Reflect的對象
Reflect re=new Reflect();
//1.第一種表達方式,實際也在告訴我們任何一個類都有一個隱含的靜態成員class
Class c1=Reflect.class;
//2.第二種方式,已經知道該類的對象通過getClass方式
Class c2=re.getClass();
//官網說c1,c2表示了Reflect的類類型(Class Type),即萬事萬物皆對象
//一個類只可能是Class類的一個實例對象
System.out.println(c1==c2); //true
//3.第三種方式
try {
Class c3=Class.forName("com.swpu.relect.Reflect");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Reflect{}
二:動態加載類
Class.forName("類的全稱")不僅表示了類的類類型,還表示了動態加載類。
編譯時刻加載類是靜態加載類,new創建對象是靜態加載類,在編譯時刻就需要加載所有可能使用到的類,通過動態加載類可以解決該問題。
運行時刻加載類是動態加載類。
三:java獲取方法信息
基本類型都有類類型
public class Demo2 {
public static void main(String[] args) {
Class c1= int.class;
Class c2=String.class;
Class c3=void.class;
System.out.println(c1.getName()); //return int
System.out.println(c2.getName()); //java.lang.String
System.out.println(c3.getName()); //void
}
}
編寫了一個API接口來獲取類的信息
public class ClassUtil {
/**
* 打印類的信息,包括類的成員函數,成員變量
* @param object
*/
public static void PrintClassMessage(Object object){
//要獲取類的信息,首先獲取類的類類型
Class c=object.getClass();
//獲取類的名稱
System.out.println("類的名稱爲:"+c.getName());
/*
* 獲取方法.
* getMethods()方法獲取的是所有public的函數,包括從父類繼承而來的
* getDeclaredMethods:獲取的是所有自己定義的方法,不問訪問權限,不包括父類繼承過來的
*/
Method [] ms=c.getMethods();
for(Method m:ms){
//得到方法的返回值類型的類型
Class returnType=m.getReturnType();
System.out.print(returnType+" ");
//獲取到方法名
System.out.print(m.getName()+"(");
//獲取參數類型-->得到的是參數 列表類型的類類型
Class [] ParamTypes=m.getParameterTypes();
for(Class param:ParamTypes){
System.out.print(param.getName()+",");
}
System.out.println(")");
}
}
}
四:java獲取成員變量的信息
/**
* 成員變量也是對象,是java.lang.reflect.Field的對象
*
*/
Field[] fs=c.getDeclaredFields();
for(Field f:fs){
//得到成員變量的類類型
Class fieldType=f.getType();
String typeName=fieldType.getName();
//得到成員變量的名稱
String fieldName=f.getName();
System.out.println(typeName+"("+fieldName+")");
//
}
五:java獲取構造方法的信息
public static void printConMessage(Object obj){
Class c=obj.getClass();
/**
* 構造函數也是對象
* java.lang.Constructor中封裝了構造函數的信息
* getConstructors獲取所有的public的構造函數
* getDeclaredConstructors得到所有的構造函數的信息
*/
Constructor[] cs=c.getDeclaredConstructors();
for(Constructor con:cs){
System.out.print(con.getName()+"(");
//獲取構造函數的參數列表-->得到的是參數列表的類類型
Class[] returnType=con.getParameterTypes();
for(Class class1:returnType){
System.out.print(class1.getName()+",");
}
System.out.println(")");
}
}
六:方法反射對象的基本操作
1):如何獲取一個方法:方法的名稱和方法的參數列表唯一確定一個方法
2):方法反射的操作:method.invoke(對象,參數列表)
public class MethodInvoke {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//要獲取print(int,int)方法
A a1=new A();
Class c=a1.getClass();
/*
*2.獲取方法 名稱 參數列表
*/
try {
Method m=c.getMethod("print", new Class[] {int.class,int.class});
//方法的反射操作:用m對象來進行操作,和a1.print(0的效果一樣
//方法如果沒有返回值返回null,有返回值就返回具體的值
Object o=m.invoke(a1,10,20);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
try {
Method ms=c.getMethod("print", String.class,String.class);
Object o1=ms.invoke(a1, "Hello","World");
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class A {
public void print(int a,int b){
System.out.println(a+b);
}
public void print(String a,String b){
System.out.println(a.toUpperCase()+","+b.toUpperCase());
}
}
七:通過Class,Method瞭解集合泛型的本質
public class Demo6 {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
ArrayList list=new ArrayList();
ArrayList<Integer >list1=new ArrayList<Integer>();
list1.add(1);
//list1.add("string");是錯誤的
Class c1=list.getClass();
Class c2=list1.getClass();
System.out.println(c1==c2); //return true;說明編譯之後集合的泛型是去泛型化的
//反射的操作都是編譯之後的操作
/*
* java中集合的泛型,是防止錯誤消息的輸入,只在編譯階段有效果,繞過編譯就無效了
* 我們可以通過方法的反射來驗證:
*/
try {
Method m=c1.getMethod("add",Object.class);
Object o=m.invoke(list1, "fanxing");//繞過編譯操作就繞過了泛型
System.out.println(list1.size());
System.out.println(list1);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
最後進行一下總結:
我們要用到反射,首先要獲取類,獲取類有三種方法:
1):通過類.class來獲取
2):通過類實例化之後的對象.getclass()方法來獲取
3):通過class.forName("類名")來獲取,這也是動態加載,在這裏還要分清楚動態加載和靜態加載的區別
我們獲取到類之後就可以通過方法來獲取類中的成員變量(getField),方法(getMethod),方法中的參數列表類型(getParamType),構造函數(getConstructor),進而獲得他們的類類型和名稱。
當有了這些基礎之後我們就可以來進行方法的反射操作,還可以驗證泛型的本質。