http://blog.csdn.net/dream_broken/article/details/8830489java
反射中,最基礎的是對Class類的瞭解和使用。在JAVA中Object是一切類的父類,而getClass()方法是Object中定義的,以下spring
- public final native Class<?> getClass();
那麼能夠這麼說,全部類的對象實際上都是Class類的實例。若是你對類加載及JVM方法區有所瞭解,這個應該很容易理解。數組
本文主要是寫點代碼認識Class類的一些經常使用方法。app
1.獲取Class對象框架 在Class類中,只定義了個私有的構造方法,這意味着,沒法經過new Class()方式建立一個Class對象。eclipse
雖然沒法直接使用new Class()方式建立對象,可是Class類中提供了forName()方法,經過它仍然能夠得到Class對象。ide
- public static Class<?> forName(String className)
- throws ClassNotFoundException {
- return forName0(className, true, ClassLoader.getCallerClassLoader());
- }
-
-
-
-
- public static Class<?> forName(String name, boolean initialize,
- ClassLoader loader)
- throws ClassNotFoundException
除了使用forName()方法得到Class對象外,上面說過了Object是全部類的父類,而Object中有getClass()方法,因此經過"類名.getClass()"也能夠得到Class對象,也能夠經過「類名.class"工具
- package test;
-
- public class A1 {
-
- }
-
-
-
-
-
- <span style="font-size:18px;">public class A2 {
-
- public static void main(String[] args){
- Class<?> c1=null;
- Class<?> c2=null;
- Class<?> c3=null;
- try {
- c1=Class.forName("test.A1");
- c2=A1.class;
- A1 a1=new A1();
- c3=a1.getClass();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- System.out.println("類路徑:"+c1.getName());
- System.out.println("類路徑:"+c2.getName());
- System.out.println("類路徑:"+c3.getName());
- }
- }</span>
運行結果測試 類路徑:test.A1 類路徑:test.A1 類路徑:test.A1ui 經過運行結果可知,3種實例化Class對象的方式是同樣的,可是使用forName()是較爲經常使用的一種(固然,若是使用Hibernate或spring等框架時,常常使用"類.class「方式傳送一個JavaBean實體)。 下面先看過設計上比較醜陋的例子。
- <span style="font-size:18px;">package test;
-
-
-
-
-
- public interface Fruit {
- public void say();
- }
-
-
-
- package test;
-
-
-
-
- public class Apple implements Fruit {
- @Override
- public void say() {
- System.out.println("hello,I'm apple!");
- }
- }
-
-
-
-
-
-
-
- public class Banana implements Fruit {
-
- @Override
- public void say() {
- System.out.println("hello,I'm banana!");
- }
- }
-
-
-
-
- package test;
-
-
-
-
- public class FruitUtil {
-
- public static Fruit createFruit(String fruitName){
- if("apple".equalsIgnoreCase(fruitName)) return (Fruit)new Apple();
- if("banana".equalsIgnoreCase(fruitName)) return (Fruit)new Banana();
- return null;
- }
- }
-
-
-
- package test;
-
-
-
-
- public class Test {
-
- public static void main(String[] args){
- Fruit f=FruitUtil.createFruit("apple");
- if(f!=null) {
- f.say();
- }else{
- System.out.println("沒有水果!");
- }
- }
- </span>}
運行結果 hello,I'm apple! 代碼沒錯,運行結果也沒錯,我之因此說它醜陋,是從代碼擴展性方面考慮。好比,若是我要再添加一種水果呢?那麼就必須修改FruitUtil.createFruit()方法中的代碼了,增長if判斷。那若是我要新曾幾十種水果呢?那是否是要寫幾十個if判斷。。。。。做爲一個接觸JAVA兩年的菜鳥的我,都以爲代碼設計不友好了,更別說修改原有代碼對系統的危害了。那有沒有一種方法,當新增水果時,不須要對原有代碼作任何修改呢?有,這時,Class.forName()一聲大哄,粉墨登場了。
- <span style="font-size:18px;">package test;
-
-
-
-
-
- public interface Fruit {
- public void say();
- }
-
-
- package test;
-
-
-
-
- public class Apple implements Fruit {
- @Override
- public void say() {
- System.out.println("hello,I'm apple!");
- }
- }
-
-
-
- package test;
-
-
-
-
- public class Banana implements Fruit {
-
- @Override
- public void say() {
- System.out.println("hello,I'm banana!");
- }
- }
-
-
- package test;
-
-
-
-
- public class FruitUtil {
-
- public static Fruit createFruit(String classPath)throws Exception{
- Fruit fruit=null;
- try {
- fruit=(Fruit)Class.forName(classPath).newInstance();
- } catch (Exception e) {
- e.printStackTrace();
- throw new Exception("建立水果失敗!");
- }
- return fruit;
- }
- }
-
-
- package test;
-
- import java.io.File;
- import java.io.FileInputStream;
- import java.util.Properties;
-
-
-
-
-
- public class Test {
-
- private final static String FRUIT_CONF_PATH=System.getProperty("user.dir");
- public static void main(String[] args){
- Properties p=new Properties();
- try {
-
- FileInputStream in=new FileInputStream(new File(FRUIT_CONF_PATH+File.separator+"bin"+File.separator+"fruit.properties"));
- p.load(in);
- String fruitClassPath=p.getProperty("apple");
- p.clear();
- in.close();
- Fruit f=FruitUtil.createFruit(fruitClassPath);
- f.say();
- } catch (Exception e) {
- e.printStackTrace();
- System.out.println("獲取水果實例失敗!");
- }
- }
- }</span>
fruit.properties配置文件
- apple=test.Apple
- banana=test.Banana
運行結果 hello,I'm apple! 這樣改寫後,之後有新增水果時,只要編寫新增水果類,並再配置文件中配置新水果的類路徑就OK了,原有的代碼不須要修改。 這樣的設計就具備很好的擴展性。 |
2.獲取類中的成員變量 getFields():得到類(包括父類)的public成員變量 getDeclaredFields():得到類(不包括父類)的所有成員變量
- package test;
-
- public class A {
-
- public int n_A;
- private String s_A;
- protected double d_A;
- }
-
- package test;
-
- public class A1 extends A {
- public int n_A1;
- private String s_A1;
- protected double d_A1;
-
- }
-
- package test;
-
- import java.lang.reflect.Field;
-
- public class A2 {
- public static void main(String[] args){
- Class<?> c1=null;
- try {
- c1=Class.forName("test.A1");
- Field[] f1=c1.getFields();
- for(Field f:f1)
- System.out.println("A1(包括父類)類中public 成員變量:"+f.getName());
- System.out.println("獲取A1(不包括父類)類中的全部成員變量::::::::");
- Field[] f2=c1.getDeclaredFields();
- for(Field f:f2)
- System.out.println("A1(不包括父類)類中的成員變量:"+f.getName());
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- }
-
- }
運行結果 A1(包括父類)類中public 成員變量:n_A1 A1(包括父類)類中public 成員變量:n_A 獲取A1(不包括父類)類中的全部成員變量:::::::: A1(不包括父類)類中的成員變量:n_A1 A1(不包括父類)類中的成員變量:s_A1 A1(不包括父類)類中的成員變量:d_A1 |
3.獲取類中的方法 getMethods():獲取類(包括父類)中的public方法(不包括構造方法) getDeclaredMethods():獲取本類(不包括父類)中的全部方法(不包括構造方法) getConstructors():獲取本類(不包括父類)中的全部public構造方法 考慮到篇幅問題,就不貼代碼了。 |
4.實例化對象
- <span style="font-size:18px;">package test;
-
- public class A1 {
- private int n;
-
- public A1(){
- this.n=0;
- }
- public A1(int n){
- this.n=n;
- }
-
- public int getN() {
- return n;
- }
- public void setN(int n) {
- this.n = n;
- };
- }
-
-
- package test;
-
- import java.lang.reflect.Constructor;
-
- public class A2 {
- public static void main(String[] args){
- Class<?> c1=null;
- try {
- c1=Class.forName("test.A1");
- A1 a1=(A1)c1.newInstance();
- System.out.println("使用Class類中的newInstance()方法實例化,a1.n="+a1.getN());
- Constructor<?>[] con=c1.getConstructors();
- A1 a2=(A1)con[0].newInstance();
- System.out.println("使用Constructor類中的public T newInstance(Object ... initargs)方法實例化,a2.n="+a2.getN());
- A1 a3=(A1)con[1].newInstance(10);
- System.out.println("使用Constructor類中的public T newInstance(Object ... initargs)方法實例化,a3.n="+a3.getN());
-
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- }
-
- }</span>
運行結果 使用Class類中的newInstance()方法實例化,a1.n=0 使用Constructor類中的public T newInstance(Object ... initargs)方法實例化,a2.n=0 使用Constructor類中的public T newInstance(Object ... initargs)方法實例化,a3.n=10 |
5.經過反射調用類中的方法
- <span style="font-size:18px;color:#000000;">package test;
-
- public class A {
-
- public void sayHello(){
- System.out.println("hello,world");
- }
- public void sayHello(String name){
- System.out.println("hello,"+name);
- }
- }
-
- package test;
-
- import java.lang.reflect.Method;
-
- public class Test01 {
-
- public static void main(String[] args){
- Class<?> c=null;
- try {
- c=Class.forName("test.A");
- A a=(A)c.newInstance();
- Method m1=c.getMethod("sayHello");
- m1.invoke(a);
- Method m2=c.getMethod("sayHello", String.class);
- m2.invoke(a, "everyOne");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }</span>
運行結果 hello,world hello,everyOne |
6.經過反射破壞類的封裝性(給私有變量賦值並訪問)
- <span style="font-size:18px;">package test;
-
- public class User {
-
- private String name;
- private int age;
- public String getName() {
- return name;
- }
- public int getAge() {
- return age;
- }
-
- }
-
-
- package test;
-
- import java.lang.reflect.Field;
-
-
-
-
- public class Test01 {
-
- public static void main(String[] args){
- Class<?> c=null;
- try {
- c=Class.forName("test.User");
- User user=(User)c.newInstance();
- Field name=c.getDeclaredField("name");
- Field age=c.getDeclaredField("age");
- name.setAccessible(true);
- age.setAccessible(true);
- name.set(user, "張三");
- age.set(user, 20);
- System.out.println("姓名:"+name.get(user)+" "+user.getName());
- System.out.println("年齡:"+age.get(user)+" "+user.getAge());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }</span>
運行結果 姓名:張三 張三 年齡:20 20 |