概念
JAVA反射機(jī)制是在運行狀態(tài)中养叛,對于任意一個類翠忠,都能夠知道這個類的所有屬性和方法;對于任意一個對象盗温,都能夠調(diào)用它的任意一個方法和屬性;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機(jī)制成肘。
要想解剖一個類,必須先要獲取到該類的字節(jié)碼文件對象卖局。而解剖使用的就是Class類中的方法。所以先要獲取到每一個字節(jié)碼文件對應(yīng)的Class類型的對象艇劫。-
類加載過程
image.png
Class類的實例表示正在運行的Java應(yīng)用程序中的類和接口吼驶。每個類只會產(chǎn)生一個Class對象惩激,在類加載的時候自動創(chuàng)建。
獲取class方式
public class ClassTest {
public static void main(String[] args) {
try {
// 通過Class.forName獲取
Class<?> aClass = Class.forName("clas.User");
System.out.println(aClass.getSimpleName());
System.out.println("---------------");
// 通過類明.class獲取
Class<User> userClass = User.class;
System.out.println(userClass.getSimpleName());
System.out.println("---------------");
// 通過對象getClass()獲取
Class<? extends User> aClass1 = new User().getClass();
System.out.println(aClass1.getSimpleName());
// 如果是基本類型 可以通過TYPE獲取
Class<Integer> integerClass = Integer.class;
Class<Integer> type = Integer.TYPE;
System.out.println(integerClass.getSimpleName());
System.out.println(type.getSimpleName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
- Class 部分方法使用
父類Person
public class Person {
public String name;
private String age;
public void say1(String a){
System.out.println("is person say1"+a);
}
private void say2(){
System.out.println("is person say2");
}
}
子類User
public class User extends Person{
public String className;
private String teachName;
public User() {
}
private User(String className) {
this.className = className;
}
public User(String className, String teachName) {
this.className = className;
this.teachName = teachName;
}
public void read1(String a){
System.out.println("is user read1"+a);
}
private void read2(String a){
System.out.println("is user read2"+a);
}
public String getTeachName() {
return teachName;
}
public void setTeachName(String teachName) {
this.teachName = teachName;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
@Override
public String toString() {
return "User{" +
"className='" + className + '\'' +
", teachName='" + teachName + '\'' +
'}';
}
}
需要注意上面兩個類的屬性和方法的訪問修飾符
測試類
public class ClassApi {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("clas.User");
// 獲取成員變量,包含子類和父類蟹演,只能是public修飾的屬性
Field[] fields = clazz.getFields();
System.out.println("*****獲取成員變量,包含子類和父類风钻,只能是public修飾的屬性******");
for (Field field : fields) {
System.out.println(field);
System.out.println("------------");
}
System.out.println("*****返回當(dāng)前類的所有屬性*******");
//返回當(dāng)前類的所有屬性,與訪問修飾符無關(guān)酒请。排除父類骡技。
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
System.out.println("--------");
}
System.out.println("*****訪問私有屬性*******");
// 訪問私有屬性
Field teachName = clazz.getDeclaredField("teachName");// 這是一個私有屬性
teachName.setAccessible(true);//破壞封裝性
User o = (User) clazz.newInstance();
teachName.set(o,"張三");
System.out.println(o.getTeachName());
// 獲取普通方法,當(dāng)前對象以及父類對象的所有公共方法
Method[] methods = clazz.getMethods();
System.out.println("*****獲取普通方法,當(dāng)前對象以及父類對象的所有公共方法*******");
for (Method method : methods) {
System.out.println(method);
System.out.println("--------");
}
//獲取當(dāng)前類的所有方法羞反,與修飾詞無關(guān)
Method[] declaredMethods = clazz.getDeclaredMethods();
System.out.println("*****獲取當(dāng)前類的所有方法翎嫡,與修飾詞無關(guān)*******");
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
System.out.println("--------");
}
// 訪問當(dāng)前類私有方法
System.out.println("*****訪問當(dāng)前類私有方法*******");
Method read1 = clazz.getDeclaredMethod("read1", String.class);
read1.invoke(o,"讀英語");
Method read2 = clazz.getDeclaredMethod("read2", String.class);//這是一個私有方法
read2.setAccessible(true);//沒有設(shè)置該屬性會報IllegalAccessException
read2.invoke(o,"讀語文");
// 無法獲取父類的方法噢 NoSuchMethodException
//Method say1 = clazz.getDeclaredMethod("say1", String.class);
//如何獲取父類的私有屬性呢?
//先得到父類class
System.out.println("*****獲取父類的私有屬性和方法*******");
Class<?> superclass = clazz.getSuperclass();
Field[] declaredFields1 = superclass.getDeclaredFields();
Method[] declaredMethods1 = superclass.getDeclaredMethods();
for (Field field : declaredFields1) {
System.out.println(field);
}
System.out.println("----方法----");
for (Method method : declaredMethods1) {
System.out.println(method);
}
// 獲取構(gòu)造方法 ,不能訪問父類構(gòu)造方法猴鲫,構(gòu)造方法不會繼承
System.out.println("*****獲取構(gòu)造方法敷燎,公有的*******");
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("----獲取構(gòu)造方法,公有的與私有的----");
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
// 訪問私有構(gòu)造方法
System.out.println("----訪問私有構(gòu)造方法----");
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(String.class);//私有的
declaredConstructor.setAccessible(true);
User obj = (User) declaredConstructor.newInstance("李四");
System.out.println(obj);
} catch (ClassNotFoundException | NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
打印結(jié)果
*****獲取成員變量,包含子類和父類澄惊,只能是public修飾的屬性******
public java.lang.String clas.User.className
------------
public java.lang.String clas.Person.name
------------
*****返回當(dāng)前類的所有屬性*******
public java.lang.String clas.User.className
--------
private java.lang.String clas.User.teachName
--------
*****訪問私有屬性*******
張三
*****獲取普通方法唆途,當(dāng)前對象以及父類對象的所有公共方法*******
public java.lang.String clas.User.toString()
--------
public java.lang.String clas.User.getClassName()
--------
public void clas.User.read1(java.lang.String)
--------
public java.lang.String clas.User.getTeachName()
--------
public void clas.User.setClassName(java.lang.String)
--------
public void clas.User.setTeachName(java.lang.String)
--------
public void clas.Person.say1(java.lang.String)
--------
public final void java.lang.Object.wait() throws java.lang.InterruptedException
--------
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
--------
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
--------
public boolean java.lang.Object.equals(java.lang.Object)
--------
public native int java.lang.Object.hashCode()
--------
public final native java.lang.Class java.lang.Object.getClass()
--------
public final native void java.lang.Object.notify()
--------
public final native void java.lang.Object.notifyAll()
--------
*****獲取當(dāng)前類的所有方法,與修飾詞無關(guān)*******
public java.lang.String clas.User.toString()
--------
public java.lang.String clas.User.getClassName()
--------
public void clas.User.read1(java.lang.String)
--------
private void clas.User.read2(java.lang.String)
--------
public java.lang.String clas.User.getTeachName()
--------
public void clas.User.setClassName(java.lang.String)
--------
public void clas.User.setTeachName(java.lang.String)
--------
*****訪問當(dāng)前類私有方法*******
is user read1讀英語
is user read2讀語文
*****獲取父類的私有屬性和方法*******
public java.lang.String clas.Person.name
private java.lang.String clas.Person.age
----方法----
public void clas.Person.say1(java.lang.String)
private void clas.Person.say2()
*****獲取構(gòu)造方法掸驱,公有的*******
public clas.User(java.lang.String,java.lang.String)
public clas.User()
----獲取構(gòu)造方法肛搬,公有的與私有的----
public clas.User(java.lang.String,java.lang.String)
private clas.User(java.lang.String)
public clas.User()
----訪問私有構(gòu)造方法----
User{className='李四', teachName='null'}
Process finished with exit code 0