浅谈Java反射机制

java的反射机制是java中最基础而且最重要的知识之一。

一、类装载器ClassLoader

1、java文件的执行过程

【.java->.class(javac)】+类库中的.class->类装载(ClassLoader)->GIT即时编译/Interpreter解释器->执行引擎
【注】类加载到执行引擎之间,我们可以自行选择混合模式(GIT+INTERPRETER)也可以用解释器或者即时编译器的单模式。

2、类装载器的工作机制

1)、背景

【类装载器就是把类的字节码文件装入JVM】
步骤分为:装载->链接->初始化

其中,链接分为三步:
1、校验:检查载入的Class文件的正确性(例如如果开头不是CA FE BA BE的文件将不会再进入下一步)
2、准备:给类的静态变量分配存储空间
3、解析:将符号引用转化成直接引用
【注】JVM官方文档称,JAVA和C++最大的两个不同点就是内存管理和垃圾回收,这里的解析就是涉及java的内存管理,java中没有涉及到指针,只有在解析的时候符号引用才会转化成指针,当然,直接引用也可能不是指针而是句柄

其中装载工作由ClassLoader及其子类负责。ClassLoader其实采用的是一种"全盘负责双亲委托机制"。

2)、什么是全盘负责呢?

让我们回顾动态代理传入给代理类的ClassLoader中,是被代理类的ClassLoader,如果不懂"全盘负责"机制的小伙伴或许会有疑问:"代理类的类加载器为什么要和被代理类的加载器用同一个呢?"这完全基于JVM中的一个协议除非显示地使用另一个ClassLoader,该类所依赖及引用的类也由这个ClassLoader载入

                       思考:为什么要全盘负责呢?

JVM中主要有三个类加载器,都是jdk.internal.loader.ClassLoaders的内部类,分别是根装载器(用C++写的,所以在不是Object对象,输出为null)、拓展类装载器、应用类装载器。它们都有自己特定的装载范围,根装载器装载JRE的核心类库,拓展类加载器装载JRE拓展目录ext中的JAR类包,应用类装载器装载ClassPath路径下的类包。所以,不同装载器其实有自己不同的覆盖范围,一个类通常与引用或者说依赖对象是同一领域(同一包中),所以出于层次感的考虑会优先使用同一类加载器,当然,也不是一定的,例如在ClassPath下的类依赖一个String类,它当然还是不会被根装载器所装载。

3)、什么是双亲委托呢?

在这里插入图片描述
如图所示,java中目前的装载器就这四种类型,它们是如何加载类的呢?简单地阐述一下实现思路.
步骤①:首先从最底层的自定义装载器开始,然后通过判断该装载器是否有Parent一直找到根加载器.
步骤②在递归回来的时候才会进行类加载,它是通过两步来进行类加载的:1、判断Cache中是否已经有了该类2、判断是否能加载该类。

这里着重要强调一下在缓存中判断是否已经加载的意义:
1)用空间换取时间,已经加载了的类不需要重复加载
2)安全,这个动作最重要的原因就是保障JAVA的安全性。

为了体现缓存区在整个JAVA体系中安全性的地位,我举一个非常经典的例子。
【试想】如果有人编写了一个基础类java.lang.String,然后在装载的时候如果没有判断是否存在,那么就会直接覆盖基类的java.lang.String,那么不仅功效可能有所影响,更严重的是安全性的可靠度就完全取决于作这个程序的JAVA工程师的可靠度了。

二、Class对象

1、基本介绍

我们都知道每一个类都对应一个.class文件,那么,我们是否可以直接操作.class文件进行一系列的编程呢?JAVA的反射机制保障了这样的情况是存在的,主要是出于灵活性的考虑。具体过程是怎么样的呢?请看下图:
(以Book类为例)
在这里插入图片描述
如上图所示,每一个类在加载并初始化后都会有一个Class<?>对象,这个对象实际上是?类的结构信息的描述对象,如上图的Class对象中,就应有Book类的结构信息的描述,包括构造函数、方法、和属性等。此外,除了类有Class<?>对象,数组、枚举、注解以及基本数据类型甚至连void都拥有特定的Class<?>。

2、Class中获取信息

1、主要的类

所需要的主要的类都在java.reflect包中,主要有Constructor、Method、Field。

2、代码示例

1)示例一
e com.chapter4.ioc.summary1.reflect42.instance421;

public class Car {
private String brand;
private String color;
protected int maxSpeed;
private String version;

//默认构造函数
public Car() {}
//带参构造函数
public Car(String brand,String color,int maxSpeed) {
	this.brand=brand;
	this.color=color;
	this.maxSpeed=maxSpeed;
}
//Duplicate method Car(String, String, int) in type Car
/*public Car(String version,String color,int maxSpeed) {
	this.version=version;
	this.color=color;
	this.maxSpeed=maxSpeed;
}*/
//未带参的方法
public void introduce() {
	System.out.println("brand:"+brand+";color:"+color+";maxSpeed:"+maxSpeed);
}
//set和get方法
public String getBrand() {
	return brand;
}
public void setBrand(String brand) {
	this.brand = brand;
}
public String getColor() {
	return color;
}
public void setColor(String color) {
	this.color = color;
}
public int getMaxSpeed() {
	return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
	this.maxSpeed = maxSpeed;
}

}
package com.chapter4.ioc.summary1.reflect42.instance421;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/*
 * 反射机制可以以一种间接的方式操纵目标类
 */
public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
	Car car=initByDefaultConst();
	Car car1=initByDefaultConst1();
	car.introduce();
	car1.introduce();
	//实例化对象拥有指向类描述对象的引用,类描述对象又拥有指向ClassLoader的引用
	System.out.println(car.getClass().getClassLoader());
	//每一个类在JVM中都拥有一个对应的java.lang.Class对象,它提供了类结构信息的描述。数组、枚举、注解以及基本的java类型甚至void都有对应的Class对象
	System.out.println(void.class.getClassLoader());//void的class文件被根加载器加载
	System.out.println(void.class.getClass());//输出为java.lang.Class 证明类描述对象所在包的位置在java.lang.class
	
}

private static Car initByDefaultConst1() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
	// TODO Auto-generated method stub
	//1、利用classLoader得到字节码
	ClassLoader loader=Thread.currentThread().getContextClassLoader();
	Class<?> clazz=loader.loadClass("com.chapter4.ioc.summary1.reflect42.instance421.Car");
	//2、得到Constructor对象
	Constructor<?> con=clazz.getConstructor(String.class,String.class,int.class);
	return (Car) con.newInstance("红旗","黑色",30);

}

private static Car initByDefaultConst() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
	// TODO Auto-generated method stub
	//1、利用ClassLoader将car漏到内存,得到Clazz
	ClassLoader loader=Thread.currentThread().getContextClassLoader();
	Class<?> clazz=loader.loadClass("com.chapter4.ioc.summary1.reflect42.instance421.Car");
	//2、得到构造对象,然后newInstance创建新对象
	Constructor<?> con=clazz.getConstructor((Class[])null);
	Car car=(Car) con.newInstance();
	//3、得到属性方法,然后设置相应属性
	Method setBrand=clazz.getMethod("setBrand", String.class);
	setBrand.invoke(car, "红旗CA72");
	Method setColor=clazz.getMethod("setColor", String.class);
	setColor.invoke(car, "黑色");
	//注意:int.class和Integer.class字节码是不一样的!
	Method setMaxSpeed=clazz.getMethod("setMaxSpeed", int.class);
	setMaxSpeed.invoke(car, 20);
	return car;
}
}
2)示例2
package com.chapter4.ioc.summary1.reflect42.instance421;

public class PrivateCar {
	//私有成员变量,使用传统的类调用方式,其实是只能在本类中访问的
String color;
public void introduce() {
	System.out.println("The color of car is:"+color);
}
}
package com.chapter4.ioc.summary1.reflect42.instance421;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class PrivateCarReflectTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
	PrivateCar car=initPrivateCar();
	car.introduce();
}

private static PrivateCar initPrivateCar() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
	// TODO Auto-generated method stub
	//通过类加载器加载该类
	ClassLoader loader=Thread.currentThread().getContextClassLoader();
	Class<?> clazz=loader.loadClass("com.chapter4.ioc.summary1.reflect42.instance421.PrivateCar");
	//可以通过Class<?>文件实例化PrivateCar对象,也可以直接clazz.newinstance()
	Constructor<?> con=clazz.getConstructor();
	PrivateCar car=(PrivateCar) con.newInstance();
	//得到属性,注意getField()只能获取public的属性
	Field color=clazz.getDeclaredField("color");
	color.setAccessible(true);
	color.set(car, "蓝色");
	return car;
}
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值