1. 反射机制:是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java的反射机制。
动态语言:在程序运行时,允许改变程序结构或变量类型。
2. 反射的实现
(1)获取Class对象的三种方式
先定义一个user实体类
package test;
public class User {
private String phone;
private String userName;
private String password;
public User() {
}
public User(String phone, String userName, String password) {
this.phone = phone;
this.userName = userName;
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [phone=" + phone + ", userName=" + userName
+ ", password=" + password + "]";
}
}
得到class的三种方法
package test;
public class ReflectService {
public static void main(String[] args) {
// 第一种方式获取Class对象
// 通过对象调用 getClass() 方法来获取
User user = new User();
Class userClass1 = user.getClass();
System.out.println(userClass1.getName());
// 第二种方式获取Class对象
// 直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高
Class userClass2 = User.class;
System.out.println(userClass2.getName());
// 判断两种方式获取的Class对象是否为同一个
System.out.println(userClass1 == userClass2);
// 第三种方式获取Class对象
// 通过 Class 对象的 forName() 静态方法来获取,用的最多,但会抛出ClassNotFoundException异常,必须是类的全路径。
try {
Class userClass3 = Class.forName("test.User");
System.out.println(userClass3.getName());
// System.out.println(userClass1 ==userClass2);
System.out.println(userClass3 == userClass1);
System.out.println(userClass3 == userClass2);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//
}
}
运行结果
一个类在 JVM 中只能有一个 Class 实例
(2) 通过反射获取构造方法。
public Constructor[] getConstructors():获取所有"公有的"构造方法;
public Constructor[] getDeclaredConstructors():获取所有构造方法(包括私有的、受保护的、默认的、公有的);
public Constructor getConstructor(Class… parameterTypes):获取单个的"公有的"构造方法;
public Constructor getDeclaredConstructor(Class… parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
测试:
package test;
public class User {
public User() {
System.out.println("调用公有的无参构造方法!");
}
public User(String userName) {
System.out.println("调用一个有参的构造方法:" + userName);
}
User(int age) {
System.out.println("调用一个默认的构造方法:" + age);
}
protected User(char ca) {
System.out.println("调用一个受保护的构造方法:" + ca);
}
private User(String userName, int age) {
System.out.println("调用一个私有的构造方法:" + userName + "--" + age);
}
private int id;
String userName;
protected String password;
public boolean flag;
@Override
public String toString() {
return "User [id=" + id + ", userName=" + userName + ", password="
+ password + ", flag=" + flag + "]";
}
}
package test;
import java.lang.reflect.Constructor;
public class ConstructorTest {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("test.User");
System.out.println("**********所有公有构造方法**************");
Constructor[] conArray = clazz.getConstructors();
for (Constructor con : conArray) {
System.out.println(con);
}
System.out.println("*****所有的构造方法(私有、受保护、默认、公有)*****");
conArray = clazz.getDeclaredConstructors();
for (Constructor con : conArray) {
System.out.println(con);
}
System.out.println("*********获取私有构造方法,并调用*********");
Constructor con = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(con);
System.out.println("*********获取公有构造方法,并调用*********");
Constructor cons = clazz.getConstructor();
System.out.println(cons);
// 调用构造方法
Object obj = cons.newInstance();
System.out.println("obj = " + obj);
User user = (User) obj;
System.out.println(user);
}
}
测试结果:
(3)通过反射获取成员变量
Field[] getFields():获取所有的"公有字段";
Field[] getDeclaredFields():获取所有字段(私有、受保护、默认、公有);
public Field getField(String fieldName):获取某个"公有的"字段;
public Field getDeclaredField(String fieldName):获取某个字段;
public void set(Object obj,Object value): obj:表示操作的目标对象;value:字段所要设置的值;如果成语变量为基本类型,可以使用Filed类中带有类型名的值设置方法,如 setBoolean(Object obj,Object value), setInt(Object obj,Object value).
测试
package test;
import java.lang.reflect.Field;
public class FiledTest {
public static void main(String[] args) throws Exception {
Class Clazz = Class.forName("test.User");
System.out.println("获取所有公有的字段");
Field[] fieldArray = Clazz.getFields();
for (Field f : fieldArray) {
System.out.println(f);
}
System.out.println("获取所有的字段(包括私有、受保护、默认的)");
fieldArray = Clazz.getDeclaredFields();
for (Field f : fieldArray) {
System.out.println(f);
}
System.out.println("获取公有字段**并调用");
User user = (User) Clazz.getConstructor().newInstance();
Field filed = Clazz.getField("flag");
System.out.println(filed);
// 为字段设置值
filed.setBoolean(user, false);// 为user中的flag赋值
System.out.println("flag:" + user.flag);
System.out.println("获取私有字段****并调用");
filed = Clazz.getDeclaredField("id");
System.out.println(filed);
/**在访问private,protected成员变量和方法时,必须使用setAccessible(Boolean flag)取消java语言检查**/
filed.setAccessible(true);
filed.setInt(user, 111);
System.out.println("获取受保护字段****并调用");
filed = Clazz.getDeclaredField("password");
System.out.println(filed);
filed.setAccessible(true);
filed.set(user, "123456");
System.out.println("获取默认字段****并调用");
filed = Clazz.getDeclaredField("userName");
System.out.println(filed);
filed.setAccessible(true);
filed.set(user, "登录");
System.out.println("用户信息:" + user);
}
}
测试结果:
(4)通过反射获取成员方法
public Method[] getMethods():获取所有"公有方法"(这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法);
public Method[] getDeclaredMethods():获取的是类自身声明的所有方法;
public Method getMethod(String name,Class<?>… parameterTypes) name : 方法名,Class … : 形参的Class类型对象
public Method getDeclaredMethod(String name,Class<?>… parameterTypes)
测试
package test;
public class User {
public void login1(String userNmae, int userId) {
System.out.println("调用公有的login1()方法: userNmae = " + userNmae
+ ";password=" + userId);
}
protected int login2(int userId) {
System.out.println("调用受保护的login2()方法:userId=" + userId);
return userId;
}
void login3() {
System.out.println("调用默认的login3()方法");
}
private void login4(String telephone) {
System.out.println("调用私有的方法login4(): telephone = " + telephone);
}
}
package test;
import java.lang.reflect.Method;
public class MethodTest {
public static void main(String[] args) throws Exception {
// 1.获取Class对象
Class clazz = Class.forName("test.User");
// 2.获取所有公有方法
System.out.println("获取所有的公有方法");
clazz.getMethods();
Method[] methodArray = clazz.getMethods();
for (Method m : methodArray) {
System.out.println(m);
}
System.out.println("获取所有的方法,包括私有的");
methodArray = clazz.getDeclaredMethods();
for (Method m : methodArray) {
System.out.println(m);
}
User user = (User) clazz.getConstructor().newInstance();
System.out.println("获取公有的方法");
Method method = clazz.getMethod("login1", String.class, int.class);
System.out.println(method);
method.invoke(user, "denglu", 11);
System.out.println("获取私有的login2()方法");
method = clazz.getDeclaredMethod("login2", int.class);
System.out.println(method);
method.setAccessible(true);
Object result = method.invoke(user, 123);
System.out.println("返回值:" + result);
System.out.println("获取私有的login3()方法");
method = clazz.getDeclaredMethod("login3", null);
System.out.println(method);
System.out.println("获取私有的show4()方法");
method = clazz.getDeclaredMethod("login4", String.class);
System.out.println(method);
method.setAccessible(true);
method.invoke(user, "12345678901");
}
}
结果: