反射一般都是使用在框架中比较多,比如javaweb中SSH框架低层就是使用了反射机制,那么什么是反射呢?反射就是把你.class文件也叫字节码文件读取里面的类 方法 属性读取出来等,比如我们通过编译把.java文件编译成.class文件文件,然后通过类加载器加载到JVM中,现在看下我bin目录下的.class文件,
我们平时写一个Person类,可以new出很多Person对象,但是这些.class文件用什么类来表示呢?在java中在java.lang包下有个类Class就表示描述的是.class文件,现在看下api是怎么描述Class类的,不过这是中文文档,
之前说了它可以获取类中的属性 方法 修饰符等,这个在java中也封装成了类,也就是说 像属性,方法,修饰符等封装成了类,然后通过这个类取获取有什么方法,属性等,在java下java.lang.reflect这包下就有上述几个类,
1:Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段
2:Method
Method
提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。
static
方法和常量,对类和成员访问修饰符进行解码。修饰符集被表示为整数,用不同的位位置 (bit position) 表示不同的修饰符
下面我写了一个简单的Person类,然后编译下生成Person.class文件
package com.generic;
public class Person {
private String name;
private int age;
/**
* 构造函数
* @param name
* @param age
*/
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
下面通过一张图来表示上面几个关系
Person.class 这个文件对应的就是Class类
现在我们依次来获取Class Constructor
Method
Field等,然后看给我们提供了什么api可以玩玩,
1:如何获取Class类型对象,
获取Class类型对象一共有三个方法
//第一种方式
Class c1 = Class.forName("com.generic.Person");//c1引用保存内存地址值指向堆中的对象,该对象代表的是Person.class字节码文件
我们打印出c1的值是这样的class com.generic.Person
第二种方式
Person p = new Person("张三", 100);
Class<? extends Person> c3 = p.getClass();
newInstance()
创建此 Class 对象所表示的类的一个新实例 ---无参的构造
isSynthetic()
如果此类是复合类,则返回 true,否则 false。
isInterface()
判定指定的 Class
对象是否表示一个接口isInstance(Object obj)
判定指定的 Object
是否与此 Class
所表示的对象赋值兼容。
isEnum()
当且仅当该类声明为源代码中的枚举时返回 true
isArray()
判定此 Class
对象是否表示一个数组类
isAnonymousClass()
当且仅当基础类是匿名类时返回 true
isAnnotation()
如果此 Class 对象表示一个注释类型则返回 true。getSuperclass()
返回表示此 Class
所表示的实体(类、接口、基本类型或 void)的超类的 Class
getSimpleName()
返回源代码中给出的基础类的简称getResourceAsStream(String name)
查找具有给定名称的资源getResource(String name)
查找带有给定名称的资源。forName(String className)
返回与带有给定字符串名的类或接口相关联的 Class
对象forName(String name, boolean initialize, ClassLoader loader)
使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class
对象
getClasses()
返回一个包含某些 Class
对象的数组,这些对象表示属于此 Class
对象所表示的类的成员的所有公共类和接口,包括从超类和公共类继承的以及通过该类声明的公共类和接口成员
getClassLoader()
返回该类的类加载器
getConstructor(Class... parameterTypes)
返回一个 Constructor
对象,它反映此 Class
对象所表示的类的指定公共构造方法
getConstructors()
返回一个包含某些 Constructor
对象的数组,这些对象反映此 Class
对象所表示的类的所有公共构造方法
getFields()
返回一个包含某些 Field
对象的数组,这些对象反映此 Class
对象所表示的类或接口的所有可访问公共字段
getMethods()
返回一个包含某些 Method
对象的数组,这些对象反映此 Class
对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法
getModifiers()
返回此类或接口以整数编码的 Java 语言修饰符
getName()
以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称getPackage()
获取此类的包
at java.lang.Class.newInstance(Unknown Source)
at com.generic.Demo1.main(Demo1.java:7)
这是因为Person类没有无参的构造函数造成的,因为我们已经写了一个构造函数带name,age所以java默认不会给我们创建一个无参的构造,所以要我们程序员手动的给加上就不会报错了,
System.out.println("age="+person2.getAge()+"------>name="+person2.getName());
getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null
getDeclaredAnnotations()
返回直接存在于此元素上的所有注释
getDeclaringClass()
返回 Class
对象,该对象表示声明由此 Constructor
对象表示的构造方法的类getExceptionTypes()
返回一组表示声明要抛出的异常类型的 Class
对象,这些异常是由此 Constructor
对象表示的基础构造方法抛出的
getGenericExceptionTypes()
返回一组 Type 对象,这些对象表示声明要由此 Constructor 对象抛出的异常
getGenericParameterTypes()
按照声明顺序返回一组 Type 对象,这些对象表示此 Constructor 对象所表示的方法的形参类型
getModifiers()
以整数形式返回此 Constructor
对象所表示构造方法的 Java 语言修饰符
getName()
以字符串形式返回此构造方法的名称
getParameterAnnotations()
按照声明顺序返回一组数组,这些数组表示通过此 Method 对象表示的方法的形参上的注释
getParameterTypes()按照声明顺序返回一组 Class
对象,这些对象表示此 Constructor
对象所表示构造方法的形参类型
getTypeParameters()
按照声明顺序返回一组 TypeVariable 对象,这些对象表示通过此 GenericDeclaration 对象所表示的一般声明来声明的类型变量
hashCode()
返回此 Constructor
的哈希码
isSynthetic()
如果此构造方法是一个复合构造方法,则返回 true;否则返回 false
isVarArgs()
如果声明此构造方法可以带可变数量的参数,则返回 true;否则返回 false
newInstance(Object... initargs)
使用此 Constructor
对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例
toGenericString()
返回描述此 Constructor
的字符串,其中包括类型参数
Constructor<Person> constructor = c1.getConstructor(String.class,int.class);
Person person2 = constructor.newInstance("李四",120);
System.out.println("age="+person2.getAge()+"------>name="+person2.getName());
Field field = c1.getDeclaredField("name");//获取Person对象中的name属性 也就是成员变量,
field.set(person2, "王五");//给name重新赋值
System.out.println(field.get(person2));//获取name值并打印出来
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(Unknown Source)
at java.lang.reflect.AccessibleObject.checkAccess(Unknown Source)
at java.lang.reflect.Field.set(Unknown Source)
at com.generic.Demo1.main(Demo1.java:18)
setAccessible(boolean flag)
//将此对象的 accessible 标志设置为指示的布尔值 也就是我们常说的暴力反射,但是这样就打破了程序的封装性,使程序变的不安全,因为你私有的变量可以在外面随意给他赋值,
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo1 {
private static Object invoke;
private static Method declaredMethod;
private static Object invoke2;
@SuppressWarnings("unchecked")
public static void main(String[] args) throws NoSuchFieldException {
try {
Class<Person> c1 = (Class<Person>) Class.forName("com.generic.Person");//c1引用保存内存地址值指向堆中的对象,该对象代表的是Person.class字节码文件
Constructor<Person> constructor = c1.getConstructor(String.class,int.class);
Person person2 = constructor.newInstance("李四",120);//创建构造函数
// Person person3 = constructor.newInstance();//创建无参构造函数
Method[] methods = c1.getMethods();//获取所有的类中的方法 包含 你父类Object中的所有方法
for(Method m:methods){
System.out.println(m.getName());
}
Method[] methods2 = c1.getDeclaredMethods();//这是返回你类中定义的方法
System.out.println("-------------");
for(Method m:methods2){
System.out.println(m.getName());
}
//以为是二种方法获取Person类中的getName()方法
declaredMethod = c1.getDeclaredMethod("getName", null);
invoke2 = declaredMethod.invoke(person2, null);
System.out.println("invoke2--->"+invoke2);
Method method = c1.getMethod("getName", null);//获取Person类中无参的getName()方法
invoke = method.invoke(person2, null);//求出getName()的返回值
System.out.println("invoke--->"+invoke);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
getDeclaredAnnotations()
返回直接存在于此元素上的所有注释。
getDeclaringClass()
返回表示声明由此 Method
对象表示的方法的类或接口的 Class
对象
getDefaultValue()
返回由此 Method 实例表示的注释成员的默认值
getExceptionTypes()
返回 Class
对象的数组,这些对象描述了声明将此 Method
对象表示的基础方法抛出的异常类型
getGenericExceptionTypes()
返回 Type 对象数组,这些对象描述了声明由此 Method 对象抛出的异常
getGenericParameterTypes()
按照声明顺序返回 Type 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型的
getGenericReturnType()
返回表示由此 Method 对象所表示方法的正式返回类型的 Type 对象
getModifiers()
以整数形式返回此 Method
对象所表示方法的 Java 语言修饰符
getName()
以 String
形式返回此 Method
对象表示的方法名称
getParameterAnnotations()
返回表示按照声明顺序对此 Method 对象所表示方法的形参进行注释的那个数组的数组
getParameterTypes()
按照声明顺序返回 Class
对象的数组,这些对象描述了此 Method
对象所表示的方法的形参类型
getReturnType()
返回一个 Class
对象,该对象描述了此 Method
对象所表示的方法的正式返回类型
getTypeParameters()
返回 TypeVariable 对象的数组,这些对象描述了由 GenericDeclaration 对象表示的一般声明按声明顺序来声明的类型变量invoke(Object obj, Object... args)
对带有指定参数的指定对象调用由此 Method
对象表示的基础方法
isSynthetic()
如果此方法为复合方法,则返回 true;否则,返回 false
isVarArgs()
如果将此方法声明为带有可变数量的参数,则返回 true;否则,返回 false
toGenericString()
返回描述此 Method
的字符串,包括类型参数
反射的缺点:
(2)使用反射相对来说不安全
(3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性