本文主要介绍反射的基本使用
目录
反射
反射作用及优缺点
Class类
创建Class对象的三种方式:
由Class对象得到类的对象
其他常用方法:
获取属性
获取方法
获取构造方法
获取父类及接口
Field类
Method类
Modifier类
Constructor类
代码示例:
反射机制是指在程序运行状态中,对于任意一个类(只要知道类的完整路径,即包名和类名),都能获取这个类的所有信息(所有属性和方法);反射不需要有明确的类型对象,所有的对象都使用Object表示,所以对于一个对象,通过反射都能调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。
作用
优缺点
优点
缺点
java.lang.Class
在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后生成.class文件,在类加载器将.class文件读取到内存中的时候,jvm就会创建.class文件的Class对象,并且只创建一个,存放到jvm的方法区内存中,用于表示这个类的类型信息。任何类在被使用时,都会创建这个类的Class对象,即我们写的每一个类都是对象,即每一个类都有自己的对象,也是Class类的对象
java中的反射就是通过类的Class对象来操作的,来看下Class类:
构造方法:
private Class(ClassLoader loader) //私有的构造方法,无法显示声明一个Class对象,即无法使用new来创建对象
private Class(ClassLoader loader, Class> arrayComponentType) {
classLoader = loader;
componentType = arrayComponentType;
}
1 public static Class> forName(String className) throws ClassNotFoundException,调用Class的静态方法forName获取该类的Class对象,参数className要包括包名和类名,此方法可以不用java文件,只用java对象编译后的.class文件,将其加载到内存中,通过这种方式来创建Class对象,也需要知道完整的路径和类名
2 通过类的隐含的静态成员class调用 比如获取类Student的Class对象 Class c1=Student.class
3java语言中任何一个java对象都有getClass 方法,调用该类的任何一个对象的getClass方法创建该类的Class对象
1public T newInstance() 调用Class对象的newInstance方法,实际上是利用默认构造器来创建该类的实例,该实例为Object类型
该方法在jdk9被Deprecated了
2.使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例。
String getName()返回Class对象的类名,包括包名
String getSimpleName()返回Class对象的类名,不包括包名
ClassLoader getClassLoader()返回当前Class的类加载器
Field getField(String name)返回Class对象对应类的public修饰的指定名字的属性的Field对象,
Field[] getFields() 返回Class对象对应类的所有public修饰的属性的Filed对象数组,不能获取父类的
Field getDeclaredField(String name)返回Class对象对应类的指定名字的属性的Field对象
Field[] getDeclaredFields()返回Class对象对应类的所有属性的Field对象的数组
native int getModifiers()返回Class对象的修饰符对应的int值
Method对应类中的方法
Method getMethod(String name, Class>... parameterTypes)返回Class对象所有公共方法中指定名称的方法,可变参数:该方法中所有形参的类型的Class对象,基本数据类型的不要写成包装类的Class对象
Method[] getMethods()返回Class对象所有Public修饰的方法对应的Method对象的数组,包括父类的public方法,不包括无修饰符的方法
Method getDeclaredMethod(String name, Class>... parameterTypes)返回Class对象中指定方法名的Method对象,第一个参数是方法名,第二个参数是可变参数,是所有形式参数 类型的Class对象,基本数据类型不用写成包装类,参数个数用来区分重载的方法
Method[] getDeclaredMethods()获取Class对象的所有方法的Method对象的数组,只有当前类的方法
Constructor[] getConstructors():获取所有公共public修饰的构造方法 对应的Constructor对象的数组
Constructor
Constructor
Constructor[] getDeclaredConstructors():获取所有构造方法对应的Construct对象的数组
native Class super T> getSuperclass()获取父类的Class对象
Class>[] getInterfaces()获取接口的Class对象的数组,因为接口可以有多个,父类只能有一个
既然设计到了属性,方法,构造方法,修饰符,那就先看属性类Field,java.lang.reflect.Field
用来辅助获取和操作类的字段
常用方法:
Class> getType()返回该属性的类型的Class对象。基本数据类型的返回包装类的Class对象
String getName():返回属性的名称
Object get(Object obj)获取指定对象的指定字段的值
void set(Object obj, Object value)设置指定对象的指定字段的值
setAccessible(boolean flag)设置该属性是否可以被访问,可以把private修饰的属性变为可访问的,从外部打破了访问权限
int getModifiers()获取属性修饰符对应的int值,,0默认的,1public2private4protected
看下Method类,import java.lang.reflect.Method
用来处理Class对象返回的方法
Method常用方法:
String getName()获得方法名
int getModifiers返回当前Method对象的修饰符对应的int值
Class>getReturnType()返回该方法返回值类型对应Class对象
Class>[] getParameterTypes()返回所有 参数类型的Class对象 的数组
Class>getExceptionTypes()返回当前Method对象的底层代码中抛出的异常类型对应的Class对象的数组
Class>getDeclaringClass返回当前Method对象表示的方法所在类或接口的Class实例
String toGenericString()返回描述此Method对象的字符串,包括类型参数
Object invoke(Object obj, Object... args)执行Method对象对应的方法,第一个参数是对象,第二个参数是可变参数,该方法要求的参数,是实参
再来看修饰符类,里面有修饰符的常用方法,在 java.lang.reflect.Modifier
static String toString(int mod)
static boolean isPublic(int mod)将修饰符对应的int参数传入,返回对应的修饰符字符串
static boolean isPublic(int mod)判断是否为public类型,类似的方法还有不少,不一 一列举
再来看下构造器类相关的方法,在java.lang.reflect.Constructor
T newInstance(Object ... initargs)用构造方法来创建实例,返回Object类型的对象,可变参数: 构造器中应传入的参数,实参,无参构造器不需要参数
int getModifiers()返回构造方法的修饰符对应的int值
String getName()返回构造方法的名称,其实就是对应的类名,但是包含包名
Class>[] getParameterTypes()返回构造方法中参数类型对应的Class对象的数组
void setAccessible(boolean flag)修改构造方法的试用权限,可以将私有构造方法设置成可访问,利用私有构造方法创建实例
先看下用来示例的Student类:
public class Student {
private int age;
public String name;
protected int high;
boolean sex;
public Student() {
System.out.println("无参构造器");
}
private Student(String name) {
this.name=name;
}
public Student(int age, String name, int high, boolean sex) {
super();
this.age = age;
this.name = name;
this.high = high;
this.sex = sex;
}
public void setAge(int age) {
this.age = age;
}
public static String test1(int i, String s) {
return s + " : " + i;
}
private int getAge() {
return age;
}
}
下面示例三种方式创建Class对象
public class ReflectTest01 {
public static void main(String[] args) throws ClassNotFoundException {
// 利用反射获取Class对象的三种方式
Class clazz1 = Class.forName("reflect.Student");
System.out.println(clazz1.getName());
// java中每个类都有.class属性
Class clazz2 = Student.class;
// 通过对象实例的引用
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz1 == clazz2);
System.out.println(clazz1 == clazz3);
}
}
out:
reflect.Student
无参构造器
true
true
示例获取类的属性
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ReflectTest03 {
public static void main(String[] args) throws ClassNotFoundException {
Class clazz = Class.forName("reflect.Student");
// 获取public修饰的属性的数组
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
// 获取类中所有的属性,返回Field数组,getName方法
Field[] fields2 = clazz.getDeclaredFields();
for (Field field : fields2) {
// 获取变量名
System.out.println(field.getName());
}
Field[] field3 = clazz.getDeclaredFields();
for (Field field : field3) {
int i = field.getModifiers();// 获取变量修饰符对应的int值,0默认的,1public2private4protected
String str = Modifier.toString(i);
System.out.println(str);
Class c = field.getType();// 返回属性的类型比如Integer,String类对应的Class对象
String s1 = c.getName();// 返回带包名的类名
String s2 = c.getSimpleName();// 返回不带包名的类型
System.out.println(s2);
System.out.println(field.getName());
}
// 反编译打印Student类的属性
StringBuilder sb = new StringBuilder(200);
sb.append(Modifier.toString(clazz.getModifiers()) + "\t" + clazz.getName() + "{\n");
for (Field f : field3) {
sb.append("\t");
if (f.getModifiers() != 0) {
sb.append(Modifier.toString(f.getModifiers()) + " ");
}
sb.append(f.getType().getSimpleName() + " ");
sb.append(f.getName() + "\n");
}
sb.append("}");
System.out.println(sb);
}
}
out:
name
age
name
high
sex
private
int
age
public
String
name
protected
int
high
boolean
sex
public reflect.Student{
private int age
public String name
protected int high
boolean sex
}
获取属性并修改属性示例:
import java.lang.reflect.Field;
public class ReflectTest04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException, InstantiationException {
Class c = Class.forName("reflect.Student");
Object student = c.newInstance();//创建对象实例
Field f1 = c.getField("name");//获取指定public属性
f1.set(student, "张三丰");//为属性赋值,传入对象和值
System.out.println(f1.get(student));//取出值,传入对象
Field f2 = c.getDeclaredField("age");
f2.setAccessible(true);//对不可访问的变量修改访问权限,使其可被访问
f2.set(student, 15);
System.out.println(f2.get(student));
}
}
out:
无参构造器
张三丰
15
演示获取方法相关信息的示例:
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ReflectTest5 {
public static void main(String[] args) throws ClassNotFoundException {
// Class c = Class.forName("reflect.Student");
Class c = Class.forName("java.lang.Object");
Method[] methods = c.getMethods();// 获取Class对象表示的类中所有public方法,包括父类
/*
* for (Method m : methods) { System.out.println(m.getName()); }
*/
Method[] methods2 = c.getDeclaredMethods();// 获取Class对象的所有方法对应的Method数组,不包括父类
for (Method m : methods2) {
System.out.println(Modifier.toString(m.getModifiers()));// 获取方法的修饰符
Class returnType = m.getReturnType();// 返回方法返回值类型对应的Class对象
System.out.println(returnType.getSimpleName());// 输出方法的返回值类型
System.out.println(m.getName());// 获取方法名
Class[] types = m.getParameterTypes();// 获取参数的类型对应的Class对象数组
for (Class type : types) {
System.out.println(type.getSimpleName());
}
System.out.println("----------------");
}
// 反编译打印类中的所有方法
StringBuilder sb = new StringBuilder(200);
sb.append(Modifier.toString(c.getModifiers()) + "\t" + "class " + c.getSimpleName() + "{" + "\n");
for (Method m : methods2) {
sb.append("\t");
sb.append(Modifier.toString(m.getModifiers()) + " ");// 方法修饰符
sb.append(m.getReturnType().getSimpleName() + " "); // 方法返回值
sb.append(m.getName()); // 方法名
sb.append("(");
Class[] classes = m.getParameterTypes(); // 方法的参数
for (int i = 0; i < classes.length; i++) {
sb.append(classes[i].getSimpleName() + " ");
if (i != classes.length - 1) {
sb.append(",");
}
}
sb.append(")");
sb.append("{}\n");
}
sb.append("}");
System.out.println(sb);// 打印拼接好的字符串
}
}
out:
private
int
getAge
----------------
public
void
setAge
int
----------------
public static
String
test1
int
String
----------------
public class Student{
private int getAge(){}
public void setAge(int ){}
public static String test1(int ,String ){}
}
演示调用类中方法示例
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectTest06 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class class1 = Class.forName("reflect.Student");
Method method = class1.getDeclaredMethod("test1", int.class, String.class);//获取指定方法
Object obj = class1.newInstance();//创建对象
Object strObj = method.invoke(obj, 5, "Str");//执行指定方法
System.out.println(strObj);
}
}
out:
无参构造器
Str : 5
获取构造方法并利用构造方法创建实例的示例:
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
public class ReflectTest07 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class c = Class.forName("reflect.Student");
// Class c = Class.forName("java.lang.StringBuilder");
// Class c = Class.forName("java.util.HashMap");
Constructor[] cons = c.getConstructors();// 获取所有公共的构造方法(public修饰),返回一个Constructor类型数组
for (Constructor i : cons) {
System.out.println(Modifier.toString(i.getModifiers()));// 打印修饰符
System.out.print(i.getName() + "\t");// 打印构造方法名字
Class[] classes = i.getParameterTypes();
for (Class c1 : classes) {
System.out.print(c1.getSimpleName() + " ");// 打印参数类型
}
System.out.println();
}
// 调用公共无参构造器创建实例
Constructor con1 = c.getConstructor();
Object obj = con1.newInstance();
// 利用私有构造器创建对象
Constructor con2 = c.getDeclaredConstructor(String.class);// 获取私有构造器
con2.setAccessible(true);// 设置其权限可访问
Object obj2 = con2.newInstance("李白");// 调用私有构造器创建对象实例
// 使用公共有参构造器创建对象
Constructor con3 = c.getDeclaredConstructor(int.class, String.class, int.class, boolean.class);
Object obj3 = con3.newInstance(10, "杜甫", 180, true);
System.out.println(obj3);//返回对象对应的内存地址
}
}
获取父类及接口类型示例
package reflect;
public class ReflectTest08 {
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Class.forName("reflect.Student");
Class c1sup = c1.getSuperclass();// 获取父类
System.out.println(c1sup.getSimpleName());
Class c2 = Class.forName("java.util.HashMap");
Class c2sup = c2.getSuperclass();
System.out.println(c2sup.getSimpleName());
// 获取父接口
Class[] c2inters = c2.getInterfaces();
for (Class ci : c2inters) {
System.out.print(ci.getSimpleName() + " ");
}
System.out.println();// 换行
}
}
out:
Object
AbstractMap
Map Cloneable Serializable
演示将一个类的全部信息通过反射机制打印出来
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ReflectTest09 {
public static void main(String[] args) throws ClassNotFoundException {
// Class c = Class.forName("java.util.HashMap");
Class c = Class.forName("reflect.Student");
Class sup = c.getSuperclass();// 父类
Class[] inters = c.getInterfaces();// 接口数组
Constructor[] cons = c.getDeclaredConstructors();// 构造方法数组
Field[] fields = c.getDeclaredFields();// 属性数组
Method[] methods = c.getDeclaredMethods();// 方法数组
StringBuilder sb = new StringBuilder(400);
// 添加类名,
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName());
// 添加继承类名
if (!sup.getSimpleName().equals("Object")) {
sb.append(" extends " + sup.getSimpleName());
}
// 添加接口名
if (inters.length != 0) {
sb.append(" implements ");
for (int i = 0; i < inters.length; i++) {
sb.append(inters[i].getSimpleName());
if (i != inters.length - 1) {
sb.append(" , ");
}
}
}
// 添加左大括号
sb.append("{\n");
// 添加属性字段
for (Field f : fields) {
sb.append("\t");
if (f.getModifiers() != 0) {// 格式化没有修饰符的方法
sb.append(Modifier.toString(f.getModifiers()) + " ");
}
sb.append(f.getType().getSimpleName() + " ");
sb.append(f.getName() + "\n");
}
sb.append("\n");
// 添加构造方法
for (Constructor con : cons) {
sb.append("\t");
sb.append(Modifier.toString(con.getModifiers()) + " ");// 修饰符
String str = con.getName();// 对构造对象的名字处理
sb.append(str.substring(str.lastIndexOf(".") + 1) + "");// 构造方法名字
sb.append("(");
Class[] classType = con.getParameterTypes();
if (classType.length != 0) {
for (int i = 0; i < classType.length; i++) {
sb.append(classType[i].getSimpleName() + " ");
if (i != classType.length - 1) {
sb.append(",");
}
}
}
sb.append(")");
sb.append("{}\n");
}
sb.append("\n");
// 添加方法
for (Method m : methods) {
sb.append("\t");
if (m.getModifiers() != 0) {
sb.append(Modifier.toString(m.getModifiers()) + " ");// 方法修饰符
}
sb.append(m.getReturnType().getSimpleName() + " "); // 方法返回值
sb.append(m.getName()); // 方法名
sb.append("(");
Class[] classes = m.getParameterTypes(); // 方法的参数
for (int i = 0; i < classes.length; i++) {
sb.append(classes[i].getSimpleName() + " ");
if (i != classes.length - 1) {
sb.append(",");
}
}
sb.append(")");
sb.append("{}\n");
}
sb.append("}");
System.out.println(sb);
}
}
out:
public class Student{
private int age
public String name
protected int high
boolean sex
public Student(int ,String ,int ,boolean ){}
private Student(String ){}
public Student(){}
public void setAge(int ){}
public static String test1(int ,String ){}
private int getAge(){}
}
这段代码只能打印一个java文件定义了一个类,还不能打印接口的信息,如果一个类中还定义内部类,能打印出来内部类的方法,但不能打印出类名,属性,括号信息.
主要参考 http://www.monkey1024.com/javase/702