您的位置:

以Java执行Class为中心

一、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!");
    }
}