eg:
public Map<Integer, Integer> getMap(String className) {
Class clazz = Class.forName(className);
Consructor con = clazz.getConstructor();
return (Map<Integer, Integer>) con.newInstance();
}
一、总结:
反射的思想:在程序运行过程中确定和解析数据类的类型。
反射的作用:对于在编译期无法确定使用哪个数据类的场景,通过反射可以在程序运行时构造出不同的数据类实例。
反射的基本使用
二、Java 反射的主要组成部分有4个:
1、Class:任何运行在内存中的所有类都是该 Class 类的实例对象,每个 Class 类对象内部都包含了本来的所有信息。记着一句话,通过反射干任何事,先找 Class 准没错!
2、Field:描述一个类的属性,内部包含了该属性的所有信息,例如数据类型,属性名,访问修饰符······
3、Constructor:描述一个类的构造方法,内部包含了构造方法的所有信息,例如参数类型,参数名字,访问修饰符······
4、Method:描述一个类的所有方法(包括抽象方法),内部包含了该方法的所有信息,与Constructor类似,不同之处是 Method 拥有返回值类型信息,因为构造方法是没有返回值的。
5、反射中的用法有非常非常多,常见的功能有以下这几个:
在运行时获取一个类的 Class 对象
在运行时构造一个类的实例化对象
在运行时获取一个类的所有信息:变量、方法、构造器、注解
6、获取 Class 对象的方法有3种:
备注:
内存中只有一个 Class 对象的原因要牵扯到 JVM 类加载机制的双亲委派模型,它保证了程序运行时,加载类时每个类在内存中仅会产生一个Class对象。在这里我不打算详细展开说明,可以简单地理解为 JVM 帮我们保证了一个类在内存中至多存在一个 Class 对象。
内存中只有一个 Class 对象的原因要牵扯到 JVM 类加载机制的双亲委派模型,它保证了程序运行时,加载类时每个类在内存中仅会产生一个Class对象。在这里我不打算详细展开说明,可以简单地理解为 JVM 帮我们保证了一个类在内存中至多存在一个 Class 对象。
获取类中的变量(Field)
Field[] getFields():获取类中所有被public修饰的所有变量
Field getField(String name):根据变量名获取类中的一个变量,该变量必须被public修饰
Field[] getDeclaredFields():获取类中所有的变量,但无法获取继承下来的变量
Field getDeclaredField(String name):根据姓名获取类中的某个变量,无法获取继承下来的变量
获取类中的方法(Method)
Method[] getMethods():获取类中被public修饰的所有方法
Method getMethod(String name, Class...<?> paramTypes):根据名字和参数类型获取对应方法,该方法必须被public修饰
Method[] getDeclaredMethods():获取所有方法,但无法获取继承下来的方法
Method getDeclaredMethod(String name, Class...<?> paramTypes):根据名字和参数类型获取对应方法,无法获取继承下来的方法
获取类的构造器(Constructor)
Constuctor[] getConstructors():获取类中所有被public修饰的构造器
Constructor getConstructor(Class...<?> paramTypes):根据参数类型获取类中某个构造器,该构造器必须被public修饰
Constructor[] getDeclaredConstructors():获取类中所有构造器
Constructor getDeclaredConstructor(class...<?> paramTypes):根据参数类型获取对应的构造器
破坏类的封装性
很明显的一个特点,反射可以获取类中被private修饰的变量、方法和构造器,这违反了面向对象的封装特性,因为被 private 修饰意味着不想对外暴露,只允许本类访问,而setAccessable(true)可以无视访问修饰符的限制,外界可以强制访问。
性能损耗
在直接 new 对象并调用对象方法和访问属性时,编译器会在编译期提前检查可访问性,如果尝试进行不正确的访问,IDE会提前提示错误,例如参数传递类型不匹配,非法访问 private 属性和方法。