java反射详解

本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解。

下面开始正文。

【案例1】通过一个对象获得完整的包名和类名

 

 


  
  1. package Reflect; 

  2.   

  3. /** 

  4.  * 通过一个对象获得完整的包名和类名 

  5.  * */ 

  6. class Demo{ 

  7.     //other codes... 

  8.   

  9. public class hello{ 

  10.     public static void main(String[] args) { 

  11.         Demo demo=new Demo();//这里还是用原来的 方法生成的Demo对象, 

  12.         //我们只是想通过这个对象得到完整的包.类名 

  13.         //下面你将看到,我们不再用这种方式生成对象,和以前不太一样了, 

  14.         //刚接触反射有点绕,因为以前的习惯了,刚学习有点反应不过来 

  15.         System.out.println(demo.getClass().getName()); 

  16.     } 

【运行结果】:Reflect.Demo

注意:java中是不是每个类都有一个Class类的实例?

 

如果java中每个类都有一个Class类的实例,那么是不是只要定义了一个类都会因为有一个Class类的实例而占内存空间呢?

可以这么说。 在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。
在运行期间,如果我们要产生某个类的对象,Java虚拟机会检查该类型的Class对象是否已被加载。如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已被加载到内存,就可以用它来产生该类型的所有对象
这个问题不太确定,请高手解答。。 【案例2】实例化 Class 类对象

  
  1. package Reflect; 
  2.  
  3. class Demo { 
  4.     // other codes... 
  5.  
  6. public class hello { 
  7.     public static void main(String[] args) { 
  8.         //实例化Class类对象,实例化Class类对象是反射机制的根源,
  9. //所以涉及到反射的必须先对Class类对象进行实例化 
  10.         Class<?> demo1 = null
  11.         Class<?> demo2 = null
  12.         Class<?> demo3 = null
  13.         try { 
  14.             // 一般尽量采用这种形式 
  15.             demo1 = Class.forName("Reflect.Demo"); 
  16.         } catch (Exception e) { 
  17.             e.printStackTrace(); 
  18.         } 
  19.         demo2 = new Demo().getClass(); 
  20.         demo3 = Demo.class
  21.  
  22.         System.out.println("类名称   " + demo1.getName()); 
  23.         System.out.println("类名称   " + demo2.getName()); 
  24.         System.out.println("类名称   " + demo3.getName()); 
  25.  
  26.     } 

 

 

【运行结果】:

类名称   Reflect.Demo

类名称   Reflect.Demo

类名称   Reflect.Demo

【案例3】通过Class实例化其他类的对象,分为两种 无参,有参,都是调用 newInstance() 方法 

 


  
  1. package Reflect; 
  2.  
  3. import java.lang.reflect.Constructor; 
  4. import java.lang.reflect.Method; 
  5.  
  6. class Person { 
  7.     private String name; 
  8.     private int age; 
  9.  
  10.     public Person() { 
  11.         System.out.println("无参构造函数"); 
  12.     } 
  13.  
  14.     public Person(String name, int age) { 
  15.         System.out.println("有参构造函数"); 
  16.         this.name = name; 
  17.         this.age = age; 
  18.  
  19.     } 
  20.  
  21.     public String getName() { 
  22.         return name; 
  23.     } 
  24.  
  25.     public void setName(String name) { 
  26.         this.name = name; 
  27.     } 
  28.  
  29.     public int getAge() { 
  30.         return age; 
  31.     } 
  32.  
  33.     public void setAge(int age) { 
  34.         this.age = age; 
  35.     } 
  36.  
  37.     @Override 
  38.     public String toString() { 
  39.         return "[" + this.name + "  " + this.age + "]"
  40.     } 
  41.  
  42. public class hello { 
  43.     public static void main(String[] args) throws Exception { 
  44.         Class<?> demo = null
  45.         // 实例化Class类对象,反射的根源 
  46.         demo = Class.forName("Reflect.Person"); 
  47.         Person per = null
  48.         // 调用无参构造函数,创建Person对象实例 
  49.         per = (Person) demo.newInstance(); 
  50.         per.setName("Rollen"); 
  51.         per.setAge(20); 
  52.         System.out.println(per); 
  53.         // 使用有参的构造函数初始化,必须要得到相应的构造函数 
  54.         Constructor<Person> constructor = (Constructor<Person>) demo 
  55.                 .getConstructor(String.classint.class); 
  56.         per = constructor.newInstance("张三"100); 
  57.         System.out.println(per); 
  58.     } 

【运行结果】:

 

无参构造函数

[Rollen  20]

有参构造函数

[张三  100]

【案例】通过 Class 调用其他类中的构造函数   (也可以通过这种方式通过 Class 创建其他类的对象)多个构造函数,一定要注意顺序,Debug时可以清楚的看到顺序
 

  
  1. package Reflect; 
  2.   
  3. import java.lang.reflect.Constructor; 
  4.   
  5. class Person{ 
  6.       
  7.     public Person() { 
  8.           
  9.     } 
  10.     public Person(String name){ 
  11.         this.name=name; 
  12.     } 
  13.     public Person(int age){ 
  14.         this.age=age; 
  15.     } 
  16.     public Person(String name, int age) { 
  17.         this.age=age; 
  18.         this.name=name; 
  19.     } 
  20.     public String getName() { 
  21.         return name; 
  22.     } 
  23.     public int getAge() { 
  24.         return age; 
  25.     } 
  26.     @Override 
  27.     public String toString(){ 
  28.         return "["+this.name+"  "+this.age+"]"
  29.     } 
  30.     private String name; 
  31.     private int age; 
  32.   
  33. public class hello{ 
  34.     public static void main(String[] args) { 
  35.         Class<?> demo=null
  36.         try
  37.             demo=Class.forName("Reflect.Person"); 
  38.         }catch (Exception e) { 
  39.             e.printStackTrace(); 
  40.         } 
  41.         Person per1=null
  42.         Person per2=null
  43.         Person per3=null
  44.         Person per4=null
  45.         //取得全部的构造函数 
  46.         Constructor<?> cons[]=demo.getConstructors(); 
  47.         try
  48.             per1=(Person)cons[0].newInstance(); 
  49.             per2=(Person)cons[1].newInstance("Rollen"); 
  50.             per3=(Person)cons[2].newInstance(20); 
  51.             per4=(Person)cons[3].newInstance("Rollen",20); 
  52.         }catch(Exception e){ 
  53.             e.printStackTrace(); 
  54.         } 
  55.         System.out.println(per1); 
  56.         System.out.println(per2); 
  57.         System.out.println(per3); 
  58.         System.out.println(per4); 
  59.     } 
注意一点:上面运行出错,因为构造函数不匹配,通过Debug查看:
cons[0] 对应 public Reflect.Person(java.lang.String)
cons[1] 对应 public Reflect.Person(int)
cons[2] 对应 public Reflect.Person(java.lang.String,int)
cons[3] 对应 public Reflect.Person()
调整顺序才可以正常执行。。

【案例】 返回一个类实现的接口:

 

 


  
  1. package Reflect; 
  2.   
  3. interface China{ 
  4.     public static final String name="Rollen"
  5.     public static  int age=20
  6.     public void sayChina(); 
  7.     public void sayHello(String name, int age); 
  8.   
  9. class Person implements China{ 
  10.     public Person() { 
  11.           
  12.     } 
  13.     public Person(String sex){ 
  14.         this.sex=sex; 
  15.     } 
  16.     public String getSex() { 
  17.         return sex; 
  18.     } 
  19.     public void setSex(String sex) { 
  20.         this.sex = sex; 
  21.     } 
  22.     public void sayChina(){ 
  23.         System.out.println("hello ,china"); 
  24.     } 
  25.     public void sayHello(String name, int age){ 
  26.         System.out.println(name+"  "+age); 
  27.     } 
  28.     private String sex; 
  29.   
  30. public class hello{ 
  31.     public static void main(String[] args) { 
  32.         Class<?> demo=null
  33.         try
  34.             demo=Class.forName("Reflect.Person"); 
  35.         }catch (Exception e) { 
  36.             e.printStackTrace(); 
  37.         } 
  38.         //保存所有的接口 
  39.         Class<?> intes[]=demo.getInterfaces(); 
  40.         for (int i = 0; i < intes.length; i++) { 
  41.             System.out.println("实现的接口   "+intes[i].getName()); 
  42.         } 
  43.     } 

 

【运行结果】:

实现的接口   Reflect.China

(注意,以下几个例子,都会用到这个例子的Person类,所以为节省篇幅,此处不再粘贴Person的代码部分,只粘贴主类hello的代码)

【案例】:取得其他类中的父类

 

 


  
  1. public class hello{ 
  2.     public static void main(String[] args) { 
  3.         Class<?> demo=null
  4.         try
  5.             demo=Class.forName("Reflect.Person"); 
  6.         }catch (Exception e) { 
  7.             e.printStackTrace(); 
  8.         } 
  9.         //取得父类 
  10.         Class<?> temp=demo.getSuperclass(); 
  11.         System.out.println("继承的父类为:   "+temp.getName()); 
  12.     } 

【输出结果】:继承的父类为:   java.lang.Object

【案例】:获得其他类中的全部构造函数


  
  1. public class hello{ 
  2.     public static void main(String[] args) { 
  3.         Class<?> demo=null
  4.         try
  5.             demo=Class.forName("Reflect.Person"); 
  6.         }catch (Exception e) { 
  7.             e.printStackTrace(); 
  8.         } 
  9.         Constructor<?>cons[]=demo.getConstructors(); 
  10.         for (int i = 0; i < cons.length; i++) { 
  11.             System.out.println("构造方法:  "+cons[i]); 
  12.         } 
  13.     } 

【输出结果】:

 

构造方法:  public Reflect.Person(java.lang.String)

构造方法:  public Reflect.Person()

【通过拼凑的方法输出构造方法】


  
  1. public class hello { 
  2.     public static void main(String[] args) { 
  3.         Class<?> demo = null
  4.         try { 
  5.             demo = Class.forName("Reflect.Person"); 
  6.         } catch (Exception e) { 
  7.             e.printStackTrace(); 
  8.         } 
  9.         Constructor<?> cons[] = demo.getConstructors(); 
  10.         for (int i = 0; i < cons.length; i++) { 
  11.             //构造方法参数类型 
  12.             Class<?> p[] = cons[i].getParameterTypes(); 
  13.             System.out.print("构造方法:  "); 
  14.             //修饰符 
  15.             int mo = cons[i].getModifiers(); 
  16.             System.out.print(Modifier.toString(mo) + " "); 
  17.             //构造方法名 
  18.             System.out.print(cons[i].getName()); 
  19.             System.out.print("("); 
  20.             for (int j = 0; j < p.length; ++j) { 
  21.                 //构造方法 参数类型名 
  22.                 System.out.print(p[j].getName() + " arg" + i); 
  23.                 if (j < p.length - 1) { 
  24.                     System.out.print(","); 
  25.                 } 
  26.             } 
  27.             System.out.println("){}"); 
  28.         } 
  29.     } 

 

 

【运行结果】:

构造方法:  public Reflect.Person(){}

构造方法:  public Reflect.Person(java.lang.String arg1){}

有时候一个方法可能还有异常,呵呵。下面看看:

 


  
  1. class hello { 
  2.     public static void main(String[] args) { 
  3.         Class<?> demo = null
  4.         try { 
  5.             demo = Class.forName("Reflect.Person"); 
  6.         } catch (Exception e) { 
  7.             e.printStackTrace(); 
  8.         } 
  9.         Method method[] = demo.getMethods(); 
  10.         for (int i = 0; i < method.length; ++i) { 
  11.             //返回类型 
  12.             Class<?> returnType = method[i].getReturnType(); 
  13.             //参数类型 
  14.             Class<?> para[] = method[i].getParameterTypes(); 
  15.             //修饰符 
  16.             int temp = method[i].getModifiers(); 
  17.             System.out.print(Modifier.toString(temp) + " "); 
  18.             System.out.print(returnType.getName() + "  "); 
  19.             System.out.print(method[i].getName() + " "); 
  20.             System.out.print("("); 
  21.             for (int j = 0; j < para.length; ++j) { 
  22.                 //参数类型 名 
  23.                 System.out.print(para[j].getName() + " " + "arg" + j); 
  24.                 if (j < para.length - 1) { 
  25.                     System.out.print(","); 
  26.                 } 
  27.             } 
  28.             Class<?> exce[] = method[i].getExceptionTypes(); 
  29.             if (exce.length > 0) { 
  30.                 System.out.print(") throws "); 
  31.                 for (int k = 0; k < exce.length; ++k) { 
  32.                     //异常的名字 
  33.                     System.out.print(exce[k].getName() + " "); 
  34.                     if (k < exce.length - 1) { 
  35.                         System.out.print(","); 
  36.                     } 
  37.                 } 
  38.             } else { 
  39.                 System.out.print(")"); 
  40.             } 
  41.             System.out.println(); 
  42.         } 
  43.     } 

【运行结果】

 


  
  1. public java.lang.String  getSex () 
  2. public void  setSex (java.lang.String arg0) 
  3. public void  sayChina () 
  4. public void  sayHello (java.lang.String arg0,int arg1) 
  5. public native int  hashCode () 
  6. public final native java.lang.Class  getClass () 
  7. public final void  wait () throws java.lang.InterruptedException  
  8. public final void  wait (long arg0,int arg1) throws java.lang.InterruptedException  
  9. public final native void  wait (long arg0) throws java.lang.InterruptedException  
  10. public boolean  equals (java.lang.Object arg0) 
  11. public final native void  notify () 
  12. public final native void  notifyAll () 
  13. public java.lang.String  toString () 

【案例】接下来让我们取得其他类的全部属性吧,最后我讲这些整理在一起,也就是通过class取得一个类的全部框架


  
  1. public class hello { 
  2.     public static void main(String[] args) { 
  3.         Class<?> demo = null
  4.         try { 
  5.             demo = Class.forName("Reflect.Person"); 
  6.         } catch (Exception e) { 
  7.             e.printStackTrace(); 
  8.         } 
  9.         System.out.println("============本类属性=============="); 
  10.         // 取得本类的全部属性 
  11.         Field[] field = demo.getDeclaredFields(); 
  12.         for (int i = 0; i < field.length; i++) { 
  13.             // 权限修饰符 
  14.             int mo = field[i].getModifiers(); 
  15.             String priv = Modifier.toString(mo); 
  16.             // 属性类型 
  17.             Class<?> type = field[i].getType(); 
  18.             System.out.println(priv + " " + type.getName() + " " 
  19.                     + field[i].getName() + ";"); 
  20.         } 
  21.         System.out.println("=======实现的接口或者父类的属性===="); 
  22.         // 取得实现的接口或者父类的属性 
  23.         Field[] filed1 = demo.getFields(); 
  24.         for (int j = 0; j < filed1.length; j++) { 
  25.             // 权限修饰符 
  26.             int mo = filed1[j].getModifiers(); 
  27.             String priv = Modifier.toString(mo); 
  28.             // 属性类型 
  29.             Class<?> type = filed1[j].getType(); 
  30.             System.out.println(priv + " " + type.getName() + " " 
  31.                     + filed1[j].getName() + ";"); 
  32.         } 
  33.     } 

结果:


  
  1. ===============本类属性======================== 
  2. private java.lang.String sex; 
  3. ===============实现的接口或者父类的属性======================== 
  4. public static final java.lang.String name; 
  5. public static final int age; 

【案例】其实还可以通过反射调用其他类中的方法:


  
  1. public class hello { 
  2.     public static void main(String[] args) { 
  3.         Class<?> demo = null
  4.         try { 
  5.             demo = Class.forName("Reflect.Person"); 
  6.         } catch (Exception e) { 
  7.             e.printStackTrace(); 
  8.         } 
  9.         try
  10.             //调用Person类中的sayChina方法 
  11.             Method method=demo.getMethod("sayChina"); 
  12.             //通过反射调用方法,完全和以前颠倒过来了, 
  13.             //这里是方法实例 调用invoke方法,方法参数为类的实例对象 
  14.             method.invoke(demo.newInstance()); 
  15.             //调用Person的sayHello方法 
  16.             method=demo.getMethod("sayHello", String.class,int.class); 
  17.             method.invoke(demo.newInstance(),"Rollen",20); 
  18.               
  19.         }catch (Exception e) { 
  20.             e.printStackTrace(); 
  21.         } 
  22.     } 

结果:


  
  1. hello ,china 
  2. Rollen  20 

【案例】调用其他类的setget方法


  
  1. public class hello { 
  2.     public static void main(String[] args) throws Exception { 
  3.         Class<?> demo = null
  4.         Object obj = null
  5.         demo = Class.forName("Reflect.Person"); 
  6.         obj = demo.newInstance(); 
  7.         setter(obj, "Sex""男", String.class); 
  8.         getter(obj, "Sex"); 
  9.     } 
  10.     /** 
  11.      * @param obj   操作的对象 
  12.      * @param att   操作的属性 
  13.      */ 
  14.     public static void getter(Object obj, String att) { 
  15.         try { 
  16.             Method method = obj.getClass().getMethod("get" + att); 
  17.             //原来是 对象调用方法;现在是方法对象调用,参数是 类的实例 
  18.             System.out.println(method.invoke(obj)); 
  19.         } catch (Exception e) { 
  20.             e.printStackTrace(); 
  21.         } 
  22.     } 
  23.     /** 
  24.      * @param obj  操作的对象 
  25.      * @param att  操作的属性 
  26.      * @param value 设置的值 
  27.      * @param type 参数的属性 
  28.      */ 
  29.     public static void setter(Object obj, String att, Object value, 
  30.             Class<?> type) { 
  31.         try { 
  32.             Method method = obj.getClass().getMethod("set" + att, type); 
  33.             method.invoke(obj, value); 
  34.         } catch (Exception e) { 
  35.             e.printStackTrace(); 
  36.         } 
  37.     } 
  38. }// end class 

【运行结果】: