能夠分析類能力的程序稱為反射。對於給定的Java類名,可以通過反射獲取類的信息、將類的各成分映射出相應的Java類。
在程序運行期間,Java運行時系統始終對所有的對象維護一個被稱為運行時的類型標識。這個信息跟蹤著每個對象所屬的類。虛擬機利用運行時類型信息選擇相應的方法執行。可以通過專門的Java類訪問這些信息。保存這些信息的類被稱為Class。
創建Class類對象的三種方法:
1. 通過getClass方法
Object中的getClass方法將返回一個Class類型的實例。
class Person {
//...
}
Person p = new Person();
Class c = p.getClass();
2. forName方法
可以通過靜態方法forName獲得類名對應的Class對象。
String className = "java.util.Date"; Class c = Class.forName(className);
如果需要在運行過程中需要改變類名,就可以使用這種方法。當然,字符串className必須是一種類名或接口(包括包名),否則會出現異常。
3. T.class
Class c1 = Date.class; Class c2 = int.class; Class c3 = Double[].class;
T表示任意的Java類型。通過T.class獲取匹配的類對象。
注意:一個Class對象實際表示一種類型,而這種類型未必是一種類。
虛擬機為每個類型管理一個Class對象。因此可以用==運算符來實現兩個類對象的比較
if (p.getClass() == Person.class) {...}
通過newInstance方法可以創建一個類的實例。
Person person = p.getClass().newInstance();
創建了一個與p具有相同類類型的實例。newInstance調用默認的構造器初始化創建的對象。如果這個類沒有默認的構造器,就會拋出異常。
package com.xiaoxiaoyihan.reflection;
class Person {
//...
}
class Student extends Person{
}
public class ReflectionDemo1 {
public static void main(String[] args) {
Student s = new Student();
Class cl = s.getClass();
Class superCl = cl.getSuperclass();
System.out.println("獲取類名:" + cl.getName());
System.out.println("獲取父類名:" + superCl.getName());
}
}
【運行結果】:
獲取類名:com.xiaoxiaoyihan.reflection.Student
獲取父類名:com.xiaoxiaoyihan.reflection.Person
說明:如果類在一個包中,包的名字也作為類名的一部分。
一點擴展:
首先看一個例子:
class Person {
private String name = "蕭蕭弈寒";
// 省略setter和getter
}
class Animal {
private String name = "paqi";
// 省略setter和getter
}
Person p;
Animal a;
Class cPerson = p.getClass();
Class cAnimal = a.getClass();
// cPerson.getName()獲取的是類名、p.getName()是Person實例的name屬性值
System.out.println(cPerson.getName() + "<--->" + p.getName());
System.out.println(cAnimal.getName() + "<--->" + p.getName());
【運行結果】:
com.xxyh.reflec.Person<--->蕭蕭弈寒
com.xxyh.reflec.Animal<--->paqi
由此說明,一個Person對象p表示一個特定人的屬性,一個Animal對象a表示一個特定動物的屬性,一個Class對象表示一個特定類(Person或Animal)的屬性。從這點看,Class的實例是一種對象。
Class類中的getConstructors方法將返回公共構造器數組。Class類中的getDeclaredConstructors將返回類中聲明的構造器數組。
package com.xiaoxiaoyihan.reflection;
import java.lang.reflect.Constructor;
class Person {
private String name;
private int age;
private Person() {}
protected Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class ReflectionDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
Class cl = Class.forName("com.xiaoxiaoyihan.reflection.Person"); // 直接拋出異常以簡化代碼
Constructor[] constructors = cl.getDeclaredConstructors();
//Constructor[] constructors = cl.getConstructors();
for (Constructor c :constructors) {
System.out.println(c);
}
}
}
【運行結果】:
private com.xiaoxiaoyihan.reflection.Person()
protected com.xiaoxiaoyihan.reflection.Person(java.lang.String)
public com.xiaoxiaoyihan.reflection.Person(java.lang.String,int)
// public com.xiaoxiaoyihan.reflection.Person(java.lang.String,int)// 本部分為運行getConstructors方法輸出結果
對結果加以分析,會發現通過System.out.println(c);直接打印的構造函數是由幾部分組成的,其中包括了修飾符(public/protected/private)、類名以及構造函數的參數,那麼,這些部分是如何獲取的呢?
在Modifier類中包含靜態方法getModifiers方法,它返回一個整數i,用不同的數值表示public、static、final這樣的修飾符。Modifier中的靜態方法toString(i)返回對應的修飾符。Constructor類中包含由靜態方法getParameterTypes,它返回一個描述參數類型的Class對象數組。
package com.xiaoxiaoyihan.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
class Person {
private String name;
private int age;
private Person() {}
protected Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class ReflectionDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
Class cl = Person.class;
Constructor[] constructors = cl.getDeclaredConstructors();
for (Constructor c :constructors) {
// 獲取包名和類名
String name = c.getName();
// 獲取修飾符
String modifiers = Modifier.toString(c.getModifiers());
if (modifiers.length() > 0) { //如果有修飾符
System.out.print(modifiers + " ");
}
System.out.print(name + "(");
// 獲取構造函數的參數類型
Class[] paramTypes = c.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
if (i > 0) { // 如果不止一個參數,使用","將參數類型分割
System.out.print(",");
}
System.out.print(paramTypes[i].getName());
}
System.out.println(");");
}
}
}
【運行結果】:
private com.xiaoxiaoyihan.reflection.Person();
protected com.xiaoxiaoyihan.reflection.Person(java.lang.String);
public com.xiaoxiaoyihan.reflection.Person(java.lang.String,int);
Class類中的getMethods將返回方法的數組,其中包括本類的所有方法、從接口實現的方法、父類的公共(public)方法、父類的父類的公共方法……一直延伸到Object的公共方法。getDeclaredMethods方法將返回本類聲明的方法、從接口實現的方法。
package com.xiaoxiaoyihan.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
class Person/* extends Object */ {
private void privateMethodPerson() {
//...
}
protected void protectedMethodPerson() {
// ...
}
public void publicMethodPerson() {
//...
}
}
interface Smoke {
void smoking();
}
class Student extends Person implements Smoke{
@Override
public void smoking() {
// ...
}
private void privateMethodStudent() {
//...
}
protected void protectedMethodStudent() {
// ...
}
public void publicMethodStudent() {
//...
}
}
public class ReflectionDemo1 {
public static void main(String[] args) {
Student s = new Student();
Class cl = s.getClass();
Method[] methods = cl.getDeclaredMethods();
// Method[] methods = cl.getMethods();
for (Method m : methods) {
System.out.println(m);
}
}
}
【運行結果】:
public void com.xiaoxiaoyihan.reflection.Student.smoking()
protected void com.xiaoxiaoyihan.reflection.Student.protectedMethodStudent()
private void com.xiaoxiaoyihan.reflection.Student.privateMethodStudent()
public void com.xiaoxiaoyihan.reflection.Student.publicMethodStudent()
上面的例子故意給出一種繼承結構,是為了查看getMethods的結果,在此就不給出結果了。注意Person默認繼承了Object類。順便說一句,筆者(非科班自學菜鳥)曾在面試的時候被問到Object中有哪些方法,估計他是想問有哪些常用方法吧,我沒答全~2333,不知道讀者您能一眼看出結果嗎??。
類似地,我們看到上面的System.out.println(m);打印出方法由修飾符、返回值、類名、方法名以及參數組成。那麼這些部分是如果獲取的呢? 與Construction類相似,Method類中也提供了靜態方法getParamTypes,該方法返回描述參數類型的Class對象數組。此外,Method還提供了getReturnType方法,用於獲取返回類型的Class對象。
package com.xiaoxiaoyihan.reflection;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
class Person {
private String name = "蕭���弈寒";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void speak() {
// ...
}
public final void eat() {
// ...
}
}
public class ReflectionDemo1 {
public static void main(String[] args) {
Class cl = Person.class;
Method[] methods = cl.getDeclaredMethods();
for (Method m : methods) {
// 返回類型的Class對象
Class retType = m.getReturnType();
//
String retTypeName = retType.getName();
// 獲取方法名
String name = m.getName();
String modifiers = Modifier.toString(m.getModifiers());
if (modifiers.length() > 0) // 如果有修飾符
System.out.print(modifiers + " ");
// 返回值名
System.out.print(retType.getName() + " ");
System.out.print(name + "(");
Class[] paramTypes = m.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
if (i > 0) { // 如果不止一個參數,用","分割
System.out.print(paramTypes[i].getName());
}
}
System.out.println(");");
}
}
}
【運行結果】:
public java.lang.String getName();
public void setName();
public static void speak();
public final void eat();
Class類中的getDeclaredFields方法返回類中聲明的域數組,getFields方法返回類中的公有域、接口中的域所組成的Field對象數組。
package com.xiaoxiaoyihan.reflection;
import java.lang.reflect.Field;
import java.util.Date;
class Person {
private String name;
protected int age;
public Date birthday;
}
class Student extends Person implements Smoke{
private float score;
}
interface Smoke {
String brand = "大中華";
}
public class ReflectionDemo1 {
public static void main(String[] args) {
Class cl = Student.class;
Field[] fields = cl.getFields();
for (Field f : fields) {
System.out.println(f);
}
}
}
【運行結果】:
public static final java.lang.String com.xiaoxiaoyihan.reflection.Smoke.brand
public java.util.Date com.xiaoxiaoyihan.reflection.Person.birthday
結果顯示了字段由修飾符、類型、類名、字段名構成。這裡需要引入Field類中的getType方法,它返回字段聲明類型的Class對象。下面同樣作出解析:
package com.xiaoxiaoyihan.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Date;
class Person {
private String name;
protected int age;
public Date birthday;
}
public class ReflectionDemo1 {
public static void main(String[] args) {
Class cl = Person.class;
Field[] fields = cl.getDeclaredFields();
for (Field f : fields) {
// 屬性類型的Class對象
Class type = f.getType();
// 屬性類型名
String name = type.getName();
System.out.print(" ");
// 修飾符
String modifiers = Modifier.toString(f.getModifiers());
if (modifiers.length() > 0) { // 如果有修飾符
System.out.print(modifiers + " ");
}
System.out.println(type.getName() + " " + name + ";");
}
}
}
【運行結果】:
private java.lang.String java.lang.String;
protected int int;
public java.util.Date java.util.Date;
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2015-11/124809p2.htm