`
linleizi
  • 浏览: 232697 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Java 反射原理

 
阅读更多

 

  • JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
  • Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method;其中class代表的是类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略的看到一个类的各个组 成部分。
  • Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。
    • reflection的工作机制,如下简单的例子
      • import java.lang.reflect.Method;
        public class ReflectTest {
               public static void main(String args[]) throws ClassNotFoundException {
                      Class c = Class.forName("java.util.ArrayList");
                      Method[] m = c.getDeclaredMethods();
                      for (Method method : m) {
                             System.out.println(method.toString());
                      }
               }
        }
        
         
      • 这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。
  • Java类反射中的主要方法:
    • 构造函数:
      • Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数,
      • Constructor[] getConstructors() -- 获得类的所有公共构造函数
      • Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关)
      • Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关)
    • 字段:
      • Field getField(String name) -- 获得命名的公共字段
      • Field[] getFields() -- 获得类的所有公共字段
      • Field getDeclaredField(String name) -- 获得类声明的命名的字段
      • Field[] getDeclaredFields() -- 获得类声明的所有字段
    • 方法:
      • Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法
      • Method[] getMethods() -- 获得类的所有公共方法
      • Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法
      • Method[] getDeclaredMethods() -- 获得类声明的所有方法
    • JDK1.5以后关于注解的:
      • Annotation[] getAnnotations() -- 获得所有公共注解
      • Annotation[] getDeclaredAnnotations() -- 获得声明的所有注解
      • AnnotationType getAnnotationType() -- 获得注解的类型
  • 用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:
  1.  
    1. 获得你想操作的类的 java.lang.Class 对象。
    2. 调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。
    3. 使用 reflection API 来操作这些信息。

 

  • 反射的安全性:
    • 在处理反射时安全性是一个较复杂的问题。反射经常由框架型代码使用,由于这一点,我们可能希望框架能够全面接入代码,无需考虑常规的接入限制。但是,在其它情况下,不受控制的接入会带来严重的安全性风险,例如当代码在不值得信任的代码共享的环境中运行时。由于这些互相矛盾的需求,Java编程语言定义一种多级别方法来处理反射的安全性。基本模式是对反射实施与应用于源代码接入相同的限制:
      • 从任意位置到类公共组件的接入
      • 类自身外部无任何到私有组件的接入
      • 受保护和打包(缺省接入)组件的有限接入
    • 不过至少有些时候,围绕这些限制还有一种简单的方法。我们可以在我们所写的类中,扩展一个普通的基本类 java.lang.reflect.AccessibleObject 类。这个类定义了一种setAccessible方法,使我们能够启动或关闭对这些类中其中一个类的实例的接入检测。唯一的问题在于如果使用了安全性管理 器,它将检测正在关闭接入检测的代码是否许可了这样做。如果未许可,安全性管理器抛出一个例外。
    • 下面是一段程序:
      •        public static void main(String args[]) throws ClassNotFoundException {
                      try {
                             String test = "";
                             Class clas = test.getClass();
                             Field field = clas.getDeclaredField("count");
                             // field.setAccessible(true);
                             System.out.println(field.get("test"));
                      } catch(Exception e) {
                             System.out.println("Exception");
                             e.printStackTrace(System.out);
                      }
               }
        
         
      • 如果我们编译这一程序时,不使用任何特定参数直接运行,它将在field .get(“test”)调用中抛出一个IllegalAccessException异常。如果我们不注释 field.setAccessible(true)代码行,那么重新编译并重新运行该代码,它将编译成功。最后,如果我们在命令行添加了JVM参数 -Djava.security.manager以实现安全性管理器,它仍然将不能通过编译,除非我们定义了ReflectSecurity类的许可权 限。
  • 反射的性能:
    • 写了个简单的测试程序,如下:
      • import java.lang.reflect.Method;
        
        public class ReflectTest {
        	String name;
        	int age;
        	public static void main(String args[])  throws Exception {
        		
        		Object o2 = javaCreate();
        		
        		ReflectTest my = new ReflectTest();
        		
        		long a = System.currentTimeMillis();
        		long b = System.currentTimeMillis();
        		a = System.currentTimeMillis();
        		for (int i = 0; i < 5000; i++) {
        			javaCreate();
        		}
        		b = System.currentTimeMillis();
        		System.out.println("javaCreate : " + (b - a));
        		
        		a = System.currentTimeMillis();
        		for (int i = 0; i < 5000; i++) {
        			manualCreate();
        		}
        		b = System.currentTimeMillis();
        		System.out.println("manualCreate : " + (b - a));
        		
        		a = System.currentTimeMillis();
        		for (int i = 0; i < 5000; i++) {
        			javaSet(o2);
        		}
        		b = System.currentTimeMillis();
        		System.out.println("javaSet : " + (b - a));
        		
        		a = System.currentTimeMillis();
        		for (int i = 0; i < 5000; i++) {
        			manualSet(my);
        		}
        		b = System.currentTimeMillis();
        		System.out.println("manualSet : " + (b - a));
        		
        		a = System.currentTimeMillis();
        		for (int i = 0; i < 5000; i++) {
        			javaGet(o2);
        		}
        		b = System.currentTimeMillis();
        		System.out.println("javaGet : " + (b - a));
        		
        		a = System.currentTimeMillis();
        		for (int i = 0; i < 5000; i++) {
        			 manualGet(my);
        		}
        		b = System.currentTimeMillis();
        		System.out.println("manualGet : " + (b - a));
        	}
        
        	// ===============下面是 java自身的直接反射的方法
        	public static Object javaCreate()  throws Exception {
        		Object ob = ReflectTest.class.newInstance();
        		return ob;
        	}
        	public static void javaSet(Object ob)  throws Exception {
        		Method m = ReflectTest.class.getDeclaredMethod("setName",
        				new Class[] { String.class });
        		m.invoke(ob, new Object[] { "旺旺旺" });
        	}
        	public static void javaGet(Object ob) throws Exception {
        		Method m = ReflectTest.class.getDeclaredMethod("getName", new Class[0]);
        		m.invoke(ob, new Object[0]);
        	}
        	// ===============下面是 手动的创建对象
        	public static ReflectTest manualCreate() {
        		ReflectTest my = new ReflectTest();
        		return my;
        	}
        
        	public static void manualSet(ReflectTest my) {
        		my.setName("旺旺旺");
        	}
        	public static void manualGet(ReflectTest my) {
        		my.getName();
        	}
        	public int getAge() {
        		return age;
        	}
        	public void setAge(int age) {
        		this.age = age;
        	}
        	public String getName() {
        		return name;
        	}
        	public void setName(String name) {
        		this.name = name;
        	}
        }
        
         
      • 运行结果: 写道
        javaCreate : 22
        manualCreate : 0
        javaSet : 40
        manualSet : 0
        javaGet : 9
        manualGet : 0
         
    • 由此可见,反射对性能的影响。
  • 总结:
    • Java语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象(根据安全性限制),无需提前硬编码目标类。这些特性使得反射 特别适用于创建以非常普通的方式与对象协作的库。例如,反射经常在持续存储对象为数据库、XML或其它外部格式的框架中使用。Java reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。Java 的这一特性非常强大,并且是其它一些常用语言,如 C、C++、Fortran 或者 Pascal 等都不具备的。
    • 但反射有两个缺点。第一个是性能问题。用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相 对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性 能问题才变得至关重要。
    • 许多应用中更严重的一个缺点是使用反射会模糊程序内部实际要发生的事情。程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问 题。反射代码比相应的直接代码更复杂,正如性能比较的代码实例中看到的一样。解决这些问题的最佳方案是保守地使用反射——仅在它可以真正增加灵活性的地方 ——记录其在目标类中的使用。

 

 

 

分享到:
评论

相关推荐

    java反射原理

    ### Java反射原理详解 #### 一、Java反射机制概述 Java反射机制是Java语言的关键特性之一,赋予了Java一定程度上的动态性。通过反射,程序可以在运行时获取任意一个已知名称类的内部信息,包括其修饰符(如public,...

    java反射原理详解

    Java反射机制是Java语言的一种强大的特性,它允许程序在运行时动态地获取类的信息并操作类的对象。在Java中,反射主要涉及到`java.lang.Class`类、`java.lang.reflect`包中的类(如Constructor、Method、Field)以及...

    快速掌握java反射原理

    以下是对Java反射原理的详细解析: 一、Java反射的基本概念 1. 类加载:当Java虚拟机(JVM)加载一个类时,会为该类创建一个`Class`对象。这个过程就是类加载,可以通过`Class.forName()`或`ClassLoader.loadClass...

    双亲委派,3分钟搞懂Java反射原理

    java反射原理

    Java反射原理_SSH框架最底层技术

    理解Java反射原理对于深入学习和使用SSH框架至关重要。 首先,我们需要了解Java虚拟机(JVM)的运行时数据区,特别是方法区。方法区存储了加载的类的类型信息,包括类的全限定名、超类信息、是否为接口、访问修饰符...

    最简单java 反射原理示例

    以下是对这个“最简单Java反射原理示例”的详细解释。 一、Java反射的概念 Java反射机制允许我们在运行时动态地获取类的信息(如类名、方法名、参数类型等)并调用这些方法。这是通过`java.lang.Class`类和相关API...

    Java反射原理

    Java反射原理是Java编程语言中的一个重要特性,它允许程序在运行时检查和操作类、对象、接口等的内部结构和行为。这一特性使得Java具备了动态性,可以在运行时动态发现和调用类的方法、创建对象、访问和修改属性。 ...

    java反射原理及作用

    根据提供的文件信息,我们可以深入探讨Java反射机制的基本原理及其应用场景。 ### Java反射机制的基本概念 Java反射机制允许程序在运行时获取类的信息,并且能够直接操作这些信息。这包括类名、方法名称、参数类型...

    利用java反射原理实现工厂模式

    Java反射机制是Java语言提供的一种强大的工具,允许程序在运行时检查类、接口、字段和方法的信息,并能动态地调用方法或访问和修改字段值。利用反射,我们可以在运行时才知道要创建哪个类的对象,从而极大地提高了...

    面试官这样问我Java反射原理,我刚好都会

    面试中,面试官询问Java反射原理,通常是为了了解候选人的编程灵活性和对Java深层面的理解。 首先,Java反射机制的核心在于`Class`类。每个Java类在运行时都有一个对应的`Class`对象,它存储了类的所有信息,如类名...

    java反射原理制作对象打印工具

    Java反射原理是Java语言提供的一种能够在运行时检查类、接口、字段和方法的能力。通过反射,我们可以动态地创建对象、访问私有成员、调用方法,甚至改变对象的状态。在Java中,`java.lang.Class`类是反射的核心,它...

    Java注解与反射原理说明

    反射(Reflection)是Java提供的一个强大功能,允许程序在运行时检查和操作类、接口、字段以及方法等对象。它允许我们获取类的信息(如类名、属性、方法),创建对象,调用方法,甚至修改私有成员变量的值。反射是...

    hibernate 反射原理

    ### Java反射原理概览 Java反射是Java语言的一个重要特性,它允许运行时检查和操作类、构造函数、字段和方法。Java反射主要由四个核心组件构成:`Class`、`Constructor`、`Field`和`Method`。通过这些组件,开发...

    java反射机制

    6. **JAVA反射原理分析** Java反射机制基于`Class`文件结构和JVM的类加载机制。`Class`文件包含了类的元数据,而JVM在加载类时会解析这些元数据,并通过反射API提供访问。 7. **JAVA反射的应用** 反射在许多场景...

    Java反射机制

    #### 四、Java反射原理分析 1. **Class文件结构**:每个编译后的Java类都会生成一个`.class`文件,包含了类的各种信息,如常量池、字段表、方法表等。 2. **JVM加载类对象**:当JVM加载一个类时,会创建一个`Class`...

    java反射的原理机制

    Java反射是Java编程语言中的一个强大特性,它允许我们在运行时检查类、接口、字段和方法的信息,并且能够在运行时创建和操作对象。...理解并掌握反射原理,对于编写灵活、强大的Java应用程序至关重要。

Global site tag (gtag.js) - Google Analytics