1.Java反射機(jī)制
1.1 反射機(jī)制是什么
在運(yùn)行狀態(tài)中,對于任意一個(gè)類都能夠知道這個(gè)類所有的屬性和方法;并且對于任意一個(gè)對象,都能夠調(diào)用它的任意一個(gè)方法;這種動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的功能為Java語言的反射機(jī)制。
1.2 反射的應(yīng)用場合
程序在運(yùn)行時(shí)可能接受到外部傳入的對象,該對象的編譯時(shí)類型為Object,但是程序有需要改對象的運(yùn)行時(shí)類型的方法。
為了解決這些問題,程序需要在運(yùn)行時(shí)發(fā)現(xiàn)對象和類的真實(shí)信息。
如果編譯時(shí)根本無法預(yù)知該對象和類屬于哪些類,比如這些類都是以字符串形式存放在配置文件中的時(shí)候,程序只能依靠運(yùn)行時(shí)信息來發(fā)現(xiàn)該對象和類的真實(shí)信息,此時(shí)必須使用反射了。
1.3 反射的常用類
- Class類(模板類):java.lang.Class 反射的核心類,可以獲取類的屬性、方法等信息;
- Field類:java.lang.reflec包中的類,表示類的成員變量,可以用來獲取和設(shè)置類之中的屬性值;
- Method類:Java.lang.reflec包中的類,表示類的方法,它可以用來獲取類中的方法信息或者執(zhí)行方法;
- Constructor類:Java.lang.reflec包中的類,表示類的構(gòu)造方法。
1.4 反射使用步驟
① 獲取想要操作的類的Class對象,他是反射的核心,通過Class對象我們可以任意調(diào)用類的方法;
② 調(diào)用Class類中的方法,即就是反射的使用階段;
③ 使用反射API來操作這些信息。
- 類的對象:基于某個(gè)類new出來的對象,也稱為實(shí)例對象。
- 類對象:類加載的產(chǎn)物,封裝了一個(gè)類的所有信息
————類名、父類、接口、屬性、方法、構(gòu)造方法
2. Class類
位置:java.lang.Class
- 類對象,類的實(shí)例代表一個(gè)運(yùn)行 類 java應(yīng)用程序的類和接口。
public final class Class<T>
extends Object
implements Serializable, GenericDeclaration, Type, AnnotatedElement
2.1 常用方法和示例
常用方法:
String getName()
返回由 類對象表示的實(shí)體(類,接口,數(shù)組類,原始類型或空白)的名稱,作為 String 。
static Class<?> forName(String className)
獲取類對象名
Package getPackage()
獲取類對象的包名
Class<? super T> getSuperclass()
獲取父類的類對象名
Class<?>[] getInterfaces()
獲取接口的類對象名
Constructor<?>[] getConstructors()
獲取構(gòu)造方法
Class<?>[] getParameterTypes()
獲取方法(構(gòu)造/成員)的參數(shù)類型列表
Field[] getFields()
獲取屬性(自身+父類的所有public公開屬性)
Field[] getDeclaredFields()
獲取屬性(自身所有的屬性)
Method[] getMethods()
獲取方法(自身+父類單繼承疊加的所有public公開方法)
Method[] getDeclaredMethods()
獲取方法(自身所有的方法)
T newInstance()
創(chuàng)建由此類對象表示的類的新實(shí)例(此類對象必須有無參構(gòu)造)。
方法使用示例:
public class TestClassMethods {
public static void main(String[] args) throws Exception {
// 獲取類對象
Class<?> c = Class.forName("com.day.methods.Student");
System.out.println(c.getName()); // com.day.methods.Student
// 獲得指定類對象的包名
Package pack = c.getPackage();
System.out.println(pack.getName()); // com.day.methods
// 獲得父類的類對象
Class<?> superClass = c.getSuperclass();
System.out.println(superClass.getName()); // com.day.methods.Person
// 獲得接口的類對象
Class<?>[] interfaces = c.getInterfaces();
for (Class<?> inter : interfaces) {
// java.io.Serializable java.lang.Runnable java.lang.Comparable
System.out.print(inter.getName() + " ");
}
// 獲取屬性(自身+父類的public公開屬性)
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.print(field.getName() + " "); // name age name money
}
// 獲取屬性(自身所有的屬性)
Field[] fields2 = c.getDeclaredFields();
for (Field field : fields2) {
System.out.print(field.getName() + " "); // name age score
}
System.out.println("\n---------------------");
// 獲取方法(自身+父類單繼承疊加的所有public公開方法)
Method[] methods = c.getMethods();
for (Method method : methods) {
// run compareTo exam play sleep eat wait wait wait equals toString hashCode getClass notify notifyAll
System.out.print(method.getName() + " ");
}
System.out.println("\n---------------------");
// 獲取方法(自身所有的方法)
Method[] methods2 = c.getDeclaredMethods();
for (Method method : methods2) {
// run:void compareTo:int play:void exam:void
System.out.println(method.getName() + ":" + method.getReturnType());
}
System.out.println("*************************");
// 獲取構(gòu)造方法
Constructor<?>[] cs = c.getConstructors();
for (Constructor<?> cc : cs) {
// com.day.methods.Student:java.lang.String int
// com.day.methods.Student:java.lang.String
// com.day.methods.Student: (無參構(gòu)造)
System.out.print(cc.getName() + ":");
Class<?>[] param = cc.getParameterTypes();
for (Class<?> p : param) {
System.out.print(p.getName() + " ");
}
System.out.println();
}
System.out.println();
// new一個(gè)實(shí)例對象(必須要有無參構(gòu)造)
Object o = c.newInstance();
Student stu = (Student)o;
System.out.println(stu); // com.day.methods.Student@3d4eac69
}
}
class Person {
public String name;
public double money;
public Person() {}
public void eat() {}
public void sleep() {}
}
@SuppressWarnings({ "serial", "rawtypes" })
class Student extends Person implements Serializable, Runnable, Comparable{
public String name;
public int age;
double score;
public Student() {super();}
public Student(String name) {}
public Student(String name, int age) {}
public void exam() {}
public void play() {}
@Override
public void run() {}
@Override
public int compareTo(Object o) { return 0; }
}
2.2 獲取Class對象的 3 種方法
① 通過類的對象,獲取Class對象
② 通過類名獲取一個(gè)Class對象
③ 通過Class的靜態(tài)方法forName()獲取類對象 【最具普適性】
public class TestGetClassObject {
public static void main(String[] args) throws ClassNotFoundException {
// 1.通過類的對象,獲取Class對象
Person p = new Person(); // 類的對象
Class<? extends Person> c = p.getClass();
System.out.println(c.getName());
// 2.通過類名獲取一個(gè)Class對象
Class<Person> c2 = Person.class;
System.out.println(c2.getName());
// 3.通過Class的靜態(tài)方法獲取類對象 【最具普適性】
Class<?> c3 = Class.forName("com.day.reflect.Person");
System.out.println(c3.getName());
}
// 更通用的獲取類對象的方法
public static Class<?> getClassObject(String className) {
Class<?> c = null;
try {
c = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return c;
}
}
class Person {
}
2.3 反射創(chuàng)建對象的 2 種方法
① 反射通過類對象創(chuàng)建類的對象
② 方法傳參返回對象【普適性】
public class TestNewInstance {
public static void main(String[] args) throws Exception {
// 手工new對象
Teacher t = new Teacher();
t.name = "JJ";
System.out.println(t.name);
// 1.反射通過類對象創(chuàng)建類的對象
Class<?> c = Class.forName("com.day.methods.Teacher");
Teacher t2 = (Teacher)c.newInstance();
t2.name = "Jerry";
System.out.println(t2.name);
// 2.方法傳參返回對象【普適性】
Teacher t3 = (Teacher)createObject("com.day.methods.Teacher");
System.out.println(t3);
}
public static Object createObject(String className) {
try {
Class<?> c = Class.forName(className);
return c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
class Teacher {
String name;
public Teacher() { }
}
3. 工廠設(shè)計(jì)模式(示例)
- 開發(fā)中有一個(gè)非常重要的原則“開閉原則”,對拓展開放、對修改關(guān)閉;
- 工廠模式主要負(fù)責(zé)對象創(chuàng)建的問題;
- 可通過反射進(jìn)行工廠模式的設(shè)計(jì),完成動態(tài)的對象創(chuàng)建。
public class TestNewInstanceForFile {
public static void main(String[] args) throws Exception {
// 創(chuàng)建出入流對象
FileReader fr = new FileReader("files\\application.txt");
BufferedReader br = new BufferedReader(fr);
// 讀出文件中的類的全限定名
String className = br.readLine();
// 創(chuàng)建Object對象返回后進(jìn)行強(qiáng)轉(zhuǎn)為對應(yīng)類型,進(jìn)而使用
Teacher t3 = (Teacher)createObject(className);
System.out.println(t3);
br.close();
}
/**
* 工廠:創(chuàng)建對象工廠
* @param className String類型的類的全限定名
* @return Object Object類型的對象
*/
public static Object createObject(String className) {
try {
Class<?> c = Class.forName(className);
return c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
/*
* files\\application.txt 內(nèi)容:
* com.methods.Teacher
*/