简介
反射机制的相关类:java.lang.reflect包
(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
Java反射的主要用途:开发各种通用框架(Spring,Hibernate,Mybatis)。
什么是反射?
Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。
这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。
获取class对象的3种方式
-
第一种:不推荐,因为已经知道对象名
对象名.getClass()
-
第二种:不推荐,因为要导包,依赖太强,不导包就抛编译错误
类名.class
-
第三种:推荐,URL字符串可以写入文件中,但需要处理ClassNotFoundException异常
Class.forName(String className)
参数为包名.类名
在运行期间,同一个类只能产生一个Class对象。
package com.demo.java.reflex;
public class ReflexTest {
public static void main(String[] args) {
// 1:对象名.getClass()
User user = new User();
Class userClass1 = user.getClass();
// 2:类名.class
Class userClass2 = User.class;
// 3:Class.forName(String className)
Class userClass3 = null;
try {
userClass3 = Class.forName("com.demo.java.reflex.User");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Class类常用方法
方法 | 返回值类型 | 说明 |
---|---|---|
getPackage() | Package 对象 | 获取该类的存放路径 |
getName() | String 对象 | 获取该类的名称 |
getSuperclass() | Class 对象 | 获取该类继承的类 |
getInterfaces() | Class 型数组 | 获取该类实现的所有接口 |
getConstructors() | Constructor 型数组 | 获取所有"公有的"构造方法 |
getDeclaredConstructors() | Constructor 型数组 | 获取所有的构造方法,按声明顺序返回 |
getConstructor(Class… parameterTypes) | Comstructor 对象 | 获取指定的"公有的"的构造方法 |
getDeclaredConstructor(Class… parameterTypes) | Comstructor 对象 | 获取指定的构造方法 |
getFields() | Field 型数组 | 获取类中所有public类型的属性 |
getDeclaredFields() | Field 型数组 | 获取类中所有的属性(public、protected、default、private),不包括继承的属性 |
getField(String name) | Field 对象 | 根据公有属性名获取信息 |
getDeclaredField(String name) | Field 对象 | 获取属性信息(可以是保护的,私有的) |
getMethods() | Method 型数组 | 获取所有"公有方法" 包含了父类的方法,也包含Object类 |
getDeclaredMethods() | Method 型数组 | 获取所有的成员方法,包括私有的(不包括继承的) |
getMethod(String name,Class<?>… parameterTypes) | Method 对象 | name : 方法名;Class … : 形参的Class类型对象 |
getDeclaredMethod(String name,Class<?>… parameterTypes) | Method 对象 | 获取方法:可以是保护的或私有的 |
getClasses() | Class 型数组 | 获取所有“public”的内部类 |
getDeclaredClasses() | Class 型数组 | 获取所有内部类 |
getDeclaringClass() | Class 对象 | 如果该类为内部类,则返回它的成员类,否则返回null |
反射的使用
bean类
package com.demo.java.reflex;
import java.util.Date;
public class User {
public String name;
protected int age;
private Date date;
String[] str;
public User() {
super();
}
public User(String name, int age, Date date, String[] str) {
super();
this.name = name;
this.age = age;
this.date = date;
this.str = str;
}
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;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String[] getStr() {
return str;
}
public void setStr(String[] str) {
this.str = str;
}
void showDefault(String str) {
System.out.println("default:" + str);
}
public void showPublic(String str) {
System.out.println("public:" + str);
}
protected void showProtected(String str) {
System.out.println("protected:" + str);
}
private void showPrivate(String str) {
System.out.println("private:" + str);
}
public static void main(String[] args) {
System.out.println("main方法");
}
}
获取成员变量并调用
Class类常用方法:
方法 | 说明 |
---|---|
Field[] getFields() | 获取类中public类型的属性 |
Field[] getDeclaredFields() | 获取类中所有的属性(public、protected、default、private),不包括继承的属性 |
Field getField(String name) | 根据公有属性名获取信息 |
Field getDeclaredField(String name) | 获取属性信息(可以是保护的,私有的) |
Field类常用方法:
方法 | 说明 |
---|---|
void setAccessible(true) | 解除私有限定,给私有变量设置值之前调用 否则将抛出IllegalAccessException |
set(Object obj,Object value) | 设置字段的值 obj:要设置的字段所在的对象(clazz.newInstance(),clazz.getConstructor().newInstance()) value:要为字段设置的值 |
get(Object obj) | 获取属性值 |
String getName() | 获取变量名 |
Type getGenericType() | Class<?> getType() | 获取变量类型 |
int getModifiers() | 以整数形式返回Field 对象表示的字段的 Java 语言修饰符 |
Modifier.toString(field.getModifiers()) | 变量的修饰符 |
/**
* 反射获取成员属性
*
* @param clazz
*/
public void getVariable(Class clazz) {
// 公有变量
System.out.println("获取公有变量:");
Field[] userField = clazz.getFields();
for (Field field : userField) {
System.out.println("公有变量:" + field);
System.out.println("属性名:" + field.getName());
System.out.println("属性类型:" + field.getGenericType());
System.out.println("属性类型:" + field.getType());
System.out.println("修饰符:" + field.getModifiers());
System.out.println("修饰符:" + Modifier.toString(field.getModifiers()));
}
System.out.println("------------------------------------------");
// 所有变量
System.out.println("获取所有变量:");
userField = clazz.getDeclaredFields();
for (Field field : userField) {
System.out.println("变量:" + field);
System.out.println("属性名:" + field.getName());
System.out.println("属性类型:" + field.getGenericType());
System.out.println("属性类型:" + field.getType());
System.out.println("修饰符:" + field.getModifiers());
System.out.println("修饰符:" + Modifier.toString(field.getModifiers()));
System.out.println();
}
System.out.println("------------------------------------------");
System.out.println("获取指定的公有变量并调用:");
try {
Field field = clazz.getField("name");
// 实例化对象
//Object obj = clazz.getConstructor().newInstance();
Object obj = clazz.newInstance();
// 设置属性值
field.set(obj, "小明");
// 转换为对象
User user = (User) obj;
System.out.println("对象获取值:" + user.name);
System.out.println("反射获取值:" + field.get(obj));
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("------------------------------------------");
System.out.println("获取私有与保护变量并调用:");
try {
// private
Field field = clazz.getDeclaredField("date");
Object obj = clazz.newInstance();
// 取消java语言检查,否则将抛出IllegalAccessException
field.setAccessible(true);
field.set(obj, new Date());
// User user = (User) obj;
// user.getDate();
System.out.println("反射获取值:" + field.get(obj));
// protected
field = clazz.getDeclaredField("age");
Object obj1 = clazz.newInstance();
field.set(obj1, 18);
System.out.println("反射获取值:" + field.get(obj1));
} catch (Exception e) {
e.printStackTrace();
}
}
获取成员方法并调用
方法 | 说明 | return |
---|---|---|
以下为Class对象 调用的方法 | ||
getMethods() | 获取所有"公有方法" 包含了父类的方法,也包含Object类 | Method[] |
getDeclaredMethods() | 获取所有的成员方法,包括私有的(不包括继承的) | Method[] |
getMethod(String name,Class<?>… parameterTypes) | name : 方法名;Class … : 形参的Class类型对象 | Method |
getDeclaredMethod(String name,Class<?>… parameterTypes) | 获取方法:可以是保护的或私有的 | Method |
Method类常用方法:
方法 | 说明 | return |
---|---|---|
setAccessible(true) | 解除私有限定,调用私有方法之前调用 否则将抛出IllegalAccessException | void |
invoke(Object obj,Object… args): | 调用方法 obj:要调用方法的对象,args:调用方式时所传递的实参 | Object |
getName() | 获取方法名 | String |
getReturnType() | 获取方法的返回类型 | Class<?> |
getTypeParameters() | 获取参数 | TypeVariable<Method>[] |
/**
* 反射获取方法
*
* @param clazz
*/
public void getMethod(Class clazz) {
System.out.println("获取公有方法:");
Method[] method = clazz.getMethods();
for (Method m : method) {
System.out.println("公有方法:" + m);
System.out.println("方法名" + m.getName());
System.out.println("方法返回类型" + m.getReturnType());
}
System.out.println("------------------------------------------");
System.out.println("获取所有的成员方法,不包括继承的:");
method = clazz.getDeclaredMethods();
for (Method m : method) {
System.out.println("方法:" + m);
System.out.println(m.getName());
}
System.out.println("------------------------------------------");
System.out.println("调用公有方法:");
Method m;
try {
m = clazz.getMethod("showPublic", String.class);
Object obj = clazz.newInstance();
m.invoke(obj, "测试public");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("------------------------------------------");
System.out.println("调用私有方法:");
try {
m = clazz.getDeclaredMethod("showPrivate", String.class);
Object obj = clazz.newInstance();
m.setAccessible(true);
m.invoke(obj, "测试private");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("------------------------------------------");
System.out.println("调用保护方法:");
try {
m = clazz.getDeclaredMethod("showProtected", String.class);
Object obj = clazz.newInstance();
m.setAccessible(true);
m.invoke(obj, "测试protected");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("------------------------------------------");
System.out.println("调用默认方法:");
try {
m = clazz.getDeclaredMethod("showDefault", String.class);
Object obj = clazz.newInstance();
m.setAccessible(true);
m.invoke(obj, "测试default");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("------------------------------------------");
System.out.println("调用main方法:");
try {
m = clazz.getMethod("main", String[].class);
// 方式一
m.invoke(null, (Object)new String[]{"a","b","c"});
// 方式二
m.invoke(null, new Object[]{new String[]{"a","b","c"}});
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("------------------------------------------");
}
获取构造方法
相关方法:
方法 | 返回值类型 | 说明 |
---|---|---|
getConstructors() | Constructor[] | 获取所有"公有的"构造方法 |
getDeclaredConstructors() | Comstructor[] | 获取所有的构造方法 |
getConstructor(Class… parameterTypes) | Comstructor | Class … : 形参的Class类型对象 |
getDeclaredConstructor(Class… parameterTypes) | Comstructor |
Constructor类的常用方法:
方法 | 返回值类型 | 说明 |
---|---|---|
isVarArgs() | boolean | 查看该构造方法是否允许带有可变数量的参数 |
getParameterTypes() | Class 型数组 | 获取该构造方法的各个参数的类型,按照声明的顺序 |
getExceptionTypes() | Class 型数组 | 获取该构造方法可能抛出的异常类型 |
newInstance(Object … initargs) | T | 通过该构造方法利用指定参数创建一个该类的对象,如果未设置参数则表示采用默认无参数的构造方法 |
getModifiers() | int | 获取可以解析出该构造方法所采用修饰符的整数 |
// 通过反射实例化对象
Object obj = clazz.getConstructor().newInstance();
// Object obj = clazz.newInstance();
// newInstance()方法内部实际上调用了无参数构造方法,必须保证无参构造存在才可以。
// 否则会抛出java.lang.InstantiationException异常。
// 所有"公有的"构造方法
Constructor[] cons = clazz.getConstructors();
// 获取所有的构造方法
Comstructor[] cons1 = clazz.getDeclaredConstructors();
// 获取单个的"公有的"构造方法
// 获取无参构造函数,可以不写null
Constructor cdn = clazz.getConstructor(null);
// 获取"某个构造方法"
cdn = clazz.getDeclaredConstructor(int.class);
cdn.setAccessible(true);
// 调用构造方法:
Object object = cdn.newInstance(13);