虚拟机类加载机制
概述:
如果需要使用某一个类型,虚拟机把描述类的数据从class文件中加载到运行内存,并 对数据进行校验,转换解析和初始化,最终形成可以被java虚拟机直接使用的类型, 这就是虚拟机的类加载机制。
加载机制的的过程
当程序要使用某个类时,如果该类还未被加载到内存中,系统会通过加载,连接,初始 化三步来实现对这个类的加载。
- 加载:就是指将class文件中的信息读入内存,并为之创建一个Class对象
- 注意:任何类被使用时系统都会建立一个Class对象
- 连接:验证是字节码对象是否有正确的内部结构,检验是否符合官方制定的class 文件规范,以及检查字节码对象中的数据是否会对虚拟机造成危害
- 初始化:负责为类的静态成员分配内存,并设置默认初始化值
类加载机制
- 创建类的实例 创建对象时
- 类的静态成员使用 类名.访问静态方法或者属性时
- 使用反射方式来访问类型时
- 初始化某个类的子类 Stu extends Person new Stu();
- 直接使用java.exe命令来运行某个主类时
类加载器
概述:类加载器是负责加载类的对象。
将class文件中的数据加载到运行内存中,并为之生成对应的字节码对象。
分类:
-
Bootstrap ClassLoader 引导类加载器也被称为根类加载器,负责Java核心类的加载。 -
Extension ClassLoader 扩展类加载器 -
Application ClassLoader 系统类加载器 负责在JVM启动时加载来自java命令的class文件
类加载器之间的继承关系:
-Bootstrap ClassLoader
? -Extension ClassLoader
? -Application ClassLoader
类加载器加载类型的双亲委派机制:
概述:双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器,父类加载器再将该请求委派给父类的父类加载器,如果该在父类加载器在自己的搜索范围内找不到指定类时,子类加载器才会尝试自己去加载
举例:String类型需要加载,只能将加载请求给Application加载器加载,该加载器并不会直接加载,直接将加载请求给父类加载器加载,Extension加载器收到子类的加载请求之后,该加载器将该请求委派给他的父类加载Bootstrap 加载器收到类的加载请求之后,该类加载器在收到请求之后会先检查这个类型它能否加载,如果可以加载,就直接家藏完成。
举例:如果需要加载Person类型,将加载请求给Application加载,直接将该请求给父类加载器Extension 加载器加载,Extension 收到子类的请求之后,一样将请求委派给父类Bootstrap 加载,当Bootstrap 加载器收到请求之后,先检查该类能否加载,Person类型Bootstrap 加载器无法进行加载,只能将请求返回Extension 去加载,Extension 加载器也无法加载给类型,就只能将请求再返回给子类Application ,Application 加载器收到父类返回的请求后,发现该类型可以被加载,所以就加载了该类型。
反射
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c = Person.class;
Class<?> c1 = new Person().getClass();
Class<?> c2 = Class.forName("note.method_.Person");
}
反射获取字节码对象中的构造方法并实例化
概述:根据类的字节码对象获取该类的构造方法,并创造该类对象
获取构造方法的方式
- getConstructors():返回所有公共的构造方法对象
- getDeclaredConstructors():返回所有构造方法对象
- getConstructor():返回空参构造对象
- getConstructor(Class<?>… parameterTypes):返回单个指定参数的公共有参构造方法对象
- getDeclaredConstructor(Class<?>…parameterTypes):返回单个指定参数的有参构造方法对象
通过构造方法对象,创建类的实例
代码
Person类
public class Person {
private String name;
private int age;
public String hobby;
public Person() {
}
public Person(String name, int age, String hobby) {
this.name = name;
this.age = age;
this.hobby = hobby;
}
private Person(String name, int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", hobby='" + hobby + '\'' +
'}';
}
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<?> c = Class.forName("note.constructor_.Person");
System.out.println("1、-------------------------------------");
for (Constructor<?> cons : c.getConstructors()) {
System.out.println(cons);
}
System.out.println("2、-------------------------------------");
for (Constructor<?> dcons : c.getDeclaredConstructors()) {
System.out.println(dcons);
}
System.out.println("3、-------------------------------------");
Constructor<?> con1 = c.getConstructor();
System.out.println(con1);
System.out.println("4、-------------------------------------");
Constructor<?> con2 = c.getConstructor(String.class, int.class, String.class);
System.out.println(con2);
Constructor<?> con3 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(con3);
System.out.println("5、-------------------------------------");
Object o = con1.newInstance();
System.out.println(o);
System.out.println("6、-------------------------------------");
Object o1 = con2.newInstance("张三", 23, "抽烟");
System.out.println(o1);
Object o2 = con3.newInstance("李四", 24);
System.out.println(o2);
}
反射获取成员变量并实例化
获取方法:
- getFields():返回所有公共成员变量对象
- getDeclaredFields():返回所有成员变量对象
- getField(String name):返回指定的公共成员变量对象
- getDeclaredField(String name):返回单个成员变量对象
访问成员属性的方法
set(Object obj,Object value): 用于给obj对象中的该成员变量赋value值
get(Object obj):用于获取obj对象的指定成员变量值
暴力反射
概述:如果类型中的某些属性是私有化的,那么就不能直接使用方法访问该属性所以只能使用暴力反射来强制访问。
相关方法:
- isAccessible():判断当前属性对象是否需要参与虚拟机的检测
- setAccessible(boolean flag):将当前对象设置为不需要被虚拟机检测
代码
Person类
public class Person {
private String name;
private int age;
public String hobby;
public Person() {
}
public Person(String name, int age, String hobby) {
this.name = name;
this.age = age;
this.hobby = hobby;
}
private Person(String name, int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", hobby='" + hobby + '\'' +
'}';
}
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<?> c = Class.forName("note.field_.Person");
System.out.println("1、-------------------------------------");
for (Field f : c.getFields()) {
System.out.println(f);
}
System.out.println("2、-------------------------------------");
for (Field f : c.getDeclaredFields()) {
System.out.println(f);
}
System.out.println("3、-------------------------------------");
Field hobby = c.getField("hobby");
System.out.println(hobby);
System.out.println("4、-------------------------------------");
Field name = c.getDeclaredField("name");
System.out.println(name);
System.out.println("5、-------------------------------------");
Constructor<?> con = c.getConstructor(String.class,int.class,String.class);
Object o = con.newInstance("张三", 23, "抽烟");
System.out.println(hobby.get(o));
hobby.set(o,"喝酒");
System.out.println(hobby.get(o));
System.out.println("6、-------------------------------------");
System.out.println(name.isAccessible());
System.out.println(hobby.isAccessible());
System.out.println("7、-------------------------------------");
name.setAccessible(true);
System.out.println(name.get(o));
name.set(o,"李四");
System.out.println(name.get(o));
}
反射获取成员方法并使用
方法
- getMethods():返回所有公共成员方法对象
- getDeclaredMethods():返回所有成员方法对象
- getMethod(String methodName, Class<?>…parameterTypes):返回指定的公共成员方法对象
- getDeclaredMethod(String methodName, Class<?>…parameterTypes):返回指定的成员方法对象
执行方法的方式
invoke(Object o,Class…paramsTypre)
- 如果方法是已经非静态方法,需要传递一个对象执行
- 如果方法是一个静态方法,不需要传入对象,直接传入Null
代码
Person类
public class Person {
private String name;
private int age;
public String hobby;
public Person() {
}
public Person(String name, int age, String hobby) {
this.name = name;
this.age = age;
this.hobby = hobby;
}
private Person(String name, int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", hobby='" + hobby + '\'' +
'}';
}
public void show(){
System.out.println("Person类中的公共方法");
}
public void show(String s ){
System.out.println("Person类中的带参方法:"+s);
}
private void private_(){
System.out.println("Person类中的私有方法");
}
public int getNum(){
System.out.println("Person类中的带返回值的方法");
return 100;
}
public static void static_(){
System.out.println("Person类中的静态方法");
}
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
Class<?> c = Class.forName("note.method_.Person");
Constructor<?> con = c.getConstructor();
Object o = con.newInstance();
System.out.println("1、-------------------------------------");
for (Method mm : c.getMethods()) {
System.out.println(mm);
}
System.out.println("2、-------------------------------------");
for (Method mm : c.getDeclaredMethods()) {
System.out.println(mm);
}
System.out.println("3、-------------------------------------");
Method m = c.getMethod("show");
m.invoke(o);
System.out.println("4、-------------------------------------");
Method m1 = c.getDeclaredMethod("private_");
m1.setAccessible(true);
m1.invoke(o);
System.out.println("4、-------------------------------------");
Method m2 = c.getMethod("show", String.class);
m2.invoke(o,"张三");
System.out.println("5、-------------------------------------");
Method m3 = c.getMethod("getNum");
m3.invoke(o);
System.out.println("6、-------------------------------------");
Method m4 = c.getMethod("static_");
m4.invoke(o);
m4.invoke(null);
}
案例
需求:
定义一个List集合(泛型定义为Integer),如:ArrayList list = new ArrayList<>();
要求利用反射的原理,在集合中添加若干字符串并且不报错,最终输出集合中的内容
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
ArrayList<Integer> list = new ArrayList<>();
list.add(888);
list.add(118);
list.add(998);
Class<?> c =list.getClass();
Constructor<?> con = c.getConstructor();
Method add = c.getMethod("add",Object.class);
add.invoke(list,"aaa");
add.invoke(list,"bbb");
System.out.println(list);
}
1、自定义一个Stu类型
属性:String name; int age (私有化,定义公共的访问方式)
方法:toString(展示当前属性的信息)show( )
2、手动将这个类型的全类名写在文件中的第一行
3、读取文件中的类名,并创建一个该类对象(通过有参构造创建)
4、使用toString\show()方法展示对象属性
5、使用公共的访问方法给属性改值,并再次调用show方法展示属性值
Stu类:
public class Stu {
private String name;
private int age;
public Stu(String name, int age) {
this.name = name;
this.age = age;
}
public Stu() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Stu{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
private void show(){
System.out.println(name+age);
}
}
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
BufferedReader br = new BufferedReader(new FileReader("22day/src/exercise02/a.txt"));
String s = br.readLine();
Class<?> c = Class.forName(s);
Constructor<?> con = c.getConstructor(String.class, int.class);
Object o = con.newInstance("张三", 23);
Method show = c.getDeclaredMethod("show");
show.setAccessible(true);
show.invoke(o);
Method toString = c.getMethod("toString");
System.out.println(toString.invoke(o));
Field name = c.getDeclaredField("name");
Field age = c.getDeclaredField("age");
name.setAccessible(true);
age.setAccessible(true);
name.set(o,"李四");
age.set(o,99);
System.out.println(toString.invoke(o));
show.invoke(o);
}
}
show = c.getDeclaredMethod("show");
show.setAccessible(true);
show.invoke(o);
Method toString = c.getMethod("toString");
System.out.println(toString.invoke(o));
Field name = c.getDeclaredField("name");
Field age = c.getDeclaredField("age");
name.setAccessible(true);
age.setAccessible(true);
name.set(o,"李四");
age.set(o,99);
System.out.println(toString.invoke(o));
show.invoke(o);
}
}
|