一、Java执行Class的概述
Java是一种面向对象的编程语言,它的核心思想之一就是通过Class来实现面向对象的编程。在Java中,每个类都是由一个或多个Class组成的,Class代表了一个Java类或者接口的元信息。Java程序在执行时需要加载和连接Class,然后才能够对其进行实例化和调用操作。因此,在Java中,以Java执行Class为中心是非常重要的。
二、Java执行Class的分类
Java执行Class可以分为以下三种类型:
1.系统类
系统类是由Java虚拟机(JVM)提供的类,例如java.lang.Object、java.lang.String等。这些类通常位于JVM的class路径下,可以被整个JVM使用。
public class SystemClass { public static void main(String[] args) { Object obj = new Object(); String str = new String("Java"); System.out.println(obj.getClass()); System.out.println(str.getClass()); } }
2.应用类
应用类是用户自定义的类,它们通常被应用程序开发者编写并打包成jar文件,然后在应用程序中进行使用。应用类可以通过Java的类加载机制进行加载。
public class ApplicationClass { public static void main(String[] args) { MyClass myClass = new MyClass(); System.out.println(myClass.getClass()); } } class MyClass { // some code... }
3.扩展类
扩展类是由JVM扩展提供的类,例如javax.swing.JFrame、javax.swing.JButton等。这些类通常位于JRE的扩展目录下,可以被整个JVM使用。扩展类也可以通过Java的类加载机制进行加载。
public class ExtensionClass { public static void main(String[] args) { JFrame frame = new JFrame(); JButton button = new JButton("Click me"); frame.add(button); frame.setSize(300, 200); frame.setVisible(true); System.out.println(frame.getClass()); System.out.println(button.getClass()); } }
三、Java执行Class的加载
Java程序在执行时,需要从磁盘、网络等地方获取Class字节码并将其加载到内存中,然后才能够对其进行实例化和调用操作。Java使用类加载器来完成Class的加载任务。类加载器可以分为以下三种:
1.引导类加载器
引导类加载器是虚拟机自身的一部分,它负责加载JVM需要的基础类,如java.lang.Object、java.lang.String等。这些类在整个Java应用程序中都是可以被访问的。
2.扩展类加载器
扩展类加载器负责加载JRE扩展目录下的Class,例如javax.swing.JFrame等。这些类在整个Java应用程序中都是可以被访问的。
3.应用程序类加载器
应用程序类加载器负责加载应用程序的Class,例如用户自定义的Class。这些类只在应用程序内部被访问。
public class ClassLoaderDemo { public static void main(String[] args) { // 获取当前线程的类加载器 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // 加载org.springframework.jdbc.core.JdbcTemplate类 try { Class clazz = classLoader.loadClass("org.springframework.jdbc.core.JdbcTemplate"); System.out.println(clazz); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
四、Java执行Class的链接
Java程序在加载完Class之后,需要进行链接操作,包括验证、准备和解析三个步骤。
1.验证
验证步骤用来确保所加载的Class是符合Java规范的,包括格式检查、语义检查、字节码检查等。
2.准备
准备步骤用来分配所加载的Class所需的空间,并设置默认值。例如,对于一个int型的成员变量,它将会被分配4个字节的空间,并设置为0。
3.解析
解析步骤用来将被加载的Class中的符号引用解析为实际引用,并进行相关的链接处理,如常量池解析、类或接口的解析等。
public class LinkageDemo { public static void main(String[] args) { LinkageDemo demo = new LinkageDemo(); demo.sayHello(); } public void sayHello() { System.out.println("Hello, World!"); } }
五、Java执行Class的初始化
Java程序在链接完Class之后,还需要进行初始化操作,包括静态变量赋值、静态代码块调用等。Java采用了Lazyloading的思想,即在第一次使用该Class时才会进行初始化。
public class InitializationDemo { static { System.out.println("InitializationDemo被初始化了"); } public static void main(String[] args) { // 输出InitializationDemo被初始化了 System.out.println("Hello, World!"); } }
六、Java执行Class的卸载
Java程序在执行时,如果某一个Class已经不再使用,那么它将会被JVM的垃圾回收器回收。当一个Class被回收之后,可以对其进行重新加载和执行操作。
public class UnloadingDemo { public static void main(String[] args) throws ClassNotFoundException { // 创建一个自定义类加载器 MyClassLoader loader = new MyClassLoader(); // 加载并执行HelloWorld类 Class clazz = loader.loadClass("HelloWorld"); try { clazz.getMethod("sayHello").invoke(clazz.newInstance()); } catch (Exception e) { e.printStackTrace(); } // 卸载HelloWorld类 ((MyClassLoader) clazz.getClassLoader()).unloadClass("HelloWorld"); } } class MyClassLoader extends ClassLoader { private Map> classes = new HashMap<>(); @Override protected Class findClass(String name) throws ClassNotFoundException { byte[] classBytes = getClassBytes(name); Class clazz = defineClass(name, classBytes, 0, classBytes.length); classes.put(name, clazz); return clazz; } private byte[] getClassBytes(String name) throws ClassNotFoundException { try { InputStream is = ClassLoader.getSystemResourceAsStream(name.replace(".", "/") + ".class"); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buff = new byte[2048]; int len = 0; while ((len = is.read(buff)) != -1) { outputStream.write(buff, 0, len); } return outputStream.toByteArray(); } catch (Exception e) { throw new ClassNotFoundException(name); } } public void unloadClass(String name) { classes.remove(name); } } class HelloWorld { public void sayHello() { System.out.println("Hello, World!"); } }