Class类创建的对象我们称为Class对象/类对象/字节码对象
Class对象会保存类中的信息(构造方法, 成员方法, 成员变量等)
有了Class对象就能得到类中的所有信息。
在程序的运行过程中, 通过Class对象得到类中的信息(构造方法, 成员方法, 成员变量), 并操作他们
这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。非正常的手段操作对象。
使用反射创建对象,代码更复杂,无视修饰符,
功能更强大灵活
IDEA的智能提示
框架Spring/SpringMVC/Mybatis
类名.class
对象.getClass()
Class.forName(“类全名”);
注意:三种方式获取到的是同一个Class对象
public static void main(String[] args) throws ClassNotFoundException {
// 类名.class Class:
Class<Employee> cls1 = Employee.class;
System.out.println(cls1);
// 对象.getClass() Class extends Employee>:
Employee employee = new Employee();
Class<? extends Employee> cls2 = employee.getClass();
System.out.println(cls2);
// Class.forName("类全名"); 包名.类名 第三种使用最灵活(常用),因为类不存在也能通过编译
Class<?> cls3 = Class.forName("com.itheima.bean.Employee");
System.out.println(cls3);
}
String getSimpleName(); 获得类名字符串:类名
String getName(); 获得类全名:包名.类名
public static void main(String[] args) {
// 1.得到Class对象
Class<Employee> cls = Employee.class;
// 2.得到类中的信息
String name = cls.getName();
System.out.println(name);
String simpleName = cls.getSimpleName();
System.out.println(simpleName);
}
getConstructors()
getConstructor (Class>… parameterTypes)
getDeclaredConstructors()
getDeclaredConstructor (Class>… parameterTypes)
反射得到的构造器可以做什么?
创建对象
public newInstance(Object… initargs)
如果是非public的构造器,需要打开权限(暴力反射),然后再创建对象
setAccessible(boolean)
反射可以破坏封装性,私有的也可以执行了。
public class Demo06 {
// 得到所有public的构造器: getConstructors
@Test
public void test01() {
// 1.得到Class对象
Class<Employee> cls = Employee.class;
// 2.得到所有public的构造器
Constructor<?>[] constructors = cls.getConstructors();
for (Constructor o:constructors){
System.out.println(o);
}
}
// 得到一个public的构造器: getConstructor
@Test
public void test02() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 1.得到Class对象
Class<Employee> cls = Employee.class;
// 2.得到一个public的构造器
Constructor<Employee> constructor = cls.getConstructor();
System.out.println(constructor);
Constructor<Employee> constructor1 = cls.getConstructor(String.class, int.class);
System.out.println(constructor1);
// Constructor c = cls.getConstructor(); // 匹配无参 public Employee()
// 3.使用构造器创建对象
Employee employee = constructor.newInstance();
Employee employee1 = constructor1.newInstance("张三", 88);
System.out.println(employee);
System.out.println(employee1);
}
// 得到所有存在的构造器: getDeclaredConstructors
@Test
public void test03() {
// 1.得到Class对象
Class<Employee> cls = Employee.class;
// 2.得到所有存在的构造器 Declared:声明的,存在的
//包括私有,protected等
Constructor<?>[] constructors = cls.getDeclaredConstructors();
for (Constructor o : constructors){
System.out.println(o);
}
}
// 得到一个存在的构造器: getDeclaredConstructor
@Test
public void test04() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 1.得到Class对象
Class<Employee> cls = Employee.class;
// 2.得到一个存在的构造器
Constructor<Employee> constructor = cls.getDeclaredConstructor();
Constructor<Employee> constructor1 = cls.getDeclaredConstructor(String.class);
// 3.使用构造器创建对象
Employee employee = constructor.newInstance();
constructor1.setAccessible(true);
Employee employee1 = constructor1.newInstance("王五");
System.out.println(employee);
System.out.println(employee1);
}
}
Class中获取成员方法的方法
getMethods()
getMethod(String name, Class>… parameterTypes)
getDeclaredMethods()
getDeclaredMethod (String name, Class>… parameterTypes)
反射得到成员方法可以做什么?
依然是在某个对象中触发该方法执行。
Object invoke(Object obj, Object… args)
如果某成员方法是非public的,需要打开权限(暴力反射),然后再触发执行
setAccessible(boolean)
public class Demo07 {
// 得到所有public的方法: getMethods
@Test
public void test01() {
// 1.得到Class对象
Class<Employee> cls = Employee.class;
// 2.得到所有public的方法
Method[] methods = cls.getMethods();
for (Method m : methods) {
System.out.println(m);
}
}
@Test
// 得到所有存在的方法: getDeclaredMethods
public void test02() {
// 1.得到Class对象
Class<Employee> cls = Employee.class;
// 2.得到所有存在的方法
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods) {
System.out.println(m);
}
}
// 得到一个public的方法: getMethod
@Test
public void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
// 1.得到Class对象
Class<Employee> cls = Employee.class;
// 2.得到一个public的方法
Method setName = cls.getMethod("setName", String.class);
// 3.调用方法
// Object invoke(Object obj, Object... args)
Employee instance = cls.getConstructor().newInstance();
instance.setAge(19);
setName.invoke(instance, "李四");
Method getName = cls.getMethod("getName");
Object invoke = getName.invoke(instance);
System.out.println(invoke);
// Object obj: 调用方法的对象
// Object... args: 方法的参数
// Object: 返回值
}
// 得到一个存在的方法: getDeclaredMethod
@Test
public void test04() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 1.得到Class对象
Class<?> cls = Class.forName("com.itheima.bean.Employee");
// 2.得到一个存在的方法
Method sleep = cls.getDeclaredMethod("sleep", int.class);
// 3.调用方法
Object instance = cls.getConstructor().newInstance();
sleep.setAccessible(true);
Object hours = sleep.invoke(instance, 2);
System.out.println(hours);
}
}
获取类中成员变量对象的方法
getFields()
getField(String name)
getDeclaredFields()
getDeclaredField(String name)
反射得到成员变量可以做什么?(不常用,因为我们一般通过方法来取值赋值,这样直接拿成员变量赋值效率低)
依然是在某个对象中取值和赋值。
void set(Object obj, Object value):
Object get(Object obj)
如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值
setAccessible(boolean)
public class Demo08 {
// 得到所有public的成员变量: getFields
@Test
public void test01() {
// 1.得到Class对象
Class<Employee> cls = Employee.class;
// 2.得到所有public的成员变量
Field[] fields = cls.getFields();
for (Field f : fields) {
System.out.println(f);
}
}
// 得到所有存在的成员变量: getDeclaredFields
@Test
public void test02() {
// 1.得到Class对象
Class<Employee> cls = Employee.class;
// 2.得到所有存在的成员变量
Field[] declaredFields = cls.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f);
}
}
// 得到一个public的成员变量: getField
@Test
public void test03() throws NoSuchFieldException {
// 1.得到Class对象
Class<Employee> employeeClass = Employee.class;
// 2.得到Field
Field weight = employeeClass.getField("weight");
System.out.println(weight);
}
// 得到一个存在的成员变量: getDeclaredField
@Test
public void test04() throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 1.得到Class对象
Class<Employee> employeeClass = Employee.class;
// 2.得到Field
Field age = employeeClass.getDeclaredField("age");
// 3.给成员变量赋值
// set(Object obj, Object value);
Employee employee = employeeClass.getConstructor().newInstance();
age.setAccessible(true);
age.set(employee, 99);
// Object obj: 成员变量所在对象
// Object value: 新的值
// 4.获取成员变量的值
Object o = age.get(employee);
System.out.println(o);
// Object get(Object obj);
// Object obj: 成员变量所在对象
// Object: 返回成员变量的值
}
}
需求: 利用反射根据文件中的不同类名和方法名,创建不同的对象并调用方法。
分析:
通过Properties加载配置文件
得到类名和方法名
通过类名反射得到Class对象
通过Class对象创建一个对象
通过Class对象得到方法
调用方法
public class Demo09 {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.load(new FileReader("D:\\it_workspace\\src\\config.properties"));
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
Class<?> cls = Class.forName(className);
Object instance = cls.getConstructor().newInstance();
Method method = cls.getMethod(methodName);
method.invoke(instance);
}
}
Teacher
如果你对本文有疑问,你可以在文章下方对我留言,敬请指正,对于每个留言我都会认真查看。