Java反射机制详解

“一.Java 反射机制浅析

      Java反射机制是在运行状态中,对于任意一个,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。当然反射本身并不是一个新概念,它可能会使我们联想到光学中的反射概念,尽管计算机科学赋予了反射概念新的含义,但是,从现象上来说,它们确实有某些相通之处,这些有助于我们的理解。

      Java反射机制主要提供下面几种用途:

    - 在运行时判断任意一个对象所属的类
    - 在运行时构造任意一个类的对象
    - 在运行时判断任意一个类所具有的成员变量和方法
    - 在运行时调用任意一个对象的方法

二.在这里先看一下sun为我们提供了那些反射机制中的类:

java.lang.Class;一个比较特殊的类,它用于封装被装入到JVM中的类(包括类和接口)的信息。             

java.lang.reflect.Constructor;

java.lang.reflect.Field;        

java.lang.reflect.Method;

java.lang.reflect.Modifier;

很多反射中的方法,属性等操作我们可以从这四个类中查询。还是那句话要学着不断的查询API,那才是我们最好的老师。

链接:
1.Java反射机制-Class类的用法详解

java的Class类是java反射机制的基础,通过Class类我们可以获得一个类的相关信息。

下面我们来了解一下有关java中Class类的相关知识!

java.lang.Class是一个比较特殊的类,它用于封装被装入到JVM中的类(包括类和接口)的信息。

当一个类或接口被装入的JVM时便会产生一个与之关联的java.lang.Class对象,可以通过这个Class对象对被装入类的详细信息进行访问。

简单的说,获取某一个类所对应的Class对象可以通过如下三种途径:

1. Object的getClass方法(用于返回与调用该方法对象所属类关联的Class对象)
java.lang.Object中定义有getClass方法:
public final Class getClass()

所有Java对象都具备这个方法。该方法用于返回与调用该方法对象所属类相关联的Class对象,例如:

Date date1 = new Date();

Date date2 = new Date();

Class c1 = date1.getClass();

Class c2 = date2.getClass();

System.out.println(c1.getName()); // java.util.Date

System.out.println(c1 == c2); // true

上面的代码中,调用Date对象date1的getClass方法将返回用于封装Date类信息的Class对象Date。接着调用了Class类的getName方法:

public String getName()

这个方法的含义很直观,即返回所封装的类的名称。

需要注意的是,代码中的date1和date2的getClass方法返回了相同的Class对象(c1==c2的值为true)。这是因为,对于相同的类,JVM只会载入一次,而与该类对应的Class对象也只会存在一个,无论该类实例化了多少对象。

另外,需要强调的是,当一个对象被其父类的引用或其实现的接口类型的引用所指向时,getClass方法返回的是与对象实际所属类关联的Class对象。例如:

List list = new ArrayList();

System.out.println(list.getClass().getName()); // java.util.ArrayList

上面的代码中,语句list.getClass()方法返回的是list所指向对象实际所属类java.util.ArrayList对应的 Class对象而并未java.util.List所对应的Class对象。有些时候可以通过这个方法了解一个对象的运行时类型,例如:

HashSet set = new HashSet();

Iterator it = set.iterator();

System.out.println(it.getClass().getName()); //java.util.HashMap$KeyIterator

从代码可以看出,HashSet的iterator方法返回的是实现了Iterator接口的HashMap内部类(KeyIterator)对象。

因为抽象类和接口不可能实例化对象,因此不能通过Object的getClass方法获得与抽象类和接口关联的Class对象。

2. 使用.class的方式
使用类名加“.class”的方式即会返回与该类对应的Class对象。例如:

Class clazz = String.class;

System.out.println(clazz.getName()); // java.lang.String

这个方法可以直接获得与指定类关联的Class对象,而并不需要有该类的对象存在。

3. 使用Class.forName方法
Class有一个著名的static方法forName:

public static Class forName(String className) throws ClassNotFoundException

该方法可以根据字符串参数所指定的类名获取与该类关联的Class对象。如果该类还没有被装入,该方法会将该类装入JVM。

该方法声明抛出ClassNotFoundException异常。顾名思义,当该方法无法获取需要装入的类时(例如,在当前类路径中不存在这个类),就会抛出这个异常。

例如,如果当前类路径中存在Foo类:

package org.whatisjava.reflect;

public class Foo {

public Foo() {

System.out.println("Foo()");

}

static {

System.out.println("Foo is initialized");

}

}

运行下面的代码:

Class clazz = Class.forName("org.whatisjava.reflect.Foo");

控制台会有如下输出:

Foo is initialized

Class.forName("org.whatisjava.reflect.Foo")首先会将reflection.Foo类装入JVM,并返回与之关联的Class对象。JVM装入Foo类后对其进行初始化,调用了其static块中的代码。所以控制台输出的是:Foo is initialized

,而只有当实例化Foo类对象时,才会执行其构造函数,输出:Foo()。

需要注意的是:forName方法的参数是类的完整限定名(即包含包名)。


区别于前面两种获取Class对象的方法。使用Class.forName方法所要获取的与之对应的Class对象的类可以通过字符串的方式给定。该方法通常用于在程序运行时根据类名动态的载入该类并获得与之对应的Class对象。
 

通过上面的文章相信你对java的反射机制有了一定的认识,同时也对java中Class类的用法有了比较清晰的理解,在我们实际工作的过程中,我们不断的运用java知识来解决实际生湖中的问题的时候我们就能对java反射机制有一个更深入的理解!

2.java访问修饰符—Modifier(英文:修饰语,修饰器)

    在Class 、Field 、Constructor 等类中,可以看到有这样一个方法:getModifiers() ,它将以整数形式返回此 Constructor 对象所表示构造方法的 Java 语言修饰符.它的作用是返回一个类或者其成员的访问修饰符的int 类型常量,如需要知道返回的值所代表的意思,则需要了解java.lang.reflect.Modifier这个类, Modifier 类提供了 static 方法和常量,对类和成员访问修饰符进行解码。

如:

Java代码   收藏代码
  1. import java.lang.reflect.Modifier;  
  2.   
  3. import java.lang.reflect.Field;  
  4.   
  5. public class A{  
  6.     private String str1;  
  7.     private static final String str2 = "str";  
  8.     public static void main(String[] args){  
  9.        Field[] fields = A.class.getDeclaredFields();  
  10.       for(Field f:fields){  
  11.          System.out.println("字段"+f.getName()+"访问修饰符是否包括 private:"+Modifier.isPrivate(f.getModifiers()));  
  12.          System.out.println("字段"+f.getName()+"访问修饰符是否包括 static:"+Modifier.isStatic(f.getModifiers()));  
  13.          System.out.println("字段"+f.getName()+"访问修饰符是否包括 public:"+Modifier.isPublic(f.getModifiers()));  
  14.       }  
  15.     }  
  16.   
  17. }  
  三.具体功能实现:
1.反射机制获取类有三种方法,我们来获取Employee类型

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //第一种方式:  
  2. Class c1 = Class.forName("Employee");  
  3. //第二种方式:  
  4. //java中每个类型都有class 属性.  
  5. Class c2 = Employee.class;  
  6.    
  7. //第三种方式:  
  8. //java语言中任何一个java对象都有getClass 方法  
  9. Employee e = new Employee();  
  10. Class c3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)     
2.创建对象:获取类以后我们来创建它的对象,利用newInstance

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. Class c =Class.forName("Employee");  
  2.   
  3. //创建此Class 对象所表示的类的一个新实例  
  4. Object o = c.newInstance(); //调用了Employee的无参数构造方法.  

 3.获取属性:分为所有的属性和指定的属性:

      a.先看获取所有的属性的写法:

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1.             //获取整个类  
  2.             Class c = Class.forName("java.lang.Integer");  
  3.             //获取所有的属性  
  4.             Field[] fs = c.getDeclaredFields();         
  5.             //定义可变长的字符串,用来存储属性  
  6.             StringBuffer sb = new StringBuffer();  
  7.             //通过追加的方法,将每个属性拼接到此字符串中  
  8.             //最外边的public定义  
  9.             sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");  
  10.             //里边的每一个属性  
  11.             for(Field field:fs){  
  12.                 sb.append("\t");//空格  
  13.                 sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等  
  14.                 sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字  
  15.                 sb.append(field.getName()+";\n");//属性的名字+回车  
  16.             }  
  17.       
  18.             sb.append("}");  
  19.       
  20.             System.out.println(sb);  
      
   b.获取特定的属性,对比着传统的方法来学习:
[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. public static void main(String[] args) throws Exception{  
  2.               
  3. <span style="white-space:pre">  </span>//以前的方式:  
  4.     /* 
  5.     User u = new User(); 
  6.     u.age = 12; //set 
  7.     System.out.println(u.age); //get 
  8.     */  
  9.               
  10.     //获取类  
  11.     Class c = Class.forName("User");  
  12.     //获取id属性  
  13.     Field idF = c.getDeclaredField("id");  
  14.     //实例化这个类赋给o  
  15.     Object o = c.newInstance();  
  16.     //打破封装  
  17.     idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。  
  18.     //给o对象的id属性赋值"110"  
  19.     idF.set(o, "110"); //set  
  20.     //get  
  21.     System.out.println(idF.get(o));  
  22. }  

  4.获取方法,和构造方法,不再详细描述,只来看一下关键字:

方法关键字

含义

getDeclaredMethods()

获取所有的方法

getReturnType()

获得方法的放回类型

getParameterTypes()

获得方法的传入参数类型

getDeclaredMethod("方法名",参数类型.class,……)

获得特定的方法



构造方法关键字

含义

getDeclaredConstructors()

获取所有的构造方法

getDeclaredConstructor(参数类型.class,……)

获取特定的构造方法



父类和父接口

含义

getSuperclass()

获取某类的父类

getInterfaces()

获取某类实现的接口


         这样我们就可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。

四.Java反射小结

    在学习编程的过程中,我觉得不止要获得课本的知识,更多的是通过学习技术知识提高解决问题的能力,这样我们才能走在最前方。
  Java反射在我们Java学习的过程中是非常重要的知识点。可能有些同学认为这个学习起来不容易理解,其实就我个人而言还是比较简单,学习起来也比较容易理解。下面我给大家总结一下Java反射学习的要点,同时给出几个比较好的例子。
1、Java反射的概念
  反射含义:可以获取正在运行的Java对象。
2、Java反射的功能
  1)可以判断运行时对象所属的类
  2)可以判断运行时对象所具有的成员变量和方法
  3)通过反射甚至可以调用到private的方法
  4)生成动态代理
 3、实现Java反射的类
  1)Class:它表示正在运行的Java应用程序中的类和接口
  2)Field:提供有关类或接口的属性信息,以及对它的动态访问权限
  3)Constructor:提供关于类的单个构造方法的信息以及对它的访问权限
  4)Method:提供关于类或接口中某个方法信息
  注意:Class类是Java反射中最重要的一个功能类,所有获取对象的信息(包括:方法/属性/构造方法/访问权限)都需要它来实现
4、编写Java反射程序的步骤:
 1)必须首先获取一个类的Class对象
  例如:
  Class c1 = Test.class;
  Class c2 = Class.forName(“com.reflection.Test”);
  Class c3 = new Test().getClass();
2)然后分别调用Class对象中的方法来获取一个类的属性/方法/构造方法的结构
  注意:如果要能够正常的获取类中属性/构造方法/方法应该重点掌握如下的反射类
  Field
  Constructor
  Method
五.示例:此程序例子告诉大家如何操作Class/Field/Constructor/Method等与Java反射相关的类
  1.    package com.reflection;
  2.   import java.lang.reflect.Constructor;
  3.   import java.lang.reflect.Field;
        import java.lang.reflect.InvocationTargetException;
  1.   import java.lang.reflect.Method;
  2.   import java.lang.reflect.Modifier;
  3.   public class TestReflection {
  4.   private String username;
  5.   private String password;
  6.   private int[] age;
  7.   public void setUserName(String username) {
  8.   this.username = username;
  9.   }
  10.   private void setPassWord(String password) {
  11.   this.password = password;
  12.   }
  13.   public static void test01() throws ClassNotFoundException {
  14.   Class c1 = TestReflection.class;
  15.   Class c2 = Class.forName("com.reflection.TestReflection");
  16.    //获取指定的包名
  17.   String package01 = c1.getPackage().getName();
  18.   String package02 = c2.getPackage().getName();
  19.   System.out.println("package01 = " + package01);
  20.   System.out.println("package02 = " + package02);
  21.     //获取类的修饰符
  22.   int mod = c1.getModifiers();
  23.   String modifier = Modifier.toString(mod);
  24.   System.out.println("modifier = " + modifier);
  25.     //获取指定类的完全限定名
  26.   String className = c1.getName();
  27.   System.out.println("className = " + className);
  28.     //获取指定类的父类
  29.   Class superClazz = c1.getSuperclass();
  30.   String superClazzName = superClazz.getName();
  31.   System.out.println("superClazzName = " + superClazzName);
  32.    //获取实现的接口
  33.   Class[] interfaces = c1.getInterfaces();
  34.   for (Class t : interfaces) {
  35.   System.out.println("interfacesName = " + t.getName());
  36.   }
  37.     //获取指定类的成员变量
  38.   Field[] fields = c1.getDeclaredFields();
  39.   for (Field field : fields) {
  40.   modifier = Modifier.toString(field.getModifiers()); 
  41.    //获取每个字段的访问修饰符
  42.   Class type = field.getType();
  43.    //获取字段的数据类型所对应的Class对象
  44.   String name = field.getName();
  45.    //获取字段名
  46.   if (type.isArray()) {
  47.    //如果是数组类型则需要特别处理
  48.   String arrType = type.getComponentType().getName() +"[]";
  49.   System.out.println("" + modifier + " " + arrType + " "
  50.   + name + ";");
  51.   } else {
  52.   System.out.println("" + modifier + " " + type + " " +
  53.   name + ";");
  54.   }
  55.   }
  56. //获取类的构造方法
  57.   Constructor[] constructors = c1.getDeclaredConstructors();
  58.   for (Constructor constructor : constructors) {
  59.   String name = constructor.getName();
  60.    //构造方法名
  61.   modifier = Modifier.toString(constructor.getModifiers());
  62.    //获取访问修饰符
  63.   System.out.println("" + modifier +" " + name + "(");
  64.   Class[] paramTypes = constructor.getParameterTypes();
  65.    //获取构造方法中的参数
  66.   for (int i = 0; i < paramTypes.length; i++) {
  67.   if (i > 0) {
  68.   System.out.print(",");
  69.   }
  70.   if (paramTypes[i].isArray()) {
  71.   System.out.println(paramTypes
  72.   [i].getComponentType().getName()+"[]");
  73.   } else {
  74.   System.out.print(paramTypes[i].getName());
  75.   }
  76.   }
  77.   System.out.println(");");
  78.   }
  79.     //获取成员方法
  80.   Method[] methods = c1.getDeclaredMethods();
  81.   for (Method method: methods) {
  82.   modifier = Modifier.toString(method.getModifiers());
  83.   Class returnType = method.getReturnType();
  84.    //获取方法的返回类型
  85.   if (returnType.isArray()) {
  86.   String arrType = returnType.getComponentType
  87.   ().getName()+"[]";
  88.   System.out.print(""+modifier+" " + arrType + " " +
  89.   method.getName() + "(");
  90.   } else {
  91.   System.out.print("" + modifier + " " +
  92.   returnType.getName() + " " + method.getName() + "(");
  93.   }
  94.   Class[] paramTypes = method.getParameterTypes();
  95.   for (int i = 0; i < paramTypes.length; i++) {
  96.   if (i > 0) {
  97.   System.out.print(",");
  98.   }
  99.   if (paramTypes[i].isArray()) {
  100.   System.out.println(paramTypes
  101.   [i].getComponentType().getName()+"[]");
  102.   } else {
  103.   System.out.print(paramTypes[i].getName());
  104.   }
  105.   }
  106.   System.out.println(");");
  107.   }
  108.   }
  109.   public static void test02() throws InstantiationException,
  110.   IllegalAccessException, SecurityException, NoSuchMethodException,
  111.   IllegalArgumentException, InvocationTargetException {
  112.     //反射调用方法,可以通过Method类的invoke方法实现动态方法的调用
  113.    //public Object invoke(Object obj, Object... args)
  114.   //第一个参数代表对象
  115.   //第二个参数代表执行方法上的参数
  116.   //若反射要调用类的某个私有方法,可以在这个私有方法对应的Mehtod对象上先调用setAccessible(true)
  117.   Class c1 = TestReflection.class;
  118.   TestReflection t1 = (TestReflection) c1.newInstance();
  119.    //利用反射来创建类的对象
  120.   System.out.println("username == " + t1.username);
  121.   System.out.println("password == " + t1.password);
  122.   Method method = c1.getDeclaredMethod("setUserName", String.class);
  123.   method.invoke(t1, "Java反射的学习");
  124.   System.out.println("username == " + t1.username);
  125.   method = c1.getDeclaredMethod("setPassWord", String.class);
  126.   method.setAccessible(true);
  127.   method.invoke(t1, "反射执行某个Private修饰的方法");
  128.   System.out.println("password == " + t1.password);
  129.   }
  130.   public static void main(String[] args) throws ClassNotFoundException,
  131.   SecurityException, IllegalArgumentException, InstantiationException,
  132.   IllegalAccessException, NoSuchMethodException, InvocationTargetException {
  133.   // test01();
  134.   test02();
  135.   }
  136.   }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值