文章目录
反射
程序经过javac.exe(即编译)后,会生成一个或多个字节码文件(.class结尾).接着用java.exe命令对某个字节码文件进行解析,相当于将其加载到内存,此过程就是类的加载.加载到内存中的类,我们称为运行时类,这就是Class的一个实例,会缓存一段时间,期间我们可以进行反射操作.
Class实例的常用获取方式
public void test1() throws ClassNotFoundException {
//创建Class的四种方式
//1.class
Class<Person> clazz1 = Person.class;
System.out.println("clazz1 = " + clazz1);
//2.getClass()
Class<? extends Person> clazz2 = new Person().getClass();
System.out.println("clazz2 = " + clazz2);
//3.Class.forName()(常用)
Class<?> clazz3 = Class.forName("com.javaboy.train.reflect.Person");
System.out.println("clazz3 = " + clazz3);
//4.ClassLoader(了解)
ClassLoader classLoader = ReflectTest.class.getClassLoader();
Class<?> clazz4 = classLoader.loadClass("com.javaboy.train.reflect.Person");
System.out.println("clazz4 = " + clazz4);
System.out.println(clazz1==clazz2);
System.out.println(clazz3==clazz4);
}
常用方法
clazz.forName(String classpath) //用clazz表示获取的Class实例对象.
clazz.newInstance() //创建运行时类的对象.
clazz.getDeclaredXxxs(Object …o) //获取运行时类的所有Xxx,不包括父类.
clazz.getXxxs(Object …o) //获取运行时类及父类中声明为public访问权限的Xxx.
以上两个方法去掉s为只获取指定的Xxx.
clazz…getSuperClass() //获取父类
clazz.getGenericSuperclass(): 获取带泛型的父类.
Xxx.setAccessible(): 设置当前Xxx是可访问的.
Field.set()/get(): 设置/获取属性.
method.invoke():调用方法.
实例代码如下:
public void test() throws Exception{
//通过反射,创建Person类对象
Class<Person> clazz = Person.class;
Constructor<Person> constructor = clazz.getDeclaredConstructor(String.class,int.class);
Person person = constructor.newInstance("haowu",12);
System.out.println(person.toString());
//通过反射,调用对象指定public属性
Field age = clazz.getDeclaredField("age");
age.set(person,13);
System.out.println(person);
//通过反射,调用对象指定public方法
Method show = clazz.getDeclaredMethod("show");
show.invoke(person);
System.out.println("================================");
//通过反射调用私有结构
Constructor<Person> constructor1 = clazz.getDeclaredConstructor(String.class);
constructor1.setAccessible(true);
Person person1 = constructor1.newInstance("昊吴");
System.out.println(person1);
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(person1,"火");
System.out.println(person1);
Method showNation = clazz.getDeclaredMethod("showNation",String.class);
showNation.setAccessible(true);
showNation.invoke(person1, "中国");
}
ClassLoader
ClassLoader: 有4种为自定义类加载器,系统类加载器,拓展加载器,引导加载器(负责Java核心库).
clazz.getClassLoader()
new Properties等同于classLoader.getResourceAsStream(“配置文件地址”).
public void test1(){
//对于自定义类,使用系统类加载器进行加载
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
System.out.println("classLoader = " + classLoader);
//调用系统类加载器的getParent(): 获取扩展类加载器
ClassLoader classLoader1 = classLoader.getParent();
System.out.println("classLoader1 = " + classLoader1);
//调用扩展类加载器的getParent(): 无法获取引导加载器
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println("classLoader2 = " + classLoader2);
// 引导加载器主要负责加载java的核心库类,无法加载自定义类的
ClassLoader classLoader3 = String.class.getClassLoader();
System.out.println("classLoader3 = " + classLoader3);
}
调用运行时类中指定的结构: 属性,方法,构造器
@Test
//调用运行时类中指定的方法(非静态一样的,只不过invoke中的第一个参数可以任意输,不需要为方法的调用者了)
public void test3() throws Exception {
Class<?> clazz = Class.forName("com.javaboy.train.reflect.Student");
//创建运行时类的对象
Student student = (Student) clazz.newInstance();
//获取指定的方法(包括非public的) getDeclaredMethod(获取的方法名称,获取方法的形参列表)
Method method = clazz.getDeclaredMethod("doS", String.class);
//设置当前属性是可访问的
method.setAccessible(true);
//调用方法 invoke(方法调用者,给方法的形参赋值的实参) 返回值为对应方法的返回值
Object o = method.invoke(student, "方法测试");
System.out.println(o);
}
@Test
//调用运行时类中指定的属性
public void test2() throws Exception {
Class<?> clazz = Class.forName("com.javaboy.train.reflect.Student");
//创建运行时类的对象
Student student = (Student) clazz.newInstance();
//获取指定的属性(包括非public的)
Field name = clazz.getDeclaredField("name1");
//设置当前属性是可访问的
name.setAccessible(true);
//设置当前属性的值 set(指明设置那个对象的属性,将此属性设置为多少)
name.set(student,"昊吴");
//获取当前属性的值 get(指明设置那个对象的属性)
System.out.println(name.get(student));
}
@Test
//调用运行时类中指定的构造器
public void test1() throws Exception {
Class<?> clazz = Class.forName("com.javaboy.train.reflect.Student");
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
Student student = (Student) constructor.newInstance("昊吴", 18);
System.out.println("student = " + student);
}