package com.angel.prac;
public class Earth {
private String name;
private double volume;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getVolume() {
return volume;
}
public void setVolume(double volume) {
this.volume = volume;
}
}
package com.angel.prac;
public class Mars {
private String name;
private float volume;
public Mars(){}
public Mars(String name, float volume) {
this.name = name;
this.volume = volume;
}
public Mars(String name){
this.name = name;
}
public String getName() {
return name;
}
public float getVolume() {
return volume;
}
}
package com.angel.prac;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Reflaction {
public void reflectClass() throws Exception{
//反射一個類:
//默認構造器的反射類:
String s = "com.angel.prac.Earth";
Class <?> c = Class.forName(s);
Earth earth = (Earth)c.newInstance();
earth.setName("Angel");
earth.setVolume(521.1314);
System.out.println("The Earth's name is "+ earth.getName() + "-----" +
"The volume is "+ earth.getVolume());
//非默認構造器的反射類:
String s0 = "com.angel.prac.Mars";
Class <?> c0 = Class.forName(s0);
// java.lang.Class.getConstructor(Class<?>... arg0)
Constructor <?> constructor = c0.getConstructor(String.class,float.class);
Mars mars = (Mars)constructor.newInstance("Mars",1314.521f);
System.out.println("The Mars' name is " + mars.getName() + "----- "+"The volume is "
+ mars.getVolume());
}
首先構造一個字符串,“com.angel.prac”是包名,"Earth"是我自己寫的一個類(Earth類在上面有具體的實現),通過Class類下的forName就可以將這個含有確切是哪個類的字符串返回一個確切的運行時類對象,然後通過newInstance方法就可以產生一個新的對象,這個對象是從c來的,newInstance這個方法的返回值是Object,此刻我們將要強轉爲Earth類型的,從而能夠運用Earth類下的屬性,方法。現在實際上我們已經拿到了這個運行時類對象了,就可以利用這個對象去操縱Earth類下的屬性,方法了。
public void reflectMethod() throws Exception{
//反射一個方法:
//默認構造器的反射方法:
String s = "com.angel.prac.Earth!nAMe!Earth";
String [] string = s.split("!");
Class<?> c = Class.forName(string[0]);
Earth earth = (Earth) c.newInstance();
Method setMethod = c.getMethod("set" + string[1].substring(0, 1).toUpperCase() +
string[1].substring(1, string[1].length()).toLowerCase(),String.class);
Method getMethod = c.getMethod("get" + string[1].substring(0, 1).toUpperCase() +
string[1].substring(1, string[1].length()).toLowerCase());
setMethod.invoke(earth, string[2]);
Object obj = getMethod.invoke(earth);
System.out.println(obj);
//非默認構造器的反射方法:
String s0 = "com.angel.prac.Mars!NaMe!vOLUme!Mars!521.1314f";
String [] str = s0.split("!");
Class<?> c1 = Class.forName(str[0]);
Constructor <?> constructor1 = c1.getConstructor(String.class, float.class);
Mars mars1 = (Mars)constructor1.newInstance(str[3] , Float.parseFloat(str[4]));
Method getMarsName = c1.getMethod("get" + str[1].substring(0, 1).toUpperCase()+
str[1].substring(1,str[1].length()).toLowerCase());
Method getMarsVolume = c1.getMethod("get" + str[2].substring(0, 1).toUpperCase()+
str[2].substring(1,str[2].length()).toLowerCase());
Object obj0 = getMarsName.invoke(mars1);
Object obj1 = getMarsVolume.invoke(mars1);
System.out.println(obj0);
System.out.println(obj1);
}
反射一個方法,splite這個方法是處理字符串的一個方法,意爲分割,在本例中就是說只要遇到一個!號那麼我就分割成一部分,存到一個數組中,最後返回一個字符串數組。用這個運行時類的對象去getMethod,就可以去獲得一個程序員指定名字的方法了,在這裏,我用了一系列處理字符串的API方法,在這裏,就不多多細說了,大家可以參考API中文文檔。在這裏有一個非常重要的方法那就是invoke,意思是調用,就是說將執行earth這個新對象下的程序員想調用的方法,這個方法是返回在Method的對象中的。然後返回一個Object對象。
public void reflectArray(){
//反射一個數組:
Object obj = Array.newInstance(int.class, 5);
for (int i = 0; i < 5; i++) {
Array.set(obj, i, i+1);
}
for (int i = 0; i < 5; i++) {
System.out.println(Array.get(obj, i));
}
}
public void reflectField() throws Exception{
//反射屬性:
//默認構造器反射一個屬性:
String s0 = "com.angel.prac.Earth!volume!5211314";
String [] str = s0.split("!");
Class<?> c0 = Class.forName(str[0]);
Earth earth = (Earth)c0.newInstance();
//java.lang.Class.getDeclaredField(String arg0)這個用於private的屬性
//java.lang.Class.getField(String arg0)這個用於public屬性
Field fie = c0.getDeclaredField(str[1]);
fie.setAccessible(true);
fie.set(earth, 3344);
System.out.println(fie.get(earth));
//非默認構造器反射一個屬性:
String s = "com.angel.prac.Mars!name!volume!火星星!521.1314f";
String [] string = s.split("!");
Class<?> c = Class.forName(string[0]);
Constructor<?> constructor = c.getConstructor(String.class, float.class);
Mars mars = (Mars)constructor.newInstance(string[3],Float.parseFloat(string[4]));
//java.lang.Class.getDeclaredField(String arg0)這個用於private的屬性
//java.lang.Class.getField(String arg0)這個用於public屬性
Field field = c.getDeclaredField(string[1]);
Field f =c.getDeclaredField(string[2]);
field.setAccessible(true);
f.setAccessible(true);
field.set(mars, "爲什麼是火星星?");
f.setFloat(mars, 1234.567f);
System.out.println(field.get(mars));
System.out.println(f.get(mars));
}
反射一個方法,例子中已經註釋了,getDeclaredField和getField的區別,我們可以通過getDeclaredField訪問類中的私有屬性,返回一個Field,要想對數據進行存取,必須將setAccessible設置爲true,這時候,你就告訴JVM了,我要訪問這個屬性,我有對它操作的權利。非默認構造器中的獲取在這就不重複了。
public void reflectIntrospection() throws Exception{
//內省(僅提供屬性示例,也可以操作類和方法):
String s0 = "com.angel.prac.Earth";
Class<?> c0 = Class.forName(s0);
Earth earth = (Earth)c0.newInstance();
BeanInfo bean = Introspector.getBeanInfo(c0, Object.class);
PropertyDescriptor[] descriptor = bean.getPropertyDescriptors();
for(PropertyDescriptor p : descriptor){
if(p.getName().equals("name")){
p.getWriteMethod().invoke(earth, "地球球");
System.out.println(p.getReadMethod().invoke(earth));
}
}
//非默認構造器反射一個屬性:
String s = "com.angel.prac.Mars!name!volume!火星星!123.09f";
String [] string = s.split("!");
Class<?> c = Class.forName(string[0]);
Constructor<?> constructor = c.getConstructor(String.class, float.class);
Mars mars = (Mars)constructor.newInstance(string[3],Float.parseFloat(string[4]));
BeanInfo beanInfo = Introspector.getBeanInfo(c, Object.class);
PropertyDescriptor [] pd = beanInfo.getPropertyDescriptors();
//直接操作屬性:
pd[0].setValue("name", "反射學完了,感到so easy!");
pd[1].setValue("volume",234);
System.out.println(pd[0].getValue("name"));
System.out.println(pd[1].getValue("volume"));
//通過方法獲得屬性:
for (PropertyDescriptor propertyDescriptor : pd) {
if(propertyDescriptor.getName().equals("volume")){
System.out.println(propertyDescriptor.getReadMethod().invoke(mars));
}
}
}
內省,這是個什麼東東呢?不妨我們去問一下google大神,看看google是如何說的:
public static void main(String[] args) throws Exception {
Reflaction reflection = new Reflaction();
reflection.reflectClass();
reflection.reflectMethod();
reflection.reflectArray();
reflection.reflectField();
reflection.reflectIntrospection();
}
}
好了,到這裏呢,反射和內省講的就差不多了,不明白?不要緊,什麼也不要說,先照着我的代碼打三遍,打完了再看一遍這篇文章,我相信你會有很大的收穫。可能有很多的人問:我費這麼大的勁,就爲了傳個參數何必要這麼複雜呢?在以後的學習和工作中, Java 的反射以及內省應用到程序設計中去可以大大的提供程序的智能化和可擴展性,以後的web開發中我們只要操縱XML的配置文件就可以了,而不必再去修改源代碼,這是不是很爽呢?當然也大大地提高了代碼的可維護性。