1. 类的加载、连接和初始化
1.1 JVM和类
- 当调用java程序时,会启动一个JVM进程
JVM中止的情形:
- 程序运行到最后正常结束
-
System.exit()
或Runtime.getRuntime().exit()
代码处结束程序 - 出现未捕获的异常或错误
- 平台强制结束了程序
1.2 类的加载
类加载过程:加载 -> 连接 -> 初始化
加载:将类的class文件读入内存,并创建一个java.lang.Class
对象;这个过程由JVM的类加载器完成,除此之外,开发者可以通过继承ClassLoader
来创建类加载器
连接:负责把类的二进制数据合并到JRE中,分为三个阶段
1)验证:检验被加载的类是否有正确的内部结构,并和其他类协调一致
2)准备:负责为类的类变量分配内存,并设置默认初始值
3)解析:将类的二进制数据中的符号引用替换成直接引用
Java 符号引用 与 直接引用
初始化:
1)假如这个类还没有被加载和连接,则程序先加载并连接该类
2)假如该类的直接父类没有被初始化,则先初始化其直接父类
3)假如类中有初始化语句,则系统依次执行这些初始化语句
类初始化的时机:
- 创建该类的实例
- 调用某个类的类方法
- 访问某个类或接口的类变量,或为该变量赋值
- 使用反射方式强制创建某个类或接口对应的
java.lang.Class
对象 - 初始化某个类的子类
- 直接使用
java.exc
命令运行某个主类.当运行某个主类时,程序会先初始化该主类 -
final
类型的变量如果在编译期间可以确定下来,系统在编译时会将它出现的地方替换成它的值,因此不会导致该类的初始化
class Test {
static {
System.out.println("Test的静态初始化块");
}
}
public class Tester {
public static void main(String[] args) {
ClassLoader loader = ClassLoader.getSystemClassLoader();
try {
loader.loadClass("Test");
System.out.println("系统加载Test类");
Class.forName("Test");
System.out.println("系统初始化Test类");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
![](https://img.haomeiwen.com/i14092234/4e5b9ef9d42d0f7e.png)
可以看到,通过loader.loadClass("Test)
,类需要先加载,再进行初始化
2. 类加载器
- 类加载器负责将
.class
文件加载到内存中,并为之生成对应的java.lang.Class
对象 - 载入JVM的类有一个唯一的标识 --- 全限定类名和类加载器
- 类加载器层次结构有3层:
Bootstrap ClassLoader
根类加载器,负责加载Java的核心类,Extension ClassLoader
,System ClassLoader
- JVM除了根类加载器以外都是ClassLoader的子类
- JVM的加载机制:
1)全盘负责:当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类负责
2)父类委托:先让父类加载,父类加载不了由自己加载
3)缓存机制:当程序中需要使用某个Class时,累计扎起先从缓存区搜寻该Class
![](https://img.haomeiwen.com/i14092234/435599425cc743fe.png)
2.1 创建自定义的类加载器
![](https://img.haomeiwen.com/i14092234/5bb937a6dcbd8702.png)
public class ClassLoaderPropTest extends ClassLoader {
private byte[] getBytes(String fileName) throws IOException {
File file = new File(fileName);
long len = file.length();
byte[] raw = new byte[(int) len];
FileInputStream fin = new FileInputStream(file);
int r = fin.read(raw);
if(r!=len){
System.out.println("无法读取全部文件");
throw new IOException("无法读取全部文件");
}
return raw;
}
private boolean compile(String javaFile) throws IOException {
System.out.println("正在编译..." + javaFile);
Process p = Runtime.getRuntime().exec("javac" + javaFile);
try{
p.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
int ret = p.exitValue();
return ret == 0;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class clazz = null;
String fileStub = name.replace(".", "/");
String javaFileName = fileStub + ".java";
String classFileName = fileStub + ".class";
File javaFile = new File(javaFileName);
File classFile = new File(classFileName);
if((javaFile.exists() && !classFile.exists()) || (javaFile.lastModified() > classFile.lastModified())){
try {
if(!compile(javaFileName) || !classFile.exists()) {
throw new ClassNotFoundException("Class Not Found: " + javaFileName);
}
if(classFile.exists()) {
try {
byte[] raw = getBytes(classFileName);
clazz = defineClass(name, raw, 0, raw.length);
} catch (IOException e) {
e.printStackTrace();
}
}
if(clazz == null) {
throw new ClassNotFoundException("没有编译完成:" + name);
}
} catch (IOException e) {
e.printStackTrace();
}
}
return clazz;
}
public static void main(String[] args) throws Exception {
String progClass = args[0];
System.out.println(progClass);
String[] progArgs = new String[args.length - 1];
System.arraycopy(args, 1, progArgs, 0, progArgs.length);
ClassLoaderPropTest classLoader = new ClassLoaderPropTest();
Class<?> clazz = classLoader.loadClass(progClass);
Method main = clazz.getMethod("main", (new String[0]).getClass());
Object arqsArray[] = {progArgs} ;
main.invoke (null ,arqsArray) ;
}
}
2.2 URlClassLoader
- 是系统类加载器和扩展类加载器的父类
- 既可以从本地获取二进制文件,也可以从远端获取
-
URLClassLoader(URL[] urls)
: 使用默认的父类加载器创建一个ClassLoader
对象,该对象将从urls
所指定的系列路径来查询并加载类。 -
URLClassLoader(URL[] urls, ClassLoader parent)
: 使用指定的父类加载器创建一个ClassLoader
对象,其他功能与前一个构造器相同。
3. 通过反射查看类信息
- 适用场景:编译时无法预知该类和对象可能属于哪些类,程序只能依靠运行时的消息来发现该类的真实信息
- 获得
Class
对象的方式:
方法名 | 作用 |
---|---|
forName(String clazzName) |
静态方法 |
class |
例如:Person.class ,代码更安全,性能更好 |
getClass() |
Object方法 |
- 获取class对应类所办含的构造器
方法名 | 作用 |
---|---|
Connstructor<T> getConstructor(Class<?>.. . parameterTypes) |
返回此Class 对象对应类的、带指定形参列表的public 构造器 |
Constructor<?>[] getConstructors() |
返回此Class 对象对应类的所有public 构造器 |
Constructor<T> getDeclaredConstructor(Class<?>.. . parameterTypes) |
返回此Class 对象对应类的、带指定形参列表的构造器,与构造器的访问权限无关 |
Constructor<?>[] getD eclaredConstructor() |
返回此Class 对象对应类的所有构造器,与构造器的访问权限无关 |
- 获取Class对应类所包含的方法
方法名 | 作用 |
---|---|
Method getMethod(String name, Class<?>... parameterTypes) |
返回此Class 对象对应类的、带指定形参列表的public 方法 |
Method getMethods() |
返回此Class 对象所表示的类的所有public 方法 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) |
返回此Class 对象对应类的、带指定形参列表的方法,与方法的访问权限无关。 |
Method[] getDeclaredMethod() |
返回此Class 对象对应类的全部方法, 与方法的访问权限无关 |
- 获取Class对应类所包含的成员变量
- 获取Class对应类所包含的Annotation
- 获取Class对应类所包含的内部类
![](https://img.haomeiwen.com/i14092234/5110560bfd2eeaf9.png)
public class reflectionTest {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class orangeClass = Orange.class;
Method method = orangeClass.getMethod("info");
Orange or1 = new Orange(1);
method.invoke(or1);
}
}
![](https://img.haomeiwen.com/i14092234/1c08d356ae666607.png)
- javac编译时没有形参名信息,因此如果需要调用
isNamePresent
和getName
的话,需要在编译时使用javac -parameters
4. 通过反射生成并查看对象
4.1 创建对象
public class ObjectPoolFactory {
private Map<String, Object> objectPool = new HashMap<>();
private Object createObject(String clazzName) throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> clazz = Class.forName(clazzName);
return clazz.getConstructor().newInstance();
}
public void initPool(String fileName) {
try {
FileInputStream fis = new FileInputStream(fileName);
Properties properties = new Properties();
properties.load(fis);
for(String name: properties.stringPropertyNames()) {
objectPool.put(name, createObject(properties.getProperty(name)));
}
} catch (IOException | NoSuchMethodException | ClassNotFoundException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
e.printStackTrace();
}
}
public Object getObject(String name) {
return objectPool.get(name);
}
public static void main(String[] args) {
ObjectPoolFactory oPF = new ObjectPoolFactory();
oPF.initPool("obj.txt");
System.out.println(oPF.getObject("a"));
System.out.println(oPF.getObject("b"));
}
}
![](https://img.haomeiwen.com/i14092234/3d4ffe81650c2181.png)
4.2 调用方法
4.3 访问字段
![](https://img.haomeiwen.com/i14092234/b56d6fb29e937603.png)
4.4 操作数组
![](https://img.haomeiwen.com/i14092234/899b777ec6db1442.png)
5. 使用反射生成JDK动态代理
5.1 使用Proxy和InvocationHandler
方法名 | 作用 |
---|---|
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) |
创建一个动态代理类所对应的Class 对象, 该代理类将实现interfaces 所指定的多个接口。第一个ClassLoader 参数指定生成动态代理类的类加载器 |
static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h) |
直接创建一个动态代理对象, 该代理对象的实现类实现了interfaces 指定的系列接口,执行代理对象的每个方法时都会被替换执行InvocationHandler 对象的invoke 方法。 |
![](https://img.haomeiwen.com/i14092234/ea48e92f30944613.png)
5.2 动态代理和AOP
public class DogUtil {
public void mehod1() {
System.out.println("---正在执行第一个方法---");
}
public void mehod2() {
System.out.println("---正在执行第二个方法---");
}
}
public class MyInvocationHandler implements InvocationHandler {
Object proxyObject;
public void setProxyObject(Object proxyObject) {
this.proxyObject = proxyObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
DogUtil dogUtil = new DogUtil();
dogUtil.mehod1();
dogUtil.mehod2();
Object ret = method.invoke(proxyObject, args);
return ret;
}
}
public class InvocationHandlerFactory {
public static Object getProxy(Object target) {
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
myInvocationHandler.setProxyObject(target);
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),myInvocationHandler);
}
}
public class TestProxt {
public static void main(String[] args) {
DogParent dog = new Dog();
DogParent dogProxy = (DogParent) InvocationHandlerFactory.getProxy(dog);
dogProxy.info();
}
}
![](https://img.haomeiwen.com/i14092234/400dbae97d9c1079.png)
![](https://img.haomeiwen.com/i14092234/27cee4385ae5610c.png)
网友评论