JavaSE 反射機制(上)
前言:反射概述
前提:jvm已加載類。
現在給jvm一個類名,能不能知道類的具體信息?能,通過反射機制。
電腦的反射機制,就是通過一個抽象的類名能夠在自己記憶(加載類的內存)中找到相匹配的類的具體信息。
Java Reflection
Reflection(反射)是被視爲動態語言的關鍵,反射機制允許程序在執行期藉助於Reflection API取得任何類的內部信息,並能直接操作任意對象的內部屬性及方法。
- Java反射機制提供的功能
- 在運行時判斷任意對象所屬的類
- 在運行時構造任意一個類的對象
- 在運行時判斷任意一個類所具有的成員變量和方法
- 在運行時調用任意一個對象的成員變量和方法
- 生成動態代理
- 反射相關的主要API:
- java.lang,Class 代表一個類
- java.lang.reflect.Method 代表類的方法
- java.lang.reflect.Field 代表類的成員變量
- java.lang.reflect.Constructor 代表類的構造方法
一、Class類
在Object類中定義了以下方法,此方法將被所有子類繼承:
public final Class getClass()
以上的方法返回值的類型是一個Class類,此類是Java反射的源頭,實際上所謂反射從程序的運行結果來看很好理解,即:可以通過對象反射求出類的名稱。
反射可以得到的信息:某個類的屬性、方法和構造器、某個類到底實現了哪個接口。對於每個類而言,JRE都爲其保留一個不變的Class類型的對象。一個Class對象包含了特定某個類的有關信息。
-
Class 概述
-
Class本身也是一個類
-
Class對象只能由系統建立對象
-
一個類在JVM中只能有一個Class實例
-
一個Class對象對應的是一個加載到JVM中的一個.class文件
-
每個類的實例都會記得自己是由哪個Class實例所生成
-
通過Class可以完整地得到一個類中的完整結構
-
-
實例化Class類對象(四種方法)
- 通過
類名.class
創建指定類的Class實例 - 通過
一個類的實例對象.getClass()
獲取對應實例對象的類的Class實例 - 通過Class的靜態方法
forName()
來獲取類的Class實例(常用!) - ClassLoader(不做介紹)
- 通過
-
Class 類的常用方法(!!!)
方法名 功能 static Class forName(String name) 根據類的全類名(包名+類名)獲取Class對象 Object newInstance() 創建目標類對象 getName() 獲取全類名 Class getSuperclass() 獲取父類的Class對象 Class[] getInterfaces() 獲取所有實現的接口,返回類的數組 ClassLoader getClassLoader() 獲取類的類加載器 Constuctor[] getConstructors() 獲取所有的公有構造器(public修飾 ) Constructor[] getDeclaredConstructors() 獲取類的所有構造方法(包括公有私有) getModifiers() 獲取構造方法的修飾符(public–>1; private–>2) Class[] getParameterTypes() 獲取構造方法的參數類型,參數個數爲返回數組的元素個數
二、Class類常用方法案例
以上方法的案例展示:(其中包含父類、兩個接口、子類以及測試類)
package com.reflection;
//父類
public class Person {
public String name;
int age;
}
package com.reflection;
//接口:Move
public interface Move {
void moveType();
}
package com.reflection;
//接口:Study
public interface Study {
void studyInfo();
}
package com.reflection;
//子類(繼承父類,並實現兩個接口)
public class Student extends Person implements Move, Study{
String school;
//無參構造
public Student(){
System.out.println("調用的是public Student()");
}
//有參構造
public Student(String school){
System.out.println("調用的是public Student(String school)");
this.school = school;
}
//私有有參構造
private Student(String name, int age){
System.out.println("調用的是private Student(String name, int age)");
this.name = name;
this.age = age;
}
void showInfo(){
System.out.println("學校是:" + this.school);
}
@Override
public void moveType() {
System.out.println("騎自行車上學");
}
@Override
public void studyInfo() {
System.out.println("學習中學知識");
}
}
package com.reflection;
//測試類
import java.lang.reflect.Constructor;
public class Test1 {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.reflection.Student"); //獲取指定類的Class實例
Class superClazz = clazz.getSuperclass(); //獲取父類
System.out.println("父類: " + superClazz.getName());
Class[] interfaces = clazz.getInterfaces();//獲取當前類的所有接口
for (Class i : interfaces) {
System.out.println("接口: " + i.getName());
}
System.out.println("===============================================");
//獲取公有構造器,內含獲取參數類型
//修飾符爲1,表示public修飾; 修飾符爲2,表示private修飾
Constructor[] cons = clazz.getConstructors(); //僅能求出公有的構造方法
for (Constructor con : cons) {
System.out.println("構造方法名稱: " + con.getName() + "的修飾符是: " + con.getModifiers());
Class[] paramClazz = con.getParameterTypes(); //獲取構造方法的參數類型,參數個數爲數組元素個數
for (Class pc : paramClazz) {
System.out.println("構造方法: " + con.getName()+ "的參數類型是: " + pc.getName());
}
System.out.println();
}
System.out.println("===============================================");
//獲取所有構造器(公有+私有),內含獲取參數類型
Constructor[] cons1 = clazz.getDeclaredConstructors(); //獲取類的所有構造方法,包括公有的和私有的
for (Constructor c : cons1) {
System.out.println("構造方法名稱: " + c.getName() + "的修飾符是: " + c.getModifiers());
Class[] paramClazz = c.getParameterTypes(); //獲取構造方法的參數類型,參數個數爲數組元素個數
for (Class pc : paramClazz) {
System.out.println("構造方法: " + c.getName()+ "的參數類型是: " + pc.getName());
}
System.out.println();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
/*運行結果:
父類: com.reflection.Person
接口: com.reflection.Move
接口: com.reflection.Study
===============================================
構造方法名稱: com.reflection.Student的修飾符是: 1
構造方法: com.reflection.Student的參數類型是: java.lang.String
構造方法名稱: com.reflection.Student的修飾符是: 1
===============================================
構造方法名稱: com.reflection.Student的修飾符是: 2
構造方法: com.reflection.Student的參數類型是: java.lang.String
構造方法: com.reflection.Student的參數類型是: int
構造方法名稱: com.reflection.Student的修飾符是: 1
構造方法: com.reflection.Student的參數類型是: java.lang.String
構造方法名稱: com.reflection.Student的修飾符是: 1
*/
三、通過反射創建一個對象
Person類、Student類、Move接口、Study接口 同(二)中案例。
現編寫Test2類如下:
package com.reflection;
import java.lang.reflect.Constructor;
public class Test2 {
public static void main(String[] args) {
try {
Class clazz1 = Class.forName("com.reflection.Student");
//如何用反射的構造方法來創建對象
try {
Object obj = clazz1.newInstance(); //相當於調用Student類的無參公有構造方法
Student stu = (Student)obj;
System.out.println(stu.school);
System.out.println("---------------------------------------");
Constructor c1 = clazz1.getConstructor(String.class);//指定獲取有一個參數爲String類型的共有的構造方法
Student stu1 = (Student)c1.newInstance("第一中學"); //通過newInstance實例話對象,相當於調用public Student(String school)
System.out.println(stu1.school);
System.out.println("---------------------------------------");
//調用私有構造方法,通過反射機制強制調用
Constructor c2 = clazz1.getDeclaredConstructor(String.class,int.class); //指定獲取有兩個參數(String, int)的構造方法
c2.setAccessible(true); //解除私有封裝
Student stu2 = (Student)c2.newInstance("zhangsan",12);
System.out.println("---------------------------------------");
} catch (Exception e){
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
/*運行結果
調用的是public Student()
null
---------------------------------------
調用的是public Student(String school)
第一中學
---------------------------------------
調用的是private Student(String name, int age)
---------------------------------------
*/
注: 注意各個構造器的調用方式。
寫在最後
祝你有個好心情,無論何時何地!
To Demut and Dottie!