java 基础之反射使用总结

反射一般都是使用在框架中比较多,比如javaweb中SSH框架低层就是使用了反射机制,那么什么是反射呢?反射就是把你.class文件也叫字节码文件读取里面的类   方法 属性读取出来等,比如我们通过编译把.java文件编译成.class文件文件,然后通过类加载器加载到JVM中,现在看下我bin目录下的.class文件,

java 基础之反射使用总结_第1张图片

我们平时写一个Person类,可以new出很多Person对象,但是这些.class文件用什么类来表示呢?在java中在java.lang包下有个类Class就表示描述的是.class文件,现在看下api是怎么描述Class类的,不过这是中文文档,



之前说了它可以获取类中的属性 方法 修饰符等,这个在java中也封装成了类,也就是说 像属性,方法,修饰符等封装成了类,然后通过这个类取获取有什么方法,属性等,在java下java.lang.reflect这包下就有上述几个类,

1:Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段

2:Method 

Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。  

3: Modifier类提供了 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类

java 基础之反射使用总结_第2张图片

现在我们依次来获取Class  Constructor Method Field等,然后看给我们提供了什么api可以玩玩,

1:如何获取Class类型对象,

获取Class类型对象一共有三个方法

//第一种方式

Class c1 = Class.forName("com.generic.Person");//c1引用保存内存地址值指向堆中的对象,该对象代表的是Person.class字节码文件

我们打印出c1的值是这样的class com.generic.Person

第二种方式

Class c2 = Person.class;//每个类型都有.class属性,这个类型包含基本类型和引用型类型,比如int.class

第三种方式
在Object类中有一个getClass()方法  表示 返回一个对象的运行时类。它的返回值是 Class<? extends Object>

Person p = new Person("张三", 100);
Class<? extends Person> c3 = p.getClass();

现在有个问题,c1,c2,c3相等么?答案是yes,因为Person.class文件在内存中只有一份,你看到Class类给我们提供了构造函数么,没有,所以不能new,只是上面获取Class对象方式不同而已,但是值是相同的,值是相等的就表示指向堆中的地址值是一样的,
现在看下Class类都给我们提供了什么api给我们调用
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 对象所表示的类的所有公共构造方法
getField(String name) 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段
getFields() 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段
getMethod(String name, Class... parameterTypes)  返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法
getMethods() 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法
getModifiers() 返回此类或接口以整数编码的 Java 语言修饰符
getName() 以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称
getPackage() 获取此类的包

上面是Class类提供的方法,
下面我们通过Class给的方法如何创建对象,获取构造函数,属性等
Person person = c1.newInstance();//获取Person对象
发现它报错了,
java.lang.InstantiationException: com.generic.Person
at java.lang.Class.newInstance(Unknown Source)
at com.generic.Demo1.main(Demo1.java:7)
这是因为Person类没有无参的构造函数造成的,因为我们已经写了一个构造函数带name,age所以java默认不会给我们创建一个无参的构造,所以要我们程序员手动的给加上就不会报错了,
Constructor<Person> constructor = c1.getConstructor(String.class,int.class);//这是获取带参数的构造函数,形参传递的是类型,
Person person2 = constructor.newInstance("李四",120);//通过构造函数创建对象,
System.out.println("age="+person2.getAge()+"------>name="+person2.getName());
下面我们看下Constructor类都有什么方法给我们使用
Constructor类方法
equals(Object obj) 
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 的字符串,其中包括类型参数

获取指定的属性
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);
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值并打印出来
在这要注意下 如果成员变量是用private修饰的,你获取就会报错
java.lang.IllegalAccessException: Class com.generic.Demo1 can not access a member of class com.generic.Person with modifiers "private"
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)
这个时候就要用Field类的父类 AccessibleObject中的一个方法setAccessible(boolean flag) //将此对象的 accessible 标志设置为指示的布尔值  也就是我们常说的暴力反射,但是这样就打破了程序的封装性,使程序变的不安全,因为你私有的变量可以在外面随意给他赋值,
获取类中的方法
package com.generic;


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();
}
}
}
Method类中的主要方法
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 的字符串,包括类型参数


反射的缺点:
(1)使用反射的性能较低 
(2)使用反射相对来说不安全 
(3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性






















































你可能感兴趣的:(java 基础之反射使用总结)