>  기사  >  Java  >  ClassLoader를 작성하는 이유는 무엇입니까? Java의 클래스로더에 대한 깊은 이해

ClassLoader를 작성하는 이유는 무엇입니까? Java의 클래스로더에 대한 깊은 이해

php是最好的语言
php是最好的语言원래의
2018-07-27 09:36:402141검색

클래스로더란 무엇인가요? 모든 프로그래밍 언어 중에서 Java는 Java Virtual Machine에서 실행된다는 점에서 독특합니다. 이는 컴파일된 프로그램이 대상 시스템의 형식이 아닌 고유하고 플랫폼 독립적인 형식으로 대상 시스템에서 실행된다는 것을 의미합니다. 이 형식은 여러 측면에서 기존 실행 프로그램과 매우 다릅니다.

Preface

Java ClassLoader는 Java 운영 체제에서 중요하지만 종종 무시되는 구성 요소입니다. 런타임 시 클래스 파일을 찾고 로드하는 일을 담당합니다. 사용자 정의 ClassLoader를 생성하면 클래스 파일이 시스템에 로드되는 방식을 완전히 재정의할 수 있습니다.

이 튜토리얼은 Java ClassLoader의 일반적인 개요를 제공하고 사용자 정의 ClassLoader의 예를 제공합니다. 이 ClassLoader는 코드를 로드하기 전에 자동으로 컴파일됩니다. ClassLoader가 수행하는 작업과 사용자 정의 ClassLoader를 생성하는 방법을 배우게 됩니다.

이 튜토리얼을 사용하려면 독자가 간단한 명령줄 Java 프로그램 생성, 컴파일, 실행을 포함하여 Java 프로그래밍에 대한 기본적인 이해가 필요합니다.

이 튜토리얼을 읽고 나면 다음 방법을 알게 됩니다.

  • JVM 기능 확장

  • #🎜 🎜 #
  • 사용자 정의 ClassLoader 만들기

  • ClassLoader를 Java 애플리케이션에 통합하는 방법 알아보기

  • #🎜🎜 # Java2 버전에 맞게 ClassLoader를 수정하세요
  • ClassLoader란 무엇인가요

모든 프로그래밍 언어 중에서 Java는 Java Virtual Machine에서 실행되며 고유합니다. 이는 컴파일된 프로그램이 대상 시스템의 형식이 아닌 고유하고 플랫폼 독립적인 형식으로 대상 시스템에서 실행된다는 것을 의미합니다. 이 형식은 여러 측면에서 기존 실행 프로그램과 매우 다릅니다.

Java 프로그램과 C 또는 C++ 프로그램의 가장 큰 차이점은 단일 실행 파일이 아니라 여러 개의 개별 클래스 파일로 구성되며 각 클래스 파일은 Java 클래스에 해당한다는 것입니다.

그뿐만 아니라 이러한 클래스 파일은 한꺼번에 메모리에 로드되는 것이 아니라 요청 시 로드됩니다. ClassLoader는 클래스를 메모리에 로드하는 JVM의 일부입니다.

또한 Java ClassLoader는 Java로 작성되었습니다. 이는 JVM에 대한 자세한 내용을 알지 못해도 자신만의 ClassLoader를 쉽게 만들 수 있음을 의미합니다.

ClassLoader를 작성하는 이유

JVM에 이미 ClassLoader가 있는 경우 다른 ClassLoader를 작성해야 하는 이유는 무엇입니까? 좋은 질문입니다. 기본 ClassLoader는 로컬 파일 시스템에서 클래스 파일을 로드하는 방법만 알고 있습니다. 일반적인 시나리오에서는 로컬에서 코드를 작성하고 로컬로 컴파일하면 충분합니다.

그러나 JAVA 언어의 가장 새로운 기능 중 하나는 로컬 하드 드라이브나 인터넷 외부에서 수업을 얻을 수 있다는 것입니다. 예를 들어, 브라우저는 사용자 정의 ClassLoader를 사용하여 웹 사이트에서 실행 가능한 컨텐츠를 얻습니다.

클래스 파일을 얻는 다른 방법도 많이 있습니다. 클래스 파일을 로컬 또는 온라인으로 로드하는 것 외에도 클래스 로더를 사용하여 다음을 수행할 수도 있습니다.

    신뢰할 수 없는 코드를 실행하기 전에 디지털 서명을 자동으로 확인
  • #🎜🎜 #

    사용자가 제공한 비밀번호를 사용한 투명한 복호화 코드
  • 사용자의 특정 요구 사항에 따라 맞춤 동적 클래스 만들기#🎜 🎜##🎜🎜 #
  • Java 바이트코드를 생성하는 모든 것이 애플리케이션에 통합될 수 있습니다.

    사용자 정의 클래스 로더의 예
애플릿을 사용해 본 적이 있다면 사용자 정의 클래스 로더를 사용해 보셨을 것입니다.

Sun이 Java 언어를 출시했을 때 가장 흥미로웠던 것 중 하나는 이 기술이 어떻게 원격 웹 서버에서 적시에 코드를 로드하는지 지켜보는 것이었습니다. 흥미로운 점은 원격 웹 서버에서 HTTP 연결을 통해 바이트코드를 전송하고 이를 로컬에서 실행한다는 것입니다.

사용자 정의 ClassLoader를 지원하는 Java 언어의 기능이 이러한 아이디어를 가능하게 합니다. 애플릿에는 사용자 정의 ClassLoader가 있습니다. 로컬 파일 시스템에서 클래스 파일을 로드하지 않고 원격 웹 서버에서 이를 가져와 Http를 통해 원본 바이트코드를 로드한 다음 이를 jvm에서 클래스로 변환합니다.

브라우저와 애플릿의 클래스 로더에는 보안 관리, 서로 다른 페이지에 있는 애플릿이 서로 영향을 미치는 것을 방지하는 등의 다른 기능도 있습니다.

아래에서는 CompilingClassLoader(CCL)라는 사용자 정의 클래스 로더를 생성하여 Java 코드를 컴파일하는 데 도움을 줍니다. 이는 기본적으로 실행 중인 시스템에 직접 간단한 make 프로그램을 구축하는 것과 같습니다.

ClassLoader 구조

ClassLoader의 기본 목적은 클래스 요청을 처리하는 것입니다. JVM에는 클래스가 필요하므로 ClassLoader에게 해당 이름으로 클래스를 로드하도록 요청합니다. ClassLoader는 클래스를 나타내는 객체를 반환하려고 시도합니다.

CompilingClassLoader(CCL)、CCL会帮我们编译Java代码。它基本上就像是在运行系统中直接构建一个简单的make程序。

ClassLoader结构

ClassLoader的基本目的是为类的请求提供服务。JVM需要一个类,于是它通过类的名字询问ClassLoader来加载这个类。ClassLoader试着返回一个代表该类的对象。

通过覆盖此过程不同阶段对应的方法,可以创建自定义的ClassLoader。

在本文的剩余部分,你会了解到ClassLoader中的一些关键方法。你会了解到每个方法的用途以及它在类加载过程中是如何调用的。你还会了解当你在自定义ClassLoader时需要完成的工作。

loadClass方法##、

ClassLoader.loadClass()方法是ClassLoader的入口。它的方法标签如下:

Class loadClass(String name, boolean resolve)

name参数代表JVM需要的类的名称,比如Foo或是java.lang.Object이 프로세스의 여러 단계에 해당하는 메서드를 재정의하여 사용자 정의 ClassLoader를 만들 수 있습니다.

#🎜🎜#이 기사의 나머지 부분에서는 ClassLoader의 몇 가지 주요 메소드에 대해 배우게 됩니다. 각 메서드의 기능과 클래스 로딩 중에 메서드가 호출되는 방식을 알아봅니다. 또한 ClassLoader를 사용자 정의할 때 수행해야 할 작업도 배우게 됩니다. #🎜🎜##🎜🎜#loadClassmethod##, #🎜🎜##🎜🎜#ClassLoader.loadClass() 메소드는 ClassLoader의 입구입니다. 메소드 태그는 다음과 같습니다: #🎜🎜#
% java Foo arg1 arg2
#🎜🎜# name 매개변수는 Foo 또는 java.lang.객체. #🎜🎜#

resolve 매개변수는 클래스를 해결해야 하는지 여부를 나타냅니다. 클래스 구문 분석은 클래스 실행을 완전히 준비하는 것으로 이해될 수 있습니다. 구문 분석은 필요하지 않습니다. JVM이 클래스의 존재 여부를 확인하거나 해당 상위 클래스만 찾으면 구문 분석할 필요가 없습니다. resolve参数说明类是否需要被解析。可以把类的解析理解为完全的准备好执行类。解析并不是必要的。如果JVM只需要确定该类存在或是找出其父类,则无需解析。

在java1.1版本以前,自定义ClassLoader只需要重写loadClass方法。

defineClass方法

defineClass方法是整个ClassLoader的核心。此方法将原始字节数组转化为一个Class对象。原始字节数组包含从本地或是远程得到的数据。

defineClass负责处理JVM的许多复杂,神秘而且依赖于具体实现的部分。它将字节码解析为运行时的数据结构,检查其有效性等。不用担心,这些你不用自己实现。事实上,你根本没法重写它,因为该方法为final方法。

findSystemClass方法

findSysetmClass方法从本地文件系统中加载文件。它在本地文件系统中查找类文件,如果存在,使用defineClass将其从原始字节转化为类对象。这是JVM在运行Java应用程序时加载类的默认机制。

对于自定义的ClassLoader,我们只会在尝试了别的方法来加载类内容之后,才调用findSystemClass方法。道理很简单:自定义的ClassLoader包含加载特殊类的一些步骤,但是并非所有的类都是特殊类。比如,即便ClassLoader需要从远程网站上获取一些类,还是有许多类需要从本地的Java库中加载。这些类并不是我们关注的重点,因此我们需要JVM用默认的方式来获取。

整个流程如下:

  • 请求自定义ClassLoader加载一个类

  • 查看远程服务器是否有该类

  • 如果有,则获取并返回

  • 如果没有,我们假设该类是位于本地的一个基础类,并调用findSystemClass从文件系统中加载出来。

在大多数自定义的ClassLoader中,你需要先滴啊用findSystemClass来减少对远程网站的访问,因为大多数Java类都位于本地的类库中。但是,在下一节中你会看到,在自动将应用代码编译之前,我们不希望JVM从本地文件系统加载类。

resolveClass方法

如前文所说,类的加载是可以部分进行(不进行解析)或是彻底进行的(进行解析)。当我们实现自己的loadClass方法时,我们或许需要调用resolveClass方法,这取决于loadClass中的resolve参数的值。

findLoadedClass方法

findLoadedClass方法充当一个缓存调用机制:当loadClass方法被调用时,他会调用这个方法来查看类是否已经被加载过了,省去了重复加载。这个方法应当最先被调用。

整合一下

我们的例子中loadClass执行以下几步(这里我们不会特别关注到底采用了什么神奇的方法来获取类文件。它可以是从本地,网络或者是压缩文件中获得的,总之我们获得了原始类文件的字节码):

  • 调用findLoadedClass查看是否已经加载过该类

  • 如果没有,则使用神奇的魔法来获得原始字节码

  • 如果获得字节码,调用defineClass将其转化为Class对象

  • 如果没有获得字节码,则调用findSystemClass,看是否能从本地文件系统获得类

  • 如果resolve值为true,则调用resolveClass来解析Class对象

  • 如果还是没有找到类,则抛出ClassNotFoundException

  • 否则,将类返回给调用者

CompilingClassLoader

CCL的作用是确保代码已经被编译,并且是最新版本的。
以下是该类的描述:

  • 当需要一个类时,查看该类是否在磁盘上,在当前的目录或是相应的子目录下

  • 如果该类不存在,但是其源码存在,在调用Java编译器来生成类文件

  • 如果类文件存在,查看他是否比源码的版本旧,如果低于源码的版本,则重新生成类文件

  • 如果编译失败,或者其他的原因导致无法从源码中生成类文件,抛出ClassNotFoundException

  • 如果还是没有类文件,那么它或许在其他的一些库中,调用findSystemClass看是否有用

  • 如果还是找不到类,抛出ClassNotFoundException

    java1.1 이전에는 사용자 정의 ClassLoader가 loadClass 메서드를 재정의하기만 하면 되었습니다.
  • defineClass 메소드

  • defineClass 메소드는 전체 ClassLoader의 핵심입니다. 이 메서드는 원본 바이트 배열을 Class 객체로 변환합니다. 원시 바이트 배열에는 로컬 또는 원격 소스에서 얻은 데이터가 포함됩니다.

    defineClass는 JVM의 복잡하고 신비하며 구현에 의존적인 여러 부분을 처리하는 역할을 담당합니다. 바이트코드를 런타임 데이터 구조로 구문 분석하고 유효성을 검사합니다. 걱정하지 마세요. 직접 구현할 필요는 없습니다. 실제로 메서드가 최종 메서드이기 때문에 전혀 재정의할 수 없습니다. 🎜

    findSystemClass 메서드

    🎜findSysetmClass 메서드는 로컬 파일 시스템에서 파일을 로드합니다. 로컬 파일 시스템에서 클래스 파일을 찾고, 있는 경우 defineClass를 사용하여 원시 바이트에서 클래스 객체로 변환합니다. 이는 Java 애플리케이션을 실행할 때 클래스를 로드하기 위한 JVM의 기본 메커니즘입니다. 🎜🎜사용자 정의 ClassLoader의 경우 클래스 콘텐츠를 로드하기 위해 다른 메서드를 시도한 후에만 findSystemClass 메서드를 호출합니다. 이유는 간단합니다. 사용자 정의 ClassLoader에는 특수 클래스를 로드하기 위한 몇 가지 단계가 포함되어 있지만 모든 클래스가 특수 클래스는 아닙니다. 예를 들어 ClassLoader가 원격 웹사이트에서 일부 클래스를 가져와야 하는 경우에도 로컬 Java 라이브러리에서 로드해야 하는 클래스가 여전히 많이 있습니다. 이러한 클래스는 우리의 초점이 아니므로 기본 방식으로 클래스를 얻으려면 JVM이 필요합니다. 🎜🎜전체 프로세스는 다음과 같습니다. 🎜
      🎜🎜클래스를 로드하도록 사용자 정의 ClassLoader를 요청합니다.🎜🎜🎜🎜원격 서버에 해당 클래스가 있는지 확인하세요🎜🎜🎜🎜그렇다면 , get 및 return 🎜🎜🎜🎜그렇지 않은 경우 클래스가 로컬 기본 클래스라고 가정하고 findSystemClass를 호출하여 파일 시스템에서 로드합니다. 🎜🎜
    🎜대부분의 사용자 정의 ClassLoader에서는 대부분의 Java 클래스가 로컬 클래스 라이브러리에 있기 때문에 원격 웹 사이트에 대한 액세스를 줄이려면 먼저 findSystemClass를 사용해야 합니다. 그러나 다음 섹션에서 볼 수 있듯이 애플리케이션 코드를 자동으로 컴파일하기 전에 JVM이 로컬 파일 시스템에서 클래스를 로드하는 것을 원하지 않습니다. 🎜

    resolveClass 메서드

    🎜앞서 언급했듯이 클래스 로딩은 부분적으로(파싱 없이) 또는 완전히(파싱 포함) 수행될 수 있습니다. 자체 loadClass 메서드를 구현할 때 loadClassresolve에 따라 resolveClass 메서드를 호출해야 할 수도 있습니다. > >매개변수의 값입니다. 🎜

    findLoadedClass 메서드

    🎜findLoadedClass 메서드는 캐시 호출 메커니즘으로 작동합니다. loadClass 메서드가 호출되면 call 이 메소드는 클래스가 로드되었는지 확인하는 데 사용되므로 반복적인 로드가 필요하지 않습니다. 이 메서드를 먼저 호출해야 합니다. 🎜

    통합

    🎜이 예에서 loadClass는 다음 단계를 수행합니다(여기서는 클래스 파일을 얻기 위해 어떤 마법의 방법이 사용되는지 특별히 주의하지 않습니다. 로컬에서, 네트워크 또는 압축 파일에서 얻었습니다. 즉, 원래 클래스 파일의 바이트코드를 얻었습니다.): 🎜
      🎜🎜Call findLoadedClass 클래스가 이미 로드되었는지 확인하세요🎜🎜🎜🎜그렇지 않다면 마법을 사용하여 원래 바이트코드를 얻으세요🎜🎜🎜🎜바이트코드를 얻으면 defineClass를 호출하여 Class로 변환하세요 객체 🎜🎜🎜🎜바이트코드를 얻지 못한 경우 findSystemClass를 호출하여 로컬 파일 시스템에서 클래스를 얻을 수 있는지 확인하세요. 🎜🎜🎜🎜해결되는 경우 code> 값이 true인 경우 resolveClass를 호출하여 Class 객체🎜🎜🎜🎜클래스를 여전히 찾을 수 없으면 ClassNotFoundException🎜을 발생시킵니다. 🎜🎜🎜그렇지 않으면 클래스를 호출자에게 반환합니다🎜🎜

    CompilingClassLoader

    🎜CCL는 코드가 제대로 작성되었는지 확인하는 데 사용됩니다. 컴파일되어 최신 버전입니다.
    다음은 이 클래스에 대한 설명입니다. 🎜
      🎜🎜클래스가 필요할 때 클래스가 디스크에 있는지, 현재 디렉토리에 있는지 또는 해당 하위 디렉토리에 있는지 확인하세요. 다음🎜🎜🎜🎜클래스는 없지만 해당 소스 코드가 있는 경우 Java 컴파일러를 호출하여 클래스 파일을 생성합니다.🎜🎜🎜🎜클래스 파일이 존재하는 경우 소스 코드 버전보다 오래된지 확인하세요. 소스 코드 버전보다 낮은 경우 클래스 파일을 다시 생성합니다🎜🎜🎜🎜컴파일이 실패하거나 다른 이유로 소스 코드에서 클래스 파일이 생성되지 않는 경우 ClassNotFoundException🎜🎜🎜🎜을 발생시킵니다. 여전히 클래스 파일이 없으면 다른 라이브러리에 있을 수 있습니다. findSystemClass를 호출하여 유용한지 확인하세요.🎜🎜🎜🎜클래스를 여전히 찾을 수 없으면 ClassNotFoundException을 발생시킵니다. 🎜🎜🎜🎜그렇지 않으면 수업을 반환하세요🎜

Java是如何编译的

在深入研究之前,我们应该回过头来看一下Java的编译机制。总的来说,当你请求一个类的时候,Java不只是编译各种类信息,它还编译了别的相关联的类。

CCL会按需一个接一个的编译相关的类。但是,当CCL编译完一个类之后试着去编译其它相关类的时候会发现,其它的类已经编译完成了。为什么呢?Java编译器遵循一个规则:如果一个类不存在,或者它相对于源码已经过时了,就需要编译它。从本质上讲,Java编译器先CCL一步完成了大部分的工作。

CCL在编译类的时候会打印其编译的应用程序。在大多数场景里面,你会看到它在程序的主类上调用编译器。

但是,有一种情况是不会在第一次调用时编译所有类的的。如果你通过类名Class.forNasme加载一个类,Java编译器不知道该类需要哪些信息。在这种场景下,你会看到CCL会再次运行Java编译器。

如何使用CompilingClassLoader

为了使用CCL,我们需要用一种独特的方式启动程序。正常的启动程序如下:

% java Foo arg1 arg2

而我们启动方式如下:

% java CCLRun Foo arg1 arg2

CCLRun是一个特殊的桩程序,它会创建一个CompilingClassLoader并使用它来加载程序的main方法,确保整个程序的类会通过CompilingClassLoader加载。CCLRun使用Java反射API来调用main方法并传参

Java2中ClassLoader的变化

Java1.2以后ClassLoader有一些变动。原有版本的ClassLoader还是兼容的,而且在新版本下开发ClassLoader更容易了

新的版本下采用了delegate模型。ClassLoader可以将类的请求委托给父类。默认的实现会先调用父类的实现,在自己加载。但是这种模式是可以改变的。所有的ClassLoader的根节点是系统ClassLoader。它默认会从文件系统中加载类。

loadClass默认实现

一个自定义的loadClass方法通常会尝试用各种方法来获得一个类的信息。如果你写了大量的ClassLoader,你会发现基本上是在重复写复杂而变化不大的代码。

java1.2的loadClass的默认实现中允许你直接重写findClass方法,loadClass将会在合适的时候调用该方法。

这种方式的好处在于你无须重写loadClass方法。

新方法:findClass

该方法会被loadClass的默认实现调用。findClass是为了包含ClassLoader所有特定的代码,而无需写大量重负的其他代码

新方法:getSystenClassLoader

无论你是否重写了findClass或是loadClass方法,getSystemClassLoader允许你直接获得系统的ClassLoader(而不是隐式的用findSystemClass获得)

新方法:getParent

该方法允许类加载器获取其父类加载器,从而将请求委托给它。当你自定义的加载器无法找到类时,可以使用该方法。父类加载器是指包含创建该类加载代码的加载器。

源码

// $Id$
 
import java.io.*;
 
/*
 
A CompilingClassLoader compiles your Java source on-the-fly.  It
checks for nonexistent .class files, or .class files that are older
than their corresponding source code.

*/
 
public class CompilingClassLoader extends ClassLoader
{
  // Given a filename, read the entirety of that file from disk
  // and return it as a byte array.
  private byte[] getBytes( String filename ) throws IOException {
    // Find out the length of the file
    File file = new File( filename );
    long len = file.length();
 
    // Create an array that's just the right size for the file's
    // contents
    byte raw[] = new byte[(int)len];
 
    // Open the file
    FileInputStream fin = new FileInputStream( file );
 
    // Read all of it into the array; if we don't get all,
    // then it's an error.
    int r = fin.read( raw );
    if (r != len)
      throw new IOException( "Can't read all, "+r+" != "+len );
 
    // Don't forget to close the file!
    fin.close();
 
    // And finally return the file contents as an array
    return raw;
  }
 
  // Spawn a process to compile the java source code file
  // specified in the 'javaFile' parameter.  Return a true if
  // the compilation worked, false otherwise.
  private boolean compile( String javaFile ) throws IOException {
    // Let the user know what's going on
    System.out.println( "CCL: Compiling "+javaFile+"..." );
 
    // Start up the compiler
    Process p = Runtime.getRuntime().exec( "javac "+javaFile );
 
    // Wait for it to finish running
    try {
      p.waitFor();
    } catch( InterruptedException ie ) { System.out.println( ie ); }
 
    // Check the return code, in case of a compilation error
    int ret = p.exitValue();
 
    // Tell whether the compilation worked
    return ret==0;
  }
 
  // The heart of the ClassLoader -- automatically compile
  // source as necessary when looking for class files
  public Class loadClass( String name, boolean resolve )
      throws ClassNotFoundException {
 
    // Our goal is to get a Class object
    Class clas = null;
 
    // First, see if we've already dealt with this one
    clas = findLoadedClass( name );
 
    //System.out.println( "findLoadedClass: "+clas );
 
    // Create a pathname from the class name
    // E.g. java.lang.Object => java/lang/Object
    String fileStub = name.replace( '.', '/' );
 
    // Build objects pointing to the source code (.java) and object
    // code (.class)
    String javaFilename = fileStub+".java";
    String classFilename = fileStub+".class";
 
    File javaFile = new File( javaFilename );
    File classFile = new File( classFilename );
 
    //System.out.println( "j "+javaFile.lastModified()+" c "+
    //  classFile.lastModified() );
 
    // First, see if we want to try compiling.  We do if (a) there
    // is source code, and either (b0) there is no object code,
    // or (b1) there is object code, but it's older than the source
    if (javaFile.exists() &&
         (!classFile.exists() ||
          javaFile.lastModified() > classFile.lastModified())) {
 
      try {
        // Try to compile it.  If this doesn't work, then
        // we must declare failure.  (It's not good enough to use
        // and already-existing, but out-of-date, classfile)
        if (!compile( javaFilename ) || !classFile.exists()) {
          throw new ClassNotFoundException( "Compile failed: "+javaFilename );
        }
      } catch( IOException ie ) {
 
        // Another place where we might come to if we fail
        // to compile
        throw new ClassNotFoundException( ie.toString() );
      }
    }
 
    // Let's try to load up the raw bytes, assuming they were
    // properly compiled, or didn't need to be compiled
    try {
 
      // read the bytes
      byte raw[] = getBytes( classFilename );
 
      // try to turn them into a class
      clas = defineClass( name, raw, 0, raw.length );
    } catch( IOException ie ) {
      // This is not a failure!  If we reach here, it might
      // mean that we are dealing with a class in a library,
      // such as java.lang.Object
    }
 
    //System.out.println( "defineClass: "+clas );
 
    // Maybe the class is in a library -- try loading
    // the normal way
    if (clas==null) {
      clas = findSystemClass( name );
    }
 
    //System.out.println( "findSystemClass: "+clas );
 
    // Resolve the class, if any, but only if the "resolve"
    // flag is set to true
    if (resolve && clas != null)
      resolveClass( clas );
 
    // If we still don't have a class, it's an error
    if (clas == null)
      throw new ClassNotFoundException( name );
 
    // Otherwise, return the class
    return clas;
  }
}
import java.lang.reflect.*;
 
/*
 
CCLRun executes a Java program by loading it through a
CompilingClassLoader.
 
*/
 
public class CCLRun
{
  static public void main( String args[] ) throws Exception {
 
    // The first argument is the Java program (class) the user
    // wants to run
    String progClass = args[0];
 
    // And the arguments to that program are just
    // arguments 1..n, so separate those out into
    // their own array
    String progArgs[] = new String[args.length-1];
    System.arraycopy( args, 1, progArgs, 0, progArgs.length );
 
    // Create a CompilingClassLoader
    CompilingClassLoader ccl = new CompilingClassLoader();
 
    // Load the main class through our CCL
    Class clas = ccl.loadClass( progClass );
 
    // Use reflection to call its main() method, and to
    // pass the arguments in.
 
    // Get a class representing the type of the main method's argument
    Class mainArgType[] = { (new String[0]).getClass() };
 
    // Find the standard main method in the class
    Method main = clas.getMethod( "main", mainArgType );
 
    // Create a list containing the arguments -- in this case,
    // an array of strings
    Object argsArray[] = { progArgs };
 
    // Call the method
    main.invoke( null, argsArray );
  }
}
public class Foo
{
  static public void main( String args[] ) throws Exception {
    System.out.println( "foo! "+args[0]+" "+args[1] );
    new Bar( args[0], args[1] );
  }
}
import baz.*;
 
public class Bar
{
  public Bar( String a, String b ) {
    System.out.println( "bar! "+a+" "+b );
    new Baz( a, b );
 
    try {
      Class booClass = Class.forName( "Boo" );
      Object boo = booClass.newInstance();
    } catch( Exception e ) {
      e.printStackTrace();
    }
  }
}
 package baz;
 
public class Baz
{
  public Baz( String a, String b ) {
    System.out.println( "baz! "+a+" "+b );
  }
}
public class Boo
{
  public Boo() {
    System.out.println( "Boo!" );
  }
}

相关文章:

基于Java类的加载方式之classloader类加载器详解

Java虚拟机学习 - 类加载器(ClassLoader)

相关视频:

全面解析Java注解

위 내용은 ClassLoader를 작성하는 이유는 무엇입니까? Java의 클래스로더에 대한 깊은 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.