类的加载器将 .class 文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的 java.lang.Class 对象,作为方法区中类数据的访问入口。一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以回收这些 Class 对象。
每个类都有一个 Class 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。通过反射,可以在运行时动态地创建编译时未知的对象(编译期间该类的 .class 不存在),从而在运行时加载类、调用方法、访问属性(即使声明为 private)。
反射最重要的用途就是开发各种通用框架。(框架 = 注解 + 反射 + 设计模式)
很多框架(比如 Spring)都是配置化的(比如通过XML 文件配置 Bean),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。
反射提供了以下功能:
Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包括以下三个类:
Object 类中定义了被所有子类继承的 public final Class getClass() 方法
该方法返回的 Class 对象包含了被 getClass 对象的所有信息(属性、构造器、方法)
获取 Class 对象
(1)对某个对象调用 getClass() 方法
Person p = new Person();
Class<? extends Person> cls1 = p.getClass();
System.out.println(cls1); //class com.xxx.java.Person
(2)直接调用类的 class 属性
Class<Person> cls2 = Person.class;
System.out.println(cls2); //class com.xxx.java.Person
(3)调用 Class 的静态 forName(String className) 方法
Class<?> cls3 = Class.forName("com.xxx.java.Person");
System.out.println(cls3); //class com.xxx.java.Person
(4)使用类加载器:ClassLoader (了解)
ClassLoader classLoader = this.class.getClassLoader();
Class<?> cls4 = classLoader.loadClass("com.xxx.java.Person");
System.out.println(cls4); //class com.xxx.java.Person
问题1:简单谈谈你对 Java 中 Class.forName()、Class.class、getClass() 三者的理解?
创建 Objetct 实例
使用 Class 的 newInstance() 方法创建 Class 对应类的实例
Class<?> c = String.class;
Object str = c.newInstance(); //调用了空参构造器
指定 Class 对应的构造器 ,对Constructor 使用 newInstance() 方法创建实例
Class<?> c = String.class;
Constructor con = c.getConstructor(String.class) //获取String类带String参数的构造器
Object obj = con.newInstance("创建带参实例"); //调用了带参构造器
获取方法和调用方法
package org.ScZyhSoft.common;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class test1 {
public static void test() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> c = methodClass.class;
Object object = c.newInstance();
Method[] methods = c.getMethods();
Method[] declaredMethods = c.getDeclaredMethods();
//获取methodClass类的add方法
Method method = c.getMethod("add", int.class, int.class);
//getMethods()方法获取的所有方法
System.out.println("getMethods获取的方法:");
for(Method m:methods)
System.out.println(m);
//getDeclaredMethods()方法获取的所有方法
System.out.println("getDeclaredMethods获取的方法:");
for(Method m:declaredMethods)
System.out.println(m);
}
}
class methodClass {
public final int fuck = 3;
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b) {
return a+b;
}
}
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,InvocationTargetException
public class test1 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> klass = methodClass.class;
//创建methodClass的实例
Object obj = klass.newInstance();
//获取methodClass类的add方法
Method method = klass.getMethod("add",int.class,int.class);
//调用method对应的方法 => add(1,4)
Object result = method.invoke(obj,1,4);
System.out.println(result);
}
}
class methodClass {
public final int fuck = 3;
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b) {
return a+b;
}
}
获取属性和设置属性
@Test
public void testField() throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
Field name = clazz.getDeclaredField("name");
//2.保证当前属性是可访问的
name.setAccessible(true);
//3.获取、设置指定对象的此属性值
name.set(p,"Tom");
System.out.println(name.get(p));
}