[Java] Java 反射机制
1 概述:反射机制
- 反射的概念:所谓的反射就是在程序运行时拥有一项自观的能力。反射使您的程序代码能够得到装载到JVM中的类的内部信息,允许您执行程序时才得到需要类的内部信息,而不是在编写代码的时候就必须要知道所需类的内部信息,这使反射成为构建灵活的应用的主要工具。
1.1 原理
- 反射机制是指程序在运行时可以动态地获取类的信息,并且可以调用类的方法、访问类的属性等。
- 反射的概念是由 Smith 在 1982 年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。
- 通俗地讲,一提到反射,我们就可以想到镜子。镜子可以明明白白地照出我是谁,还可以照出别人是谁。反映到程序中,反射就是用来让开发者知道这个类中有什么成员,以及别的类中有什么成员。
- 在Java中,反射机制被广泛应用于框架、工具和其他一些需要动态加载和使用类的场景中。
- 反射是一项高级开发人员应该掌握的“底层黑科技”,其实反射并不是 Java 独有的,许多编程语言都提供了反射功能。
- 反射机制是Java语言的一个特性,它是通过反射API实现的。
- 在Java中,每个类都有一个Class对象,它保存了该类的信息,包括类的名称、成员变量、方法和构造方法等。
- 反射机制就是通过这个Class对象来获取类的信息,并且可以动态地调用类的方法、访问类的属性等。
 
1.2 为什么会有反射机制
有的同学可能会疑惑,Java 已经有了封装为什么还要有反射呢?反射看起来像是破坏了封装性。
甚至让私有变量都可以被外部访问到,使得类变得不那么安全了。我们来看一下 Oracle 官方文档中对反射的描述:
Uses of Reflection
Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.
Extensibility FeaturesAn application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified names.
Class Browsers and Visual Development EnvironmentsA class browser needs to be able to enumerate the members of classes. Visual development environments can benefit from making use of type information available in reflection to aid the developer in writing correct code.
Debuggers and Test ToolsDebuggers need to be able to examine private members on classes. Test harnesses can make use of reflection to systematically call a discoverable set APIs defined on a class, to insure a high level of code coverage in a test suite.
从 Oracle 官方文档中可以看出,反射主要应用在以下几方面:
- 反射让开发人员可以通过外部类的全路径名创建对象,并使用这些类,实现一些扩展的功能。
- 反射让开发人员可以枚举出类的全部成员,包括构造函数、属性、方法。以帮助开发者写出正确的代码。
- 测试时可以利用反射 API 访问类的私有成员,以保证测试代码覆盖率。
也就是说,Oracle 希望开发者将反射作为一个工具,用来帮助程序员实现本不可能实现的功能(perform operations which would otherwise be impossible)。
正如《人月神话》一书中所言:软件工程没有银弹。
很多程序架构,尤其是三方框架,无法保证自己的封装是完美的。如果没有反射,对于外部类的私有成员,我们将一筹莫展,所以我们有了反射这一后门,为程序设计提供了更大的灵活性。工具本身并没有错,关键在于如何正确地使用。
1.3 Java 反射库
- 反射库(Reflection Library)提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵Java代码的程序。这项功能被大量地应用在JavaBeans中,它是Java组件的体系结构(有关Java Beans的详细内容见Java II卷)。
- 使用反射,Java可以支持Visual Basic 用户习惯使用的工具。特别是再设计或运行中添加新类时,能够快速地应用开发工具动态地查询新添加类的能力。
- 能够分析类能力的程序成为反射(Reflective)。反射机制的功能极其强大,在下面可以看到,反射机制可以用来:
- ①在运行中分析类的能力
- ②在运行中查看类对象。例如,编写一个toString()方法提供所有类使用
- ③实现通用数组操作代码
- ④利用
Method对象,这个对象很像C++中的函数指针。
反射是一种功能强大且复杂的机制。使用它的主要人员是工具构造者,而不是应用程序员。
---- 《Java核心技术卷 I 基础知识》
1.4 作用
- 1、反编译:.class –> .java
- 2、通过反射机制访问/操纵java对象的属性、方法、构造方法等;
1)在运行时判断任意一个对象所属的类。
2)在运行时判断任意一个类所具有的成员变量和方法。
3)在运行时任意调用/操纵一个对象的方法
4)在运行时构造任意一个类的对象
1.5 应用场景
哪里用到反射机制?
- 开发通用框架:为了保持通用性,通过配置文件来加载不同的对象,调用不同的方法。
- 
- Spring等很多框架都用到反射机制,注入属性,调用方法。
 
- JDBC中,利用反射动态加载了数据库驱动程序。
- 动态代理:在面向切面编程中,需要拦截特定的方法,就会选择动态代理的方式,而动态代理的底层技术就是反射。
- Eclispe等开发工具利用反射动态刨析对象的类型与结构,动态提示对象的属性和方法。
- Web服务器中利用反射调用了Sevlet的服务方法。
- 注解:注解本身只是起到一个标记符的作用,它需要利用发射机制,根据标记符去执行特定的行为。
1.6 优缺点
- 
优点:可以动态执行,在运行期间根据业务功能动态执行方法、访问属性,最大限度发挥了java的灵活性。 
- 
缺点: 
- 破坏封装:由于反射允许访问私有字段和私有方法,所以可能会破坏封装而导致安全问题。
- 性能开销:由于反射涉及到动态解析,因此无法执行 Java 虚拟机优化,再加上反射的写法的确要复杂得多,所以性能要比“正射”差很多,在一些性能敏感的程序中应该避免使用反射。
对性能有影响,这类操作总是慢于直接执行java代码。
1.7 前置知识
java虚拟机-方法区
- 
java虚拟机有一个运行时数据区,这个数据区又被分为 方法区,堆区和栈区,我们这里需要了解的主要是方法区。
- 
方法区的主要作用是存储被装载的类的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class中的类型信息,将这些信息存储到方法区中。 
- 
方法区的这些信息主要包括: 
 1、这个类型的全限定名
 2、这个类型的直接超类的全限定名
 3、这个类型是类类型还是接口类型
 4、这个类型的访问修饰符
 5、任何直接超接口的全限定名的有序列表
 6、该类型的常量池
 7、字段信息
 8、方法信息
 9、除了常量以外的所有类变量
 10、一个到class类的引用
等等(读者可以参考《深入java虚拟机》这本书的叙述)
1.8 核心API
反射机制的核心API
java.lang.Class
- Class: 一个非常重要的java基础类,每当装载一个新的类型的时候,java虚拟机都会在java堆中创建一个对应于新类型的Class实例。该实例就代表此类型,通过该Class实例我们就可以访问该类型的基本信息。
在方法区中会存储某个被装载类的类型信息。我们就可以通过Class实例来访问这些信息。
- 获得 Class 对象的方法
- Class c = Class.forName("java.lang.String")
- 基本的数据类型,可以用
Class c = int.class或Class c = Integer.TYPE的语句- 非基本数据类型,可以用:
Class c = MyClass.class
- 静态方法
- forName(className)
- 实例方法
- newInstance()
- getName() 这个类型的全限定名
- getSuperClass() 这个类型的直接超类的全限定名
- isInterface() 这个类型是类类型还是接口类型
- getTypeParamters() 这个类型的访问修饰符
- getInterfaces() 任何直接超接口的全限定名的有序列表
- getFields() 字段信息
- getMethods() 方法信息
等等(读者可以自己参看jdk帮助文档,得到更多的信息)
java.lang.reflect.Constructor
- 
Constructor: 用于描述获取到的单个成员构造器信息
- 
获得构造器的方法 
- Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数,
- Constructor[] getConstructors() -- 获得类的所有公共构造函数
- Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关)
- Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关)
java.lang.reflect.Field
- 
Field: 用于描述获取到的单个成员属性信息
- 
获得字段信息的方法 
- Field getField(String name) 获得命名的公共字段
- Field[] getFields() 获得类的所有公共字段
- Field getDeclaredField(String name) 获得类声明的命名的字段
- Field[] getDeclaredFields() 获得类声明的所有字段
- getDeclaredFields
- getFields
- getDeclaredField
- getField
- set(object, fieldValue)
- get(object)/getBoolean/Long/Short/Char/Byte/Double/Int(object)
- getName()
- getType()
- getGenericType()
- getModifiers()
- getAnnotatedType
java.lang.reflect.Method
- 
Method: 用于描述获取到的单个成员方法信息
- 
获得方法信息的方法 
- Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法
- Method[] getMethods() -- 获得类的所有公共方法
- Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法
- Method[] getDeclaredMethods() -- 获得类声明的所有方法
- Method getMethod(String name,Class<?>... parameterTypes)- 获取该Class对象表示类中名字为name、且参数为parameterTypes的指定公共成员方法
 
- Method[] getMethods()- 用于获取该Class对象表示类中所有公共成员方法
 
- Object invoke(Object obj, Object... args)- 使用对象obj来调用此Method对象所表示的成员方法,实参传递args
 
- int getModifiers()- 获取方法的访问修饰符
 
- Class<?> getReturnType()- 获取方法的返回值类型
 
- String getName()- 获取方法的名称
 
- Class<?>[] getParameterTypes()- 获取方法所有参数的类型
 
- Class<?>[] getExceptionTypes()- 获取方法的异常信息
 
java.lang.reflect.Modifier
- Modifier
java.lang.reflect.Parameter
- Parameter
java.lang.reflect.AccessibleObject
- AccessibleObject
2 样例示例代码
- 假定我们有这么一个被试验的类:
package myjava.lang.reflect;  
  
public class Employee {  
    private String name;  
    private Integer salary;  
    
    public static String PREFIX = "EMP";
  
    public Employee() {  
  
    }  
  
    public Employee(String name, Integer salary) {  
        this.name = name;  
        this.salary = salary;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public Integer getSalary() {  
        return salary;  
    }  
  
    public void setSalary(Integer salary) {  
        this.salary = salary;  
    }  
  
    @Override  
    public String toString() {  
        return "Employee{" +  
                "name='" + name + '\'' +  
                ", salary=" + salary +  
                '}';  
    }  
}
2.1 获取【Class/实例对象】
CASE : 综合案例
import org.junit.Test;  
  
/**  
 * @description 类和对象的反射测试  
 * @reference-doc  
 *  [1] [Java反射设置类静态属性值 java实现反射的三种方式 - 51cto](https://blog.51cto.com/u_16213610/7297643)  
 */public class ClassAndInstanceReflectTest {  
    /** 获取 class **/  
    @Test  
    public void getClassTest() throws ClassNotFoundException {  
        //方式1 Class.forName  
        Class c1 = Class.forName("myjava.lang.reflect.Employee");  
        
        //方式2 java中每个类型都有 class 属性  
        Class c2 = Employee.class;  
        
        //方式3 java语言中任何一个java对象都有getClass 方法  
        Employee e = new Employee();  
        Class c3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)  
    }  
  
    /** 创建对象 **/  
    @Test  
    public void createObjectTest() throws ClassNotFoundException, InstantiationException, IllegalAccessException {  
        Class c =Class.forName("myjava.lang.reflect.Employee");  
  
        //创建此Class 对象所表示的类的一个新实例  
        Object o = c.newInstance(); //调用了Employee的无参数构造方法.  
  
        System.out.println(o.toString());//Employee{name='null', salary=null}  
    }  
}
CASE : 获取 指定Class 的类名
import org.junit.Test;
    @Test
    public void getClassFullPath(){
        System.out.println(LogTest.class.getClass().getName()); // java.lang.Class
        System.out.println(LogTest.class.getClass().getCanonicalName()); // java.lang.Class
        System.out.println(LogTest.class.getClass().getSimpleName()); // Class
        System.out.println(LogTest.class.getClass().getTypeName()); // java.lang.Class
        // ////////////
        // getName: 存在于虚拟机中 class 的名称
        System.out.println(LogTest.class.getName()); // cn.johnnyzen.LogTest
        // getCanonicalName(): 取一个更见名思意的名称
        // 大部分两者是没有区别的,但是像 byte[] 这种类型就有区别了
        //   getName():打印显示为 [B
        //   getCanonicalName(): 打印显示为 byte[]
        System.out.println(LogTest.class.getCanonicalName()); // cn.johnnyzen.LogTest
        System.out.println(LogTest.class.getSimpleName()); // LogTest
        System.out.println(LogTest.class.getTypeName()); // cn.johnnyzen.LogTest
    }
2.2 获取/操纵【属性】
package myjava.lang.reflect;  
  
import org.junit.Test;  
  
import java.lang.reflect.Field;  
import java.lang.reflect.Modifier;  
  
/** 属性的反射测试 **/  
public class FieldReflectTest {  
    /**  
     * 获取所有属性  
     * @throws ClassNotFoundException  
     * @reference-doc  
     *  [1] {@lik myjava.lang.reflect.Employee }     */    @Test  
    public void getAllFieldsTest() throws ClassNotFoundException {  
        /** 获取整个类 **/  
        Class c = Class.forName("myjava.lang.reflect.Employee");  
        //获取所有的属性  
        //1) getFields : 只获取 public 的属性字段: PREFIX  
        //Field[] fs = c.getFields();        //2) getDeclaredFields : 获取指定类中所有声明属性的字段数组(包括public、private和protected,但不包括父类的字段): name salary PREFIX  
        Field[] fs = c.getDeclaredFields();  
  
        //定义可变长的字符串,用来存储属性  
        StringBuffer sb = new StringBuffer();  
        //通过追加的方法,将每个属性拼接到此字符串中  
        //最外边的public定义  
        String modifier = Modifier.toString(c.getModifiers());//Modifier.toString(17) = "public final"  
        sb.append(modifier + " class " + c.getSimpleName() +"{\n");  
        //里边的每一个属性  
        for(Field field:fs){  
            sb.append("\t");//空格  
            sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如 "public static final" 等等  
            sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字 例如 "int"            sb.append(field.getName()+";\n");//属性的名字 + 回车 例如 "SIZE"        }  
  
        sb.append("}");  
  
        System.out.println(sb);  
        /**  
         public class Employee{            private String name;            private Integer salary;            public static String PREFIX;         }         */    }  
  
    /** 获取指定的属性 **/  
    @Test  
    public void getTargetFieldTest() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {  
        Employee employee = new Employee("jane", 8970);  
  
        /** 获取整个类 **/  
        Class c = Class.forName("myjava.lang.reflect.Employee");  
        //获取所有的属性  
        Field field1 = c.getField("PREFIX");//PREFIX √(获取成功) , name X(获取失败) , getName X(获取失败)  
        //1) getField("fieldName") : 只获取 public 的属性字段: PREFIX  
        System.out.println("PREFIX : " + field1.get(employee));//"EMP"  
  
        //2) getDeclaredFields : 获取指定类中指定声明属性的字段(支持public、private和protected,但不支持父类的字段): name salary PREFIX  
        Field field2 = c.getDeclaredField("name");  
        // field2.getType()//获取指定名称的 Field,并通过 getType 获取 Field 的 Class
        field2.setAccessible(true);//如不将private属性设置为true,在获取属性值(get)时将报 IllegalAccessException        field2.get(employee); //从对象中获取目标字段的值  
        System.out.println("name : " + field1.get(employee));//"name"  
        field2.set(employee, "jack");//设置目标字段的值  
        System.out.println(String.format("%s(type:%s) = %s" , field2.getName(), field2.getType().toString(), field2.get(employee)));//"name(type:class java.lang.String) = jack"  
    }  
}
2.3 获取/操纵【方法】
package myjava.lang.reflect;  
  
import org.junit.Test;  
  
import java.lang.reflect.Constructor;  
import java.lang.reflect.InvocationTargetException;  
import java.lang.reflect.Method;  
import java.lang.reflect.Parameter;  
  
public class MethodReflectTest {  
    @Test  
    public void aMethodTest() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {  
        Employee employee = new Employee("jane", 83500);  
  
        Class clazz = employee.getClass();  
        // 根据Class对象获取对应的有参构造方法  
        Constructor constructor = clazz.getConstructor(String.class, Integer.class);  
  
        // 使用有参构造方法构造对象,并记录  
        Object employee2 = constructor.newInstance("xiaoping.deng", 30000);  
  
        Method method = clazz.getMethod("getName");  
        //clazz.getMethods() / clazz.getDeclaredMethods()  
        //clazz.getDeclaredMethod(methodName) / clazz.getEnclosingMethod()  
        Object value = method.invoke(employee2);//Object invoke(Object object, Object... args)  
        System.out.println("value : " + value);//xiaoping.deng  
    }  
  
    @Test  
    public void aMethodTest2() throws NoSuchMethodException {  
        Employee employee = new Employee("jane", 83500);  
  
        Class clazz = employee.getClass();  
  
        //Method [] methods = clazz.getMethods();  
        Method method = clazz.getDeclaredMethod("setName", String.class);//查找 方法名为 setName,且入参类型为 String 的方法,查找失败时会报 NoSuchMethodException  
        Class<?> [] parameterTypes = method.getParameterTypes();;  
        Parameter [] parameters = method.getParameters();  
        for(int i=0, size = method.getParameterCount();i<size; i++){  
            Class<?> parameterType = parameterTypes[i];  
            Parameter parameter = parameters[i];  
            //method=setName | parameterType : java.lang.String | parameter # name=name ,type=class java.lang.String, index : 0  
            System.out.println(String.format("method=%s | parameterType : %s | parameter # name=%s ,type=%s, index : %s"  
                , method.getName(), parameterType.getCanonicalName(), parameter.getName(), parameter.getType().toString(), i)  
            );  
        }  
  
        Class<?> returnType = method.getReturnType();  
        System.out.println("returnType : " + returnType.getCanonicalName());//returnType : void  
    }  
}
2.4 获取/操纵【构造器】
- 案例:通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例
import java.lang.reflect.*; 
public class ConstructorDemo { 
   public ConstructorDemo(){ } 
   public ConstructorDemo(int a, int b){ 
       System.out.println("a="+a+"b="+b); 
   } 
   public static void main(String args[]){ 
       try { 
           Class cls = Class.forName("ConstructorDemo"); 
           Class partypes[] = new Class[2]; partypes[0] = Integer.TYPE;   
           partypes[1] = Integer.TYPE; 
           Constructor ct= cls.getConstructor(partypes); 
           Object arglist[] = new Object[2]; 
           arglist[0] = new Integer(37); 
           arglist[1] = new Integer(47); 
           Object retobj = ct.newInstance(arglist); 
         } catch (Throwable e) { 
           System.err.println(e); } 
         } 
   } 
2.X 综合案例
实体类
/**
 * @author:Johnny Zen
 * @date:2017-06-09
 * @description:一个实体类(Person)
 **/
 
import java.lang.reflect.Field;
import javax.activation.FileDataSource;
import com.sun.org.apache.bcel.internal.generic.NEW;
import lombok.Setter;
import lombok.Getter;
@Setter
@Getter
public class Person extends Entity {
    private String name;
    private String password;
    private String sex;
    public String telephone;
    public Person() {
        this.name = "测试名字:哇哈哈";
        this.password = "测试密码:783234";
        this.sex = "测试性别:男";
        this.telephone = "测试电话:2947298569365";
    }
    public Person(String name, String password, String sex, String telephone) {
        super();
        this.name = name;
        this.password = password;
        this.sex = sex;
        this.telephone = telephone;
    }
    
    @Override
    public String toString() {
        return "Person [name=" + name + ",  password=" + password + ", sex=" + sex + ",  telephone="
                + telephone + "]";
    }
}
abstract class Entity {
    
}
反射试验
public static void main(String args[]) throws IllegalAccessException {
	 Person person1 = new Person("王华","123456","男","15902848904");
	 Person person2 = new Person();
	 Person person3 = new Person();
	 try {
		System.out.println("对getClass()所有方法的遍历:"); 
		System.out.println("person1.getClass().desiredAssertionStatus():"+person1.getClass().desiredAssertionStatus()); //期望的断言状态
		//out : person1.getClass().desiredAssertionStatus():false
		
		System.out.println("person1.getClass().equals(person2):"+person1.getClass().equals(person2));//out: person1.getClass().equals(person2):false
		System.out.println("person1.getClass().equals(person1):"+person1.getClass().equals(person1));//out: person1.getClass().equals(person1):false
		System.out.println("person2.getClass().equals(person3):"+person2.getClass().equals(person3));//out: person2.getClass().equals(person3):false
		
		System.out.println("person1.getClass().getCanonicalName():"+person2.getClass().getCanonicalName());//获取权威正规的类名
		//out: person1.getClass().getCanonicalName():Person
		
		System.out.println("person1.getClass().getModifiers():"+person1.getClass().getModifiers());
		//out: person1.getClass().getModifiers():1
		System.out.println("person1.getClass().getName():"+person1.getClass().getName());
		//out: person1.getClass().getName():Person
		System.out.println("person1.getClass().getSimpleName():"+person1.getClass().getSimpleName());
		//out: person1.getClass().getSimpleName():Person
		System.out.println("person1.getClass().getTypeName():"+person1.getClass().getTypeName());
		//out: person1.getClass().getTypeName():Person
		
		System.out.println("person1.getClass().hashCode():"+person1.getClass().hashCode());//获取该类的hashcode值
		//out: person1.getClass().hashCode():914424520
		System.out.println("person2.getClass().hashCode():"+person2.getClass().hashCode());
		//out: person2.getClass().hashCode():914424520
		System.out.println("person3.getClass().hashCode():"+person3.getClass().hashCode());
		//out: person3.getClass().hashCode():914424520
		
		System.out.println("person1.getClass().toGenericString():"+person1.getClass().toGenericString
		//out: person1.getClass().toGenericString():public class Person
		System.out.println("person1.getClass().toString():"+person1.getClass().toString());
		//out: person1.getClass().toString():class Person
		
		System.out.println("person1.getClass().isAnnotation():"+person1.getClass().isAnnotation());  //是否为注解类型
		//out: person1.getClass().isAnnotation():false
//            System.out.println("【person1.getClass().asSubclass(null)】:"+person1.getClass().asSubclass(null));  //疑问?
//            System.out.println("【person1.getClass().cast(person1)】:"+person1.getClass().cast(person1));   //疑问?
//            System.out.println("person1.getClass().cast(person1):"+person1.getClass().cast(person1));   //疑问?
//            System.out.println("person1.getClass().isAnnotationPresent(null):"+person1.getClass().isAnnotationPresent(null)); //疑问?
		
		System.out.println("person1.getClass().isAnonymousClass():"+person1.getClass().isAnonymousClass()); //是否是匿名类
		//out: person1.getClass().isAnonymousClass():false
		System.out.println("(new int[2]).getClass().isAnonymousClass():"+(new int[2]).getClass().isAnonymousClass()); //是否是匿名类
		//out: (new int[2]).getClass().isAnonymousClass():false
		
		System.out.println("person1.getClass().isArray():"+person1.getClass().isArray()); //是否是数组类
		//out: person1.getClass().isArray():false
		System.out.println("(new int[2]).getClass().isArray():"+(new int[2]).getClass().isArray()); //是否是数组类
		//out: (new int[2]).getClass().isArray():true
		
		/*重点方法:getFields():*/
		System.out.println("***************************************************************************************************");
		System.out.println("person1.getClass().getFields()[0].getName():"+person1.getClass().getFields()[0].getName()); //获取公共属性的第(0+1)个属性
		//out: person1.getClass().getFields()[0].getName():telephone
		
		Field fields1[] = person1.getClass().getFields(); //仅仅能获取到public属性的field
//            System.out.println("fields1[1].get(person2):"+fields1[1].get(person2)); //由于第二个域获取不到,域数组长度为1,故产生数组超界
		Field fields2[] = person1.getClass().getDeclaredFields(); //获取到所有声明的field(包括private的)
		System.out.println("fields2[1].get(person2):"+fields2[1].get(person2));//out: fields2[1].get(person2):测试密码:783234
		System.out.println("fields2[1].get(person1):"+fields2[1].get(person1));//out: fields2[1].get(person1):123456
		
		System.out.println("fields2[1].getName():"+fields2[1].getName());//out: fields2[1].getName():password
		System.out.println("fields2[1].hashCode():"+fields2[1].hashCode());//out: fields2[1].hashCode():-960414226
		System.out.println("fields2[1].toString():"+fields2[1].toString());//out: fields2[1].toString():private java.lang.String Person.password
	
		System.out.println("fields2[1].equals(person2):"+fields2[1].equals(person2));//out: fields2[1].equals(person2):false
		System.out.println("fields2[1].equals(fields2[1]):"+fields2[1].equals(fields2[1]));//field是否相同
		//out: fields2[1].equals(fields2[1]):true
		
		System.out.println("fields2[1].getType():"+fields2[1].getType());
		//out: fields2[1].getType():class java.lang.String
     System.out.println("fields[1].getType().getSimpleName()"+fields[1].getType().getSimpleName());
		//out: fields[1].getType().getSimpleName():String
	 } catch (Exception e) {
		e.printStackTrace();
		// TODO: handle exception
	}
 }
3 应用场景案例
Hibernate : ORM框架
- 
Hibernate是一个屏蔽了JDBC,实现了ORM的java框架,利用该框架我们可以抛弃掉繁琐的sql语句而是利用Hibernate中Session类的save()方法直接将某个类的对象存到数据库中,也就是所涉及到sql语句的那些代码Hibernate帮我们做了。这时候就出现了一个问题,Hibernate怎样知道他要存的某个对象都有什么属性呢?这些属性都是什么类型呢?如此,它在向数据库中存储该对象属性时的sql语句该怎么构造呢?解决这个问题的利器就是我们的java反射!
- 
下面我们以一个例子来进行阐述。 
比如,我们定义了一个
User类: 这个User类中有20个属性和这些属性的get和set方法,相应的在数据库中有一个User表,这个User表中对应着20个字段。
假设我们从User表中提取了一条记录,现在需要将这条记录的20个字段的内容分别赋给一个User对象myUser的20个属性,而Hibernate框架在编译的时候并不知道这个User类,他无法直接调用myUser.getXXX或者myUser.setXXX方法。
- 此时就用到了反射,具体处理过程如下:
1、根据查询条件构造PreparedStament语句,该语句返回20个字段的值;
2、Hibernate通过读取配置文件得到User类的属性列表list(是一个String数组)以及这些属性的类型;
3、创建myUser所属类的Class对象c;
c = myUser.getClass();
4、构造一个for循环,循环的次数为list列表的长度;
4.1、读取list[i]的值,然后构造对应该属性的set方法;
4.2、判断list[i]的类型XXX,调用PreparedStament语句中的getXXX(i),进而得到i出字段的值;
4.3、将4.2中得到的值作为4.1中得到的set方法的参数,这样就完成了一个字段像一个属性的赋值,如此循环即可;
看到了吧,这就是反射的功劳,如果没有反射很难想象如果完成同样的功能会有多么难!但是反射也有缺点,比如性能比较低、安全性比较复杂等,这里就不在讨论这些东西,感兴趣的读者可以在网上找到答案!
X 参考文献
 
    本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号