在Java中简烤,可以利用反射獲取指定類型的公有/私有屬性、方法距糖,生成該類的實(shí)例對(duì)象娶吞,并調(diào)用該對(duì)象的方法垒迂。
以下反射相關(guān)的幾個(gè)案例:
ClassDemo1.java
package one;
public class ClassDemo1 {
public static void main(String[] args) {
//Foo的實(shí)例對(duì)象
Foo foo1 = new Foo();
//任何一個(gè)類都是Class類的實(shí)例對(duì)象,有三種表示方法
//第一種表示方式-->任何一個(gè)類都有一個(gè)隱含的靜態(tài)成員變量class
Class c1 = Foo.class;
//第二種表達(dá)方式,已知該類的對(duì)象通過個(gè)體Class方法
Class c2 = foo1.getClass();
/*
* c1妒蛇,c2表示了父類的類類型(class type)
* 萬事萬物皆對(duì)象
* 類也是對(duì)象机断,是Class類的實(shí)例對(duì)象
* 這個(gè)對(duì)象我們稱為該類的類類型
*/
//不管c1或者c2都代表了Foo類的類類型楷拳,一個(gè)類只可能是Class類的一個(gè)實(shí)例對(duì)象
System.out.println(c1 == c2);
//第三種表達(dá)方式
Class c3 = null;
try {
c3 = Class.forName("one.Foo");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c2 == c3);
//我們完全可以通過類的類類型創(chuàng)建該類的對(duì)象-->通過c1或c2或c3創(chuàng)建Foo的實(shí)例
try {
Foo foo = (Foo)c1.newInstance();//需要有無參數(shù)的構(gòu)造方法
foo.print();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
class Foo {
void print() {
System.out.println("hahahaha");
}
}
ClassDemo1運(yùn)行結(jié)果
ClassDemo2.java
package one;
public class ClassDemo2 {
public static void main(String[] args) {
Class c1 = int.class;//int的類類型
Class c2 = String.class;//String的類類型
Class c3 = double.class;
Class c4 = Double.class;
Class c5 = void.class;
System.out.println(c1.getName());
System.out.println(c2.getName());
System.out.println(c2.getSimpleName());//不含包名的類名稱
}
}
ClassDemo2運(yùn)行結(jié)果
ClassUtil.java
package one;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ClassUtil {
/**
* 打印類的信息,包括類的成員函數(shù)
* @param obj 對(duì)象類
*/
public static void printClassMethodMessage(Object obj) {
//要獲取類的信息 首先要獲取類的類型
Class c = obj.getClass();//傳遞的是哪個(gè)子類的對(duì)象吏奸,c就是該子類的類類型
//獲取類的名稱
System.out.println("類的名稱是:" + c.getName());
/*
* Method類欢揖,方法對(duì)象
* 一個(gè)成員方法就是一個(gè)Method對(duì)象
* getMethods()方法獲取的是所有的public的函數(shù),包括父類繼承來的
* getDeclaredMethods()獲取的是所有該類自己聲明的方法奋蔚,不問訪問權(quán)限
*/
Method[] ms = c.getMethods();//c.getDeclaredMethods();
for (int i = 0; i < ms.length; i++) {
//得到返回值類型的類類型
Class returnType = ms[i].getReturnType();
System.out.print(returnType.getName() + " ");
//得到方法名
System.out.print(ms[i].getName() + "(");
//獲取參數(shù)類型-->得到的是參數(shù)列表的類型的類類型
Class[] paramTypes = ms[i].getParameterTypes();
for (Class class1 : paramTypes) {
//System.out.print(class1.getName() + ",");
System.out.print(class1.getSimpleName() + ",");
}
System.out.println(")");
}
}
/**
* 獲取成員變量的信息
* @param obj 對(duì)象類
*/
public static void printFieldMessage(Object obj) {
Class c = obj.getClass();
/*
* 成員變量也是對(duì)象
* java.lang.reflect.Field
* Field類封裝了關(guān)于成員變量的操作
* getField()方法獲取的是所有的public的成員變量的信息
* getDeclaredFields()獲取的是該類自己聲明的成員變量的信息她混,不管訪問權(quán)限
*/
//Field[] fs = c.getFields();
Field[] fs = c.getDeclaredFields();
for (Field field : fs) {
//得到成員變量的類類型
Class fieldType = field.getType();
String typeName = fieldType.getName();
//得到成員變量的名稱
String fieldName = field.getName();
System.out.println(typeName + " " + fieldName);
}
}
/**
* 打印對(duì)象的構(gòu)造函數(shù)的信息
* @param obj 對(duì)象類
*/
public static void printConMessage(Object obj) {
Class c = obj.getClass();
/*
* 構(gòu)造函數(shù)也是對(duì)象
* java.lang.Constructor中封裝了構(gòu)造函數(shù)的信息
* getConstructors()方法獲取的是所有的public的構(gòu)造函數(shù)的信息
* getDeclaredConstructors()獲取的事該類自己聲明的構(gòu)造函數(shù)的信息,不管訪問權(quán)限
*/
//Constructor[] cs = c.getConstructors();
Constructor[] cs = c.getDeclaredConstructors();
for (Constructor constructor : cs) {
System.out.print(constructor.getName() + "(");
//獲取構(gòu)造函數(shù)的參數(shù)列表-->得到參數(shù)列表的類類型
Class[] paramTypes = constructor.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
}
}
}
ClassDemo3.java
package one;
public class ClassDemo3 {
package one;
public class ClassDemo3 {
public static void main(String[] args) {
String s = "hello";
//打印該類方法信息
ClassUtil.printClassMethodMessage(s);
Integer n1 = 1;
ClassUtil.printClassMethodMessage(n1);
}
}
ClassDemo3運(yùn)行結(jié)果1
ClassDemo3運(yùn)行結(jié)果2
ClassDemo4.java
package one;
public class ClassDemo4 {
public static void main(String[] args) {
//打印該類成員變量信息
ClassUtil.printFieldMessage(new Integer(1));
}
}
ClassDemo4運(yùn)行結(jié)果
ClassDemo5.java
package one;
public class ClassDemo5 {
public static void main(String[] args) {
//打印構(gòu)造方法信息
ClassUtil.printConMessage("hello");
ClassUtil.printConMessage(new Integer(1));
}
}
ClassDemo5運(yùn)行結(jié)果
MethodDemo1.java
package one;
import java.lang.reflect.Method;
public class MethodDemo1 {
public static void main(String[] args) {
//獲取print(int,int)方法
//1.要獲取一個(gè)方法泊碑,首先要獲取類的類類型
A a1 = new A();
Class c = a1.getClass();
/*
* 2.獲取方法 名稱和參數(shù)列表來決定
* getMethod獲取的是public的方法
* getDeclaredMethod獲取自己聲明的方法
*/
try {
// Method m = c.getMethod("print", new Class[]{int.class,int.class});
//獲取print(int,int)方法坤按,其兩個(gè)參數(shù)都是int類型的
Method m = c.getMethod("print", int.class,int.class);
//方法的反射操作
//a1.print(10,20);方法的反射操作是用m對(duì)象來進(jìn)行方法調(diào)用和a1.print調(diào)用的效果一樣
//方法如果沒有返回值返回null,有返回值返回具體的返回值
//Object o = m.invoke(a1,new Object[]{10,20});
Object o = m.invoke(a1, 10,20); //執(zhí)行print(int,int)方法
System.out.println("==========================");
//獲取方法print(String,String)
Method m1 = c.getMethod("print", String.class,String.class);
//用方法進(jìn)行反射操作
//a1.print("hello", "World");
o = m1.invoke(a1, "hello","World"); //執(zhí)行print(String,String)
System.out.println("===========================");
//Method m2 = c.getMethod("print", new Class[]{});
Method m2 = c.getMethod("print"); //獲取沒有參數(shù)的print()方法
m2.invoke(a1); //執(zhí)行print方法
} catch (Exception e) {
e.printStackTrace();
}
}
}
class A {
public void print() {
System.out.println("helloworld");
}
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.toLowerCase());
}
}
MethodDemo1運(yùn)行結(jié)果
MethodDemo4.java
package one;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class MethodDemo4 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
ArrayList<String> list1 = new ArrayList<String>();
list1.add("hello");
//list1.add(1);錯(cuò)誤的
Class c1 = list.getClass();
Class c2 = list1.getClass();
System.out.println(c1 == c2);
//反射的操作都是編譯之后的操作
/*
* c1==c2結(jié)果返回true說明編譯之后的集合的泛型是去泛型化的
* java中集合的泛型是防止錯(cuò)誤輸入的馒过,只在編譯階段有效
* 繞過編譯就無效了
* 驗(yàn)證:我們可以通過方法的反射來操作臭脓,繞過編譯
*/
try {
Method m = c2.getMethod("add", Object.class);
m.invoke(list1, 100);//繞過變異操作就繞過了泛型
System.out.println(list1);
System.out.println(list1.size());
//此時(shí)不能使用使用foreach遍歷,因?yàn)橛衖nt型
} catch (Exception e) {
e.printStackTrace();
}
}
}
MethodDemo4運(yùn)行結(jié)果
OfficeBetter.java
package one;
//new 對(duì)象名 創(chuàng)建出來的都是靜態(tài)加載類腹忽,編譯時(shí)所有可能用到的類必須存在来累,否則不能通過編譯
//動(dòng)態(tài)加載類Class.forName ,使用此方法編譯時(shí)只調(diào)用用到的類
public class OfficeBetter {
public static void main(String[] args) {
System.out.println(args[0]);
try {
Class c = Class.forName(args[0]);
OfficeAble oa = (OfficeAble) c.newInstance();
oa.print();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
interface OfficeAble {
public void print();
}
class Word implements OfficeAble {
public void print() {
System.out.println("I am Word");
}
}
class Excel implements OfficeAble {
public void print() {
System.out.println("I am Excel");
}
}
OfficeBetter運(yùn)行結(jié)果