Java类的生命周期
生命周期有:加载(Loading)--》验证(Verification)--》准备(Preparation)---》解析(Resolution)--》初始化(Initiation)---》使用(Using)----》卸载(Unloading)。
其中标黄的验证---》准备---》解析被称为连接(Linking)。
就代码执行而言:
1.连接阶段:不执行程序员代码
2.加载阶段:可以重写ClassLoader来执行我们的代码
3.连接后阶段:执行该类的代码
ClassLoader:
ClassLoader是为了将class文件的byte数组,主要的方法是findClass用于查找类。
Java7有个迅速将File编程byte[]的方法:
byte[] cLassBytes = null; Path path; try { path = Paths.get(new URI("file:///D:/MyScript/TestClassLoader.class")); cLassBytes = Files.readAllBytes(path);
每个ClassLoader对象都有一个ClassLoader类型的字段,暂且成为parent。当调用本类的loadClass方法加载类时,会先调用parent的ClassLoader,如果他没找到,才会调用本类的findClass方法去查找类。(这样,应用的Launcher$AppClassLoader也可以通过BootStrapClassLoader来调用String类了)。
查找类的顺序,与对应的ClassLoader
系统查找类的顺序是:
1).Bootstrap classes: the runtime classes in rt.jar,
internationalization classes in i18n.jar, and others.
2).Installed extensions: classes in JAR files in the lib/ext directory
of the JRE, and in the system-wide, platform-specific extension directory (such as /usr/jdk/packages/lib/ext on
the Solaris? Operating System, but note that use of this directory applies only to Java? 6 and later).
3).The class path: classes, including classes in JAR
files, on paths specified by the system property java.class.path. If a JAR file on the class
path has a manifest with the Class-Path
attribute,
JAR files specified by the Class-Path
attribute
will be searched also. By default, thejava.class.path
property‘s
value is .
, the current directory. You can
change the value by using the -classpath or -cp command-line
options, or setting the CLASSPATH
environment
variable. The command-line options override the setting of the CLASSPATH
environment
variable.
中文就是:
1)rt.jar等(这个jar是什么呢?你用java -verbose 类名 运行下就看到了:Loaded java.io.File from C:\Program Files\Java\jre1.8.0_31\lib\rt.jar,也就是经常调用的String、Long等类,属于SDK中的)(用BootStrapClassLoader加载)
2) SDK中的拓展类,包名为javax的(java和javax都是Java的API(Application
Programming Interface)包,java是核心包,javax的x是extension的意思);
(用Launcher$ExtClassLoader加载)
3) 系统环境变量CLASSPATH的路径,当前目录(或者用命令行带 -classpath重新)
(用Launcher$AppClassLoader加载)
可是我的类文件在D:\MyScript\TestClassLoader.class不在上述三种。
2:解决方案
1.场景:我想加载一个d盘上的类,路径是:D:\MyScript\TestClassLoader.class,其不在上述三种情况。
通过重写一个ClassLoader进行加载,不过有现成的URLClassLoader我们就不要重造轮子了。
自定义ClassLoader代码
public class MyClassLoader extends ClassLoader{ @Override protected Class<?> findClass(String className) throws ClassNotFoundException { byte[] cLassBytes = null; //Java 7有下列API
<span style="white-space:pre"> </span>Path path; try { path = Paths.get(new URI("file:///D:/MyScript/TestClassLoader.class")); cLassBytes = Files.readAllBytes(path); } catch (IOException | URISyntaxException e) { e.printStackTrace(); } Class cLass = defineClass(cLassBytes, 0, cLassBytes.length); return cLass; } }
使用的时候:
Class.forName("TestClassLoader", true, new MyClassLoader());
用URLClassLoader来简化
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); // This URL for a directory will be searched *recursively* URL classes; try { classes = new URL( "file:///D:/MyScript/" ); ClassLoader custom = new URLClassLoader( new URL[] { classes }, systemClassLoader ); // this class should be loaded from your directory Class< ? > clazz = custom.loadClass( "TestClassLoader" ); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { System.out.println(method.getName()); }
URLClassLoader用的URL只能接受目录和jar包:
结尾: /代表该目录下的来; 非/而是文件则默认为jar包。
贴一个jar包的代码:
public URL findResource(String name) { try { File file = new File(jarFile); String url = file.toURL().toString(); return new URL("jar:"+url+"!/"+name); } catch (Exception e) { return null; } }<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);"> </span>
另外我用反射来验证类是否加载成功了,clazz.newInstance()也可以生成相关代码。