目录
一、类加载器
1.1、类的加载
1.2、类的加载时机
1.3、类加载器
1.4、类加载器的组成
二、反射
2.1、Class类
2.2、通过反射获取构造方法并使用
2.3、通过反射方式,获取私有构造方法,创建对象
2.4、通过反射获取成员变量并使用
2.5、通过反射,创建对象,获取指定的成员变量,进行赋值与获取值 *** 作
2.6、通过反射获取成员方法并使用
2.7、通过反射,创建对象,调用指定的方法
2.8、通过反射,创建对象,调用指定的private 方法
三、反射应用
3.1、泛型擦除
3.2、反射配置文件
一、类加载器 1.1、类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始三步来实现这个类的初始化。
加载
- 指将class文件读入内存,并为之创建一个Class对象
- 任何类被使用时,系统都会建立一个Class对象
连接
- 验证:是否有正确的内部结构,并和其他类协调一致
- 准备:负责为类的静态成员分配内存,并设置默认初始化值
- 解析:将类的二进制数据中的符号引用替换为直接引用
初始化
- 初始化步骤(new 对象)
1.2、类的加载时机
- 创建类的实例
- 类的静态变量,或者为静态变量赋值
- 类的静态方法
- 使用反射方式来强制创建某个类或接口对应的java.long.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类
1.3、类加载器
负责将.class文件加载到内存中,并为之生成对应的Class对象
1.4、类加载器的组成
- Bootstrap ClassLoader 根类加载器,也被称为引导类加载器,负责java核心类的加载。比如System、String等,在JDK中lib目录下rt.jar文件中
- Extension ClassLoader 扩展类加载器,负责JRE中的扩展目录下的jar包的加载,在JDK中jre的lib目录下ext目录
- System ClassLoader系统类加载器,负责在JVM启动时,加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
二、反射
定义:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的功能称为Java语言的反射机制
2.1、Class类
Class没有公共构造方法。Class对象时加载类时有Java虚拟机以及通过调用类加载器中defineClass方法自动构造的
获取Class对象的三种方式
- 通过Object类中的getClass() 方法
Person person = new Person();
Class c = person.getClass();
- 通过 类名.class 获取字节码文件对象
Class c = Person.class();
- 通过 Class类中的方法
Class c = Class.forName("Person");
注意:第三种和前两种的区别
- 前两种必须明确Person类型
- 第三种是指定这种类型的字符串即可,这种扩展性更强。不需要知道类,只需要提供字符串,按照配置文件加载即可
2.2、通过反射获取构造方法并使用
在反射机制中,把类成员(构造方法、成员方法、成员变量)都封装成了对应的类进行表示
构造方法使用Constructor类表示。可以通过Class类中提供的方法来获取构造方法:
- 返回一个构造方法
- getConstructor(Class>..param) 获取public修饰,指定参数类型所对应的构造方法
- getDeclaredConstructor(Class>...param)
- 获取构造方法:
- 获取到Class对象
- 获取指定的构造方法
- 通过构造方法类Constructor中的方法,创建对象 public T newInstance(Object... initargs)
Person类
public class Person {
public String name;
public int age;
private String address;
public Person() {
System.out.println("空参构造方法");
}
public Person(String name) {
this.name = name;
System.out.println("带有String的构造方法");
}
private Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("带有String, int的构造方法");
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
System.out.println("带有String, int, String的构造方法");
}
public void method1() {
System.out.println("没有返回值没有参数的方法");
}
public void method2(String name) {
System.out.println("没有返回值, 有参数的方法, name = " +
name);
}
public int method3() {
System.out.println("有返回值, 没有参数的方法");
return 123;
}
public String method4(String name) {
System.out.println("有返回值, 有参数的方法");
return name;
}
private void method5() {
System.out.println("私有方法");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
public class Demo {
public static void main(String[] args) {
try {
Class c3 = Class.forName("day0507.fanshe.Person");
Constructor> declaredConstructor = c3.getDeclaredConstructor(String.class);
Object instance = declaredConstructor.newInstance("小镭");
System.out.println(instance);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
2.3、通过反射方式,获取私有构造方法,创建对象
- AccessibleObject 类是 Field、Method 和 Constructor 对象的父类。它提供了将反射的对象,标记为在使用时取消默认 Java 语言访问控制检查的能力。
- 对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、 Method 或 Constructor 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例 的时候,会执行访问检查。常用方法如下:
- public void setAccessible(boolean flag) throws SecurityException 参数值为 true,则指示反射的对象在使用时应该取消 Java 语言访问检查。参数值为 false,则指示反射的对象应该实施 Java 语言访问检查。
获取私有构造方法,创建对象:
- 获取到Class对象
- 获取指定的构造方法
- 暴力访问,通过setAccessible(boolean flag)方法
- 通过构造方法类Constructor中的方法,创建对象 public T newInstance(Object... initargs)
public class Demo {
public static void main(String[] args) {
try {
Class c3 = Class.forName("day0507.fanshe.Person");
Constructor> declaredConstructor = c3.getDeclaredConstructor(String.class);
// 取消java语言的访问检查
declaredConstructor.setAccessible(true);
Object instance = declaredConstructor.newInstance("小镭");
System.out.println(instance);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
2.4、通过反射获取成员变量并使用
在反射机制中,把类中成员变量使用Field类表示。可通过Class类中提供的方法获取成员变量:
- 返回一个成员变量
- getField(String name) 获取指定的public修饰的变量
- getDeclaredField(String) 获取指定的任意变量
- 返回多个成员变量
- getFields() 获取指定的public修饰的变量
- getDeclaredFields() 获取所有的变量
public class FiledDemo {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchFieldException {
Class> clazz =
Class.forName("com.kaylee.reflect.Person");
Field name = clazz.getField("name");
System.out.println(name);
Field address = clazz.getDeclaredField("address");
System.out.println(address);
Field[] fields = clazz.getFields();
System.out.println("所有public修饰的变量:");
for (Field field : fields) {
System.out.println(field);
}
Field[] fields2 = clazz.getDeclaredFields();
System.out.println("所有的变量:");
for (Field field : fields2) {
System.out.println(field);
}
}
}
2.5、通过反射,创建对象,获取指定的成员变量,进行赋值与获取值 *** 作
获取成员变量,步骤如下:
- 获取Class对象
- 获取构造方法
- 通过构造方法,创建对象
- 获取指定成员变量(私有成员变量,通过setAccessible(boolean flag) 取消访问检查)
- 通过Field提供的方法,给指定成员变量进行赋值或获取值的 *** 作
- get(Object obj) 获取指定成员变量的值
- set(Object obj, Object value) 给指定成员变量赋值
public class FiledDemo2 {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchFieldException,
NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
Class> clazz =
Class.forName("com.kaylee.reflect.Person");
Constructor> constructor =
clazz.getDeclaredConstructor(String.class);
Object instance = constructor.newInstance("张三");
Field name = clazz.getField("name");
Field age = clazz.getField("age");
Field address = clazz.getDeclaredField("address");
address.setAccessible(true);
// 获取指定成员变量的值
System.out.println("name = " + name.get(instance));
System.out.println("age = " + age.get(instance));
System.out.println("address = " +
address.get(instance));
System.out.println("==================");
// 给指定成员变量赋值
name.set(instance, "李四");
age.set(instance, 22);
address.set(instance, "地球村");
System.out.println("name = " + name.get(instance));
System.out.println("age = " + age.get(instance));
System.out.println("address = " +
address.get(instance));
}
}
2.6、通过反射获取成员方法并使用
在反射机制中,把类中的成员方法使用Method类表示。可通过Class类中提供的方法获取成员方法:
- 返回获取一个方法
- getMethod(String name,Class>..param)获取public修饰的方法
- getDeclaredMethod(String name,Class>..param)获取任意修饰的方法
- 返回获取多个方法
- getMethods() 获取本类与父类中的所有public修饰的方法
- getDeclaredMethods() 获取本类中所有的方法
public class MethodDemo {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchMethodException {
Class> clazz =
Class.forName("com.kaylee.reflect.Person");
Method[] methods = clazz.getMethods();
for(Method method : methods) {
System.out.println(method);
}
System.out.println("============================");
Method[] methods2 = clazz.getDeclaredMethods();
for(Method method : methods2) {
System.out.println(method);
}
System.out.println("============================");
Method method1 = clazz.getMethod("method1", null);
System.out.println(method1);
Method method2 = clazz.getMethod("method2",
String.class);
System.out.println(method2);
Method method5 = clazz.getDeclaredMethod("method5",
null);
System.out.println(method5);
}
}
2.7、通过反射,创建对象,调用指定的方法
获取成员方法,步骤如下:
- 获取Class对象
- 获取构造方法
- 通过构造方法,创建对象
- 获取指定的方法
- 执行找到的方法
- public Object invoke(Object obj, Object... args)
- 执行指定对象obj中,当前Method对象所代表的方法,方法要传入的参数 通过args指定。
public class MethodDemo {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchMethodException {
Class> clazz =
Class.forName("com.kaylee.reflect.Person");
Method[] methods = clazz.getMethods();
for(Method method : methods) {
System.out.println(method);
}
System.out.println("============================");
Method[] methods2 = clazz.getDeclaredMethods();
for(Method method : methods2) {
System.out.println(method);
}
System.out.println("============================");
Method method1 = clazz.getMethod("method1", null);
System.out.println(method1);
Method method2 = clazz.getMethod("method2",
String.class);
System.out.println(method2);
Method method5 = clazz.getDeclaredMethod("method5",
null);
System.out.println(method5);
}
}
2.8、通过反射,创建对象,调用指定的private 方法
获取私有成员方法,步骤如下:
- 获取Class对象
- 获取构造方法
- 通过构造方法,创建对象
- 获取指定的方法
- 开启暴力访问
- 执行找到的方法
public class MethodDemo2 {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException,
InstantiationException {
Class> clazz =
Class.forName("com.kaylee.reflect.Person");
Constructor> constructor =
clazz.getDeclaredConstructor(String.class, int.class,
String.class);
Object obj = constructor.newInstance("张三", 22, "地球村");
Method method1 = clazz.getMethod("method1", null);
method1.invoke(obj, null);
Method method4 = clazz.getMethod("method4",
String.class);
Object result = method4.invoke(obj, "哈哈哈");
System.out.println("返回值:" + result);
Method method5 = clazz.getDeclaredMethod("method5",
null);
method5.setAccessible(true);
method5.invoke(obj, null);
}
}
三、反射应用 3.1、泛型擦除
将已存在的ArrayList
程序编译后产生的.class文件中是没有泛型类型约束的,这种现象我们称为泛型的擦除。因此,我们通过反射技术,来完成
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ArrayList list = new ArrayList<>();
list.add(1);
list.add(2);
// list.add("哈哈哈") // 因为有泛型的约束不能添加字符串类型数据
System.out.println(list);
//Class extends ArrayList> c1 = list.getClass();
//Class c2 = ArrayList.class;
Class> clazz = Class.forName("java.util.ArrayList");
Method add = clazz.getMethod("add", Object.class);
add.invoke(list,"哈哈哈");
System.out.println(list);
}
}
3.2、反射配置文件
通过反射配置文件,运行配置文件中指定类对应的方法
读取Personproperties.txt文件中的数据,通过反射技术,来完成对Person对象的创建
Personproperties的内容如下:
className=day0507.fanshe.Person
methodName=method5
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class ReflectTest2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, InstantiationException {
// 通过Personproperties集合从文件中读取数据
Properties prop = new Properties();
// 读取文件中的数据到集合中
prop.load(new FileInputStream("D:\\实训\\Demo\\src\\day0507\\fanshe\\Personproperties.txt"));
// 获取键所对应的值
String className = prop.getProperty("className");
// 获取字节码文件对象
Class> clazz = Class.forName(className);
// 获取构造方法
Constructor> con = clazz.getDeclaredConstructor(null);
// 创建对象
Object obj = con.newInstance(null);
//获取指定的方法
String methodName = prop.getProperty("methodName");
Method method5 = clazz.getDeclaredMethod(methodName,null);
method5.setAccessible(true);
// 执行方法
method5.invoke(obj,null);
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)