您的位置:首页 > 编程语言 > Java开发

今天看看Java反射

2016-07-21 16:38 525 查看

什么是Java反射

Java反射机制是在运行状态中,对于任何一个类,都能知道这个类的属性和方法, 对于任何一个对象,都能够调用它的任意一个方法和属性。

Java反射主要是用来

在运行时判断任意一个对象所属的类。

在运行时构造任意一个类的对象。

在运行时判断任意一个类所具有的成员变量和方法。

在运行时调用任意一个对象的方法,生成动态代理。

反射的三种方式

通过 Class.forName() 方法加载字符串,就可以得到该字符串做代表的Class对象

Class<?> cls = Class.forName("com.java.Demo");


通过类名调用class属性得到该类的Class对象。

Class<?> cls = Demo.class;


通过实例的 getClass() 方法得到Class对象

Demo demo = new Demo();
Class <?> cls = demo.getClass();


这三种方法,最后都是要得到一个Class对象,然后获取字段和函数的的方法,都是围绕着这个Class对象来实现的。

生成对象

先获得Class对象,然后通过该Class对象的newInstance()方法获取对象。

Class<?> classType = String.class;

Object obj = classType.newInstance();


先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成

Class<?> classType = Customer.class;

// 获得Constructor对象,此处获取第一个无参数的构造方法的
Constructor cons = classType.getConstructor(new Class[] {});

// 通过构造方法来生成一个对象
Object obj = cons.newInstance(new Object[] {});


但是,上面这种情况只适用于默认的 无参构造函数 ,但是如果是有参构造函数,则会报错。

Exception in thread "main" java.lang.InstantiationException: com.gzl.demo.InvokeTest
at java.lang.Class.newInstance(Class.java:418)
at com.gzl.demo.InvokeTest.main(InvokeTest.java:33)
Caused by: java.lang.NoSuchMethodException: com.gzl.demo.InvokeTest.<init>()
at java.lang.Class.getConstructor0(Class.java:2971)
at java.lang.Class.newInstance(Class.java:403)
... 1 more


这个时候,可以用下面的方法:

Class<?> classType = InvokeTest.class;
//getConstructor(Class<?>... parameterTypes),传递的是可变Class参数
Constructor cons2 = classType.getConstructor(new Class[] {String.class, int.class});
//当是基本数据类型传入的时候,需要一个包装类来包装它,但是jdk1.5也可以直接传入基本数据类型了,因为编译器会帮你自动装箱,拆箱
Object obj2 = cons2.newInstance(new Object[] {"ZhangSan",20});


两种不同的方法的区别

通过反射创建新的类示例,有两种方式:

Class.newInstance()

Constructor.newInstance()

以下对两种调用方式给以比较说明:

Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数;

Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数。

Class.newInstance() 抛出所有由被调用构造函数抛出的异常。

Class.newInstance() 要求被调用的构造函数是可见的,也即必须是public类型的;

Constructor.newInstance() 在特定的情况下,可以调用私有的构造函数。

获取函数Method

一行代码获取所有的方法。

Method[] methods = clazz.getDeclaredMethods();


可以看看Method的API

大概就是几个Get方法,常用的包括:

getModifiers()

以整数形式返回此 Method 对象所表示方法的 Java 语言修饰符。

getName()

以 String 形式返回此 Method 对象表示的方法名称。

getReturnType()

返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型。

invoke(Object obj, Object… args)

对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

在使用invoke方法之前可以先用

class.getMethod(String name,Class

getxxx(field,method,constructor)和getDeclaredxxx(field,method,constructor)的区别

getxxx() 只能访问类中的私有字段,而共有的字段是无法访问的,能访问从其他类继承下来的公共方法。

返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。返回数组中的元素没有排序,也没有任何特定的顺序。

如果类或接口没有可访问的公共字段,或者表示一个数组类、一个基本类型或 void,则此方法返回长度为 0 的数组。

特别地,如果该 Class对象表示一个类,则此方法返回该类及其所有超类的公共字段。

如果该 Class 对象表示一个接口,则此方法返回该接口及其所有超接口的公共字段。

该方法不反映数组类的隐式长度字段。用户代码应使用 Array 类的方法来操作数组。

getDeclaredxxx()

返回一个构造函数对象数组,反映由这个类对象所表示的类所声明的所有构造函数。

这些都是public、protected、default和private。返回的数组中的元素没有排序。

如果类有一个默认的构造函数,它被包含在返回的数组中。如果这个类对象表示一个接口,一个原始类型,一个数组类,或void,此方法返回一个长度为0的数组。

一个例子获取所有需要的方法

记得新建一个类,然后改一下forName()里面包的路径。

package com.gzl.demo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Test {

public static void main(String[] args){
try {
//获取Student的Class对象
Class<?> clazz = Class.forName("com.gzl.demo.Student");
//获取该类中所有的属性
Field[] fields = clazz.getDeclaredFields();
System.out.println("下面打印类中所有属性");
//遍历所有的属性
for (Field field : fields) {
field.setAccessible(true);

//打印属性信息,包括访问控制修饰符,类型及属性名
System.out.println("    修饰符:" + Modifier.toString(field.getModifiers()));
System.out.println("    类型:" + field.getType().toString());
System.out.println("    属性名:" + field.getName());
System.out.println();
}
//获取该类中的所有方法
Method[] methods = clazz.getDeclaredMethods();

for (Method method : methods) {
System.out.println("    修饰符:" + Modifier.toString(method.getModifiers()));
System.out.println("    方法名:" + method.getName());
System.out.println("    返回类型:" + method.getReturnType());

//获取方法的参数对象
Class<?>[] clazzes = method.getParameterTypes();
for (Class<?> class1 : clazzes) {
System.out.println("    参数类型:" + class1);
System.out.println();
}
}

} catch (Exception e) {
e.printStackTrace();
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息