`

java的线程上下文类加载器

    博客分类:
  • java
阅读更多
从Java 虚拟机的角度来讲,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),它C++语言实现,是虚拟机自身的一部分:另一种就是所有其他的类加载器,这些类加载器都出Java 语言实现,独立于虚拟机外部,并且全都继承自抽象类java.lang.ClassLoader。

从发开人员的角度来看,类加载器有下面3种。

(一)、启动类加载器 (BootstrapClassLoader):存放在<JAVA_HOM/lib>目录中的,或者被-Xbootclasspath 参数所指定的路径中的,并且是虚拟机识别的类库加载到虚拟机内存中(一般是java.lang下的类,和java.io下的类)。启动类加载器无法被Java 程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给引导类加载器,直接使用null 代替。

(二)、扩展类加载器(ExtensionClassloader):由sun.misc.Launcher$ExtClassLoader 实现,负责加载<JAVA_HOME>/lib/ext 目录中的,或者被java.ext.dirs 系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加器。

(三)、应用程序类加载器(ApplicationClassLoader): 这个类加载器由sun.misc.Launcher$AppClassLoader 来实现. 由于这个类加载器是ClassLoader 中的getSystemC lassLoader()方法的返回值,所以一般也称它为系统类加载器.负责加载用户类路径经( ClassPath )上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,就是程序中默认的类加载器。


双亲委派模型

类加载器之间的层次关系,称为类加载器的双亲委派模型(Parents Delegation Model)。除了顶层的启动类加载器外,其余的类加载器都有父类加载器.

工作过程是: 如果一个类加载器收到了类加载的请求,先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,所有的加载请求最终都会传送到顶层的启动类加载器中,只有当父加器无法加载这个类时,子载加载器才自己去加载。



类加载器的三个特性

类加载器有三个特性,分别为委派,可见性和单一性,其他文章上对这三个特性的介绍如下:


* 委托机制是指将加载一个类的请求交给父类加载器,如果这个父类加载器不能够找到或者加载这个类,那么再加载它。

* 可见性的原理是子类的加载器可以看见所有的父类加载器加载的类,而父类加载器看不到子类加载器加载的类。

* 单一性原理是指仅加载一个类一次,这是由委托机制确保子类加载器不会再次加载父类加载器加载过的类。


其中,委派机制是基础,在其他资料中也把这种机制叫做类加载器的双亲委派模型,其实说的是同一个意思。可加性和单一性是依赖于委派机制的。




破坏双亲委派模型

第一次“被破坏”发生在双亲委派模型出现之前。亲委派模型在JDK 1.2 之后才被引入,类加载器和抽象类Java. lang. ClassLoader 则在JDK 1 .0 时代就已经存在,对已经存在的用户自定义类加载器的实现代码, Java 设计者们引入双亲委派模型时做出了一些妥协。

第二次“被破坏”是由这个模型自身的缺陷所导致的,双亲委派很好地解决了各个类加载器的基础类的统一问题(越基础的类由越上层的类加载器进行加载),基础类之所以被称为“基础”,是因为它们总是作为被用户代码词用的API。但是基础类有时又要调用用户代码,如JNDI。此时就引入了线程上下文类加器。

第三次“被破坏”是由于用户对程序动态性的追求而导致的。代码热替换(HotSwap)、模块热部署(Hot Deployment)等


The Dreaded Thread Context Class Loader
引用

Neil Bartlett


The Dreaded Thread Context Class Loader

Tomorrow at OSGi Community Event 2012 I will be talking about “How to make your library OSGi friendly without depending on OSGi”. During this talk I will make reference to Java’s Thread Context Class Loader (TCCL), but since it is only a 25-minute talk I will not have time to go into great detail on this subject. Therefore I thought it would be helpful to write this post with some of the background information.

Much of the technical information and research in this post is derived from an old, unpublished OSGi RFP authored by Peter Kriens. I have used it with his permission.
History

The thread context class loader (TCCL) has a very interesting history in Java.

Java defines a hierarchy of class loaders, and in a typical Java runtime the “application” loader at the bottom is aware of the “classpath” (as supplied via the -classpath/-cp switch), and the boot loader is aware of the JRE classes in rt.jar etc. There is also an “extension” class loader in the middle, which loads from the JRE ext directory. Class loaders delegate upwards to their parent, which means the application loader can see any class offered by the boot loader but the boot loader cannot see the application classes.

Sun first ran into problems with this scheme when implementing Java Serialization, as used in Remote Method Invocation (RMI). Deserializing data from a stream as Java objects required knowledge of the application classes, but the deserialization code was loaded by the boot loader; therefore it would not normally have visibility of the classes. The problem was fixed by adding private native methods to the JRE that would allow inspection of the call stack in order to find the first non-null class loader.

However, many other extension libraries soon ran into the same problem, and they could not (and should not!) all solve it with private native methods in the Sun JVM. At about the same time, J2EE became very important. J2EE is an application model where the Java code runs in a severely restricted environment. Applications run in a “silo”. Each application runs in a separate class loader and threads may not cross application/silo boundaries. Applications can use the extensions provided by the VM and the libraries provided by the container, but they cannot use any code from each other. This model also suffers from the problem that the libraries provided by the container cannot access the application code.

Therefore in Java 1.2 the TCCL was introduced: a class loader that is associated with a thread, as a thread-local variable. This means that any libary can at any time access the “current” context loader by asking the calling thread. This context loader is expected to have visibility to the specific application class loader that is responsible for the call, and therefore visibility of the application classes.

Sun also started to use the TCCL heavily itself, though without proper specification or guidance. The 1.5 JDK has 79 references to Thread.getContextClassLoader(). Since Java 1.4, the Java VM was modified to use the context class loader in JNDI, JAXP, CORBA, JMX, Xalan, Xerces, AWT, Beans, SQL, Logging, Prefs, RMI, Security, Swing, and most of the XML subsystems. Additionally most middleware libraries like Hibernate, Saxon, Jakarta Commons Logging and many others started to use the TCCL as either the first or last resort. Java has provided virtually no specification or guidelines on the use of TCCL. This has caused almost every library to follow a different strategy.

The key questions to answer regarding the correct use of TCCL are:

    when should it be set, and by whom?
    of what set of classes should it have visibility?

From a J2EE point of view these questions are relatively easy to answer because the programming model is so constrained. The container owns all the entry points; i.e., it controls the HTTP thread running the Servlets and the RMI sockets for EJBs, creation of additional threads is forbidden, etc) and it can therefore ensure that the TCCL is always set on entry into the application code. Since applications are entirely self-contained, the set of visible classes is simply all classes owned by the application.

In a modular runtime such as OSGi these questions are far harder to answer. Bundles are free to create their own threads and entry points, and there is no general way to identify the set of bundles that contribute classes for an “application”; indeed, the very concept of an “application” is much harder to pin down. We could constrain the programming model and require that an application be deployed as a single bundle with no dependencies, but this would negate most of the benefits of using OSGi. Therefore OSGi does not attempt to define what the TCCL should be at any particular time, and typically it is left null.
Alternatives to TCCL

In our own OSGi-compliant code, or in any library with explicit OSGi support, we need not worry about the TCCL, because OSGi Services provide a far cleaner approach than any ClassLoader-based approach to loading extensions. However, legacy third-party libraries are still an issue. Many such libraries attempt to load application classes by name at runtime: for example, Hibernate reads class names from .hbm.xml files and then creates instances of those classes for each database record.

When you move such a library to any kind of modular environment – including OSGi, JBoss Modules or even Jigsaw – you find that it breaks, because the name of a class is not sufficient to uniquely identify it. The identity of a class consists of its fully qualified name AND the class loader that defined it, which in OSGi usually corresponds to the bundle that contains it. So in addition to the name, we need to know the class loader from which to load the class. Due to the wide variety of class loading environments created by various application servers, many libraries attempt to solve this problem with a set of heuristics. Consulting the TCCL is usually one of the heuristics, along with checking the library’s own class loader, the JRE extension class loader, etc.

If a library only consults the TCCL then we are somewhat stuck: we will have to explicitly set the TCCL from our own code before calling into the library. Fortunately this is rarely the case, for example most such libraries will also call Class.forName(), which means the library will consult its own class loader to load the class. This is still far from ideal, but we can work around it by deploying a single fragment rather than scattering calls to setContextClassLoader() throughout our code. Far better is when a library eschews class names entirely and allows Class objects to be passed; or at least offers an API method to set the class loader from which the class names should be loaded.

Unfortunately it’s very hard to predict in advance – at least without closely inspecting the code – what kind of heuristics the library employs, again because of the complete lack of specification and guidance in this area.
Summary

I hope you will attend my talk tomorrow, which is mainly addressed to authors of Java libraries that want their code to work well in OSGi, but not only in OSGi. As you can doubtless infer from this blog post, avoiding the TCCL and other weird ClassLoader-based hacks is a big part of being OSGi-friendly, but I will also talk about service dynamics and configuration issues. See you there!

Posted on 23 October 2012



Find a way out of the ClassLoader maze


中文翻译 引用
引用

[说明]几个关键字将不翻译

    ClassLoader
    System
    Context
    Thread

走出ClassLoader的迷宫

                                                               System、Current和Context ClassLoader?分别在何种情形下使用?


1、问题:在何种情形下使用thread.getcontextclassloader()?

尽管没经常遇到这个问题,但是想获得准确的答案并不那么容易,特别是在开发应用框架的时候,你需要动态的加载一些类和资源,不可避免的你会被此困扰。一般来说,动态载入资源有三种ClassLoader可以选择,System ClassLoader(也叫App ClassLoader)、当前类的ClassLoader和CurrentThread的Context ClassLoader。那么, 如何选择使用?

首先可以简单排除的是System ClassLoader,这个ClassLoader负责从参数-classpath、-cp、和操作系统CLASSPATH中载入资源。并且,任何ClassLoader的getSystemXXX()方法都是有以上几个路径指定的。我们应该很少需要编写直接使用ClassLoader的程序,否则你的代码将只能在命令行运行,发布你的代码成为ejb、web应用或者java web start应用,我肯定他们会崩溃!

接下来,我们只剩下两个选择了:当前ClassLoader和Thread Context ClassLoader

Current ClassLoader:当前类所属的ClassLoader,在虚拟机中类之间引用,默认就是使用这个ClassLoader。另外,当你使用Class.forName(), Class.getResource()这几个不带ClassLoader参数的方法是,默认同样适用当前类的ClassLoader。你可以通过方法XX.class.GetClassLoader()获取。

Thread Context ClassLoader,没一个Thread有一个相关联系的Context ClassLoader(由native方法建立的除外),可以通过Thread.setContextClassLoader()方法设置。如果你没有主动设置,Thread默认集成Parent Thread的 Context ClassLoader(注意,是parent Thread 不是父类)。如果 你整个应用中都没有对此作任何处理,那么 所有的Thread都会以System ClassLoader作为Context ClassLoader。知道这一点很重要,因为从web服务器,java企业服务器使用一些复杂而且精巧的ClassLoader结构去实现诸如JNDI、线程池和热部署等功能以来,这种简单的情况越发的少见了。

这篇文章中为什么把Thread Context ClassLoader放在首要的位置,别人并没有大张旗鼓的介绍它?很多开发者都对此不甚了解,因为sun没有提供很好的说明文档。

事实上,Context ClassLoader提供一个突破委托代理机制的后门。虚拟机通过父子层次关系组织管理ClassLoader,没有个ClassLoader都有一个Parent ClassLoader(BootStartp不在此范围之内),当要求一个ClassLoader装载一个类是,他首先请求Parent ClassLoader去装载,只有parent ClassLoader装载失败,才会尝试自己装载。

但是,某些时候这种顺序机制会造成困扰,特别是jvm需要动态载入有开发者提供的资源时。就以JNDI为例,JNDI的类是由bootstarp ClassLoader从rt.jar中间载入的,但是JNDI具体的核心驱动是由正式的实现提供的,并且通常会处于-cp参数之下(注:也就是默认的System ClassLoader管理),这就要求bootstartp ClassLoader去载入只有SystemClassLoader可见的类,正常的逻辑就没办法处理。怎么办呢?parent可以通过获得当前调用Thread的方法获得调用线程的Context ClassLoder 来载入类。

顺带补充一句,JAXP从1.4之后也换成了类似JNDI的ClassLoader实现,嘿嘿,刚刚我说什么来着,SUN文档缺乏 ^_^

介绍完这些之后,我们走到的十字路口,任一选择都不是万能的。一些人认为Context ClassLoader将会是新的标准。但是 一旦你的多线程需要通讯某些共享数据,你会发现,你将有一张极其丑陋的ClassLoader分布图,除非所有的线程使用一样的Context ClassLoader。并且委派使用当前ClassLoder对一些方法来说是默认继承来的,比如说Class.forName()。尽管你明确的在任何你能控制的地方使用Context ClassLoader,但是毕竟还有很多代码不归你管(备注:想起一个关于UNIX名字来源的笑话)。

某些应用服务器使用不同的ClassLoder作为Context ClassLoader和当前ClassLoader,并且这些ClassLoader有着相同的ClassPath,但没有父子关系,这使得情况更复杂。请列位看官,花几秒钟时间想一想,为什么这样不好?被载入的类在虚拟机内部有一个全名称,不同的ClassLoader载入的相同名称的类是不一样的,这就隐藏了类型转换错误的隐患。(注:奶奶的 俺就遇到过,JBOSSClassLoader机制蛮挫的)

这种混乱事实上在java类中也有,试着去猜测任何一个包含动态加载的java规范的ClassLoader机制,以下是一个清单:

    JNDI uses context classloaders
    Class.getResource() and Class.forName() use the current classloader
    JAXP uses context classloaders (as of J2SE 1.4)
    java.util.ResourceBundle uses the caller's current classloader
    URL protocol handlers specified via java.protocol.handler.pkgs system property are looked up in the bootstrap and system classloaders only
    Java Serialization API uses the caller's current classloader by default

而且关于这些资源的类加载机制文档时很少。

java开发人员应该怎么做?

如果你的实现是利用特定的框架,那么恭喜你,实现它远比实现框架要简单得多!例如,在web应用和EJB应用中,你仅仅只要使用 Class.getResource()就足够了。

其他的情形下,俺有个建议(这个原则是俺工作中发现的,侵权必究,抵制盗版。),

下面这个类可以在整个应用中的任何地方使用,作为一个全局的ClassLoader(所有的示例代码可以从download下载):
1 public abstract class ClassLoaderResolver {
2 /**
3 * This method selects the best classloader instance to be used for
4 * class/resource loading by whoever calls this method. The decision
5 * typically involves choosing between the caller's current, thread context,
6 * system, and other classloaders in the JVM and is made by the
7 * {@link IClassLoadStrategy} instance established by the last call to
8 * {@link #setStrategy}.
9 *
10 * @return classloader to be used by the caller ['null' indicates the
11 * primordial loader]
12 */
13 public static synchronized ClassLoader getClassLoader() {
14 final Class caller = getCallerClass(0);
15 final ClassLoadContext ctx = new ClassLoadContext(caller);
16
17 return s_strategy.getClassLoader(ctx);
18 }
19
20 public static synchronized IClassLoadStrategy getStrategy() {
21 return s_strategy;
22 }
23
24 public static synchronized IClassLoadStrategy setStrategy(
25 final IClassLoadStrategy strategy) {
26 final IClassLoadStrategy old = s_strategy;
27 s_strategy = strategy;
28
29 return old;
30 }
31
32 /**
33 * A helper class to get the call context. It subclasses SecurityManager to
34 * make getClassContext() accessible. An instance of CallerResolver only
35 * needs to be created, not installed as an actual security manager.
36 */
37 private static final class CallerResolver extends SecurityManager {
38 protected Class[] getClassContext() {
39 return super.getClassContext();
40 }
41
42 } // End of nested class
43
44 /*
45 * Indexes into the current method call context with a given offset.
46 */
47 private static Class getCallerClass(final int callerOffset) {
48 return CALLER_RESOLVER.getClassContext()[CALL_CONTEXT_OFFSET
49 + callerOffset];
50 }
51
52 private static IClassLoadStrategy s_strategy; // initialized in <clinit>
53
54 private static final int CALL_CONTEXT_OFFSET = 3; // may need to change if
55 // this class is
56 // redesigned
57 private static final CallerResolver CALLER_RESOLVER; // set in <clinit>
58
59 static {
60 try {
61 // This can fail if the current SecurityManager does not allow
62 // RuntimePermission ("createSecurityManager"):
63
64 CALLER_RESOLVER = new CallerResolver();
65 } catch (SecurityException se) {
66 throw new RuntimeException(
67 "ClassLoaderResolver: could not create CallerResolver: "
68 + se);
69 }
70
71 s_strategy = new DefaultClassLoadStrategy();
72 }
73 } // End of class.
74
75
76


通过ClassLoaderResolver.getClassLoader()方法获得一个ClassLoader的引用,并且利用正常的ClassLoader的api去加载资源,你也可以使用 ResourceLoader API作为备选方案
1 public abstract class ResourceLoader {
2
3 /**
4  * @see java.lang.ClassLoader#loadClass(java.lang.String)
5  */
6 public static Class loadClass (final String name)throws ClassNotFoundException{
7
8 final ClassLoader loader = ClassLoaderResolver.getClassLoader (1);
9
10 return Class.forName (name, false, loader);
11
12 }
13
14 /**
15
16 * @see java.lang.ClassLoader#getResource(java.lang.String)
17
18 */   
19
20
21 public static URL getResource (final String name){
22
23 final ClassLoader loader = ClassLoaderResolver.getClassLoader (1);
24
25 if (loader != null)return loader.getResource (name);
26 else return ClassLoader.getSystemResource (name);
27 }
28  more methods
29
30 } // End of class

而决定使用何种ClassLoader策略是由接口实现的,这是一种插件机制,方便变更。
public interface IClassLoadStrategy{
ClassLoader getClassLoader (ClassLoadContext ctx);
} // End of interface

它需要一个ClassLoader Context 对象去决定使用何种ClassLoader策略。
1 public class ClassLoadContext{
2
3 public final Class getCallerClass (){
4 return m_caller;
5 }
6
7 ClassLoadContext (final Class caller){
8 m_caller = caller;
9
10 }
11
12 private final Class m_caller;
13
14 } // End of class

ClassLoadContext.getCallerClass()返回调用者给ClassLoaderResolver 或者 ResourceLoader,因此能获得调用者的ClassLoader。需要注意的是,调用者是不会变的 (注:作者使用的final修饰字)。俺的方法不需要对现有的业务方法做扩展,而且可以作为静态方法是用。而且,你可以根据自己的业务场景实现独特的ClassLoaderContext。

看出来没,这是一种很熟悉的设计模式,XD ,把获得ClassLoader的策略从业务中独立出来,这个策略可以是"总是用ContextClassLoader"或者"总是用当前ClassLoader"。想预先知道那种策略是正确的比较困难,那么这种模式可以让你简单的改变策略。

俺写了一个默认的实现,基本可以对付95%的场景(enjoy yourself)
1 public class DefaultClassLoadStrategy implements IClassLoadStrategy{
2
3 public ClassLoader getClassLoader (final ClassLoadContext ctx){
4
5 final ClassLoader callerLoader = ctx.getCallerClass ().getClassLoader ();
6
7 final ClassLoader contextLoader = Thread.currentThread ().getContextClassLoader ();
8
9 ClassLoader result;
10 // If 'callerLoader' and 'contextLoader' are in a parent-child
11 // relationship, always choose the child:
12 if (isChild (contextLoader, callerLoader))result = callerLoader;
13 else if (isChild (callerLoader, contextLoader))result = contextLoader;
14 else{
15 // This else branch could be merged into the previous one,
16 // but I show it here to emphasize the ambiguous case:
17 result = contextLoader;
18 }
19 final ClassLoader systemLoader = ClassLoader.getSystemClassLoader ();
20
21
22 // Precaution for when deployed as a bootstrap or extension class:
23 if (isChild (result, systemLoader))result = systemLoader;
24 return result;
25 }
26
27
28
29  more methods
30
31 } // End of class
32


上面的逻辑比较简单,如果当前ClassLoader和Context ClassLoader是父子关系,那就总选儿子,根据委托原则,这个很容易理解。

如果两人平级,选择正确的ClassLoader很重要,运行时不允许含糊。这种情况下,我的代码选择Context ClassLoader(这是俺个人的经验之谈),当然也不要担心不能改变,你能随便根据需要改变。一般而言,Context ClassLoader比较适合框架,而Current ClassLoader在业务逻辑中用的更多。

最后,检查确保选中的ClassLoader不是System ClassLoader的parent,一旦高于System ClassLoader ,请使用System ClassLoader(你的类部署在Ext路径下面,就会出现这种情况)。

请注意,俺故意没关注被载入资源的名称。Java XML API 成为java 核心api的经历告诉我们,根据资源名称过滤是很不cool的idea。而且 我也没有去确认到底哪个ClassLoader被取得了,因为只要清楚原理,这很容易被推理出来。(哈哈,俺是强淫)

尽管讨论java 的ClassLoader不是一个很cool的话题(译者注,当年不cool,但是现在很cool),而且Java EE的ClassLoader策略越发的依赖各种平台的升级。如果这没有一个更好的设计的话,将会变成一个大大的问题。不敢您是否同意俺的观点,俺尊重你说话的权利,所以请给俺分享您的意见经验。

作者介绍:

Vladimir Roubtsov,曾经使用多种语言有超过13年的编程经历(恩 现在应该超过15年了 hoho),95年开始接触java(hoho 俺是99年看的第一本java书)。现在为Trilogy in Austin, Texas开发企业软件。


翻译完了,MMD 翻译还是很麻烦的。 XD ........
分享到:
评论

相关推荐

    深入探讨 Java 类加载器

    类加载器(class ...本文首先详细介绍了 Java 类加载器的基本概念,包括代理模式、加载类的具体过程和线程上下文类加载器等,接着介绍如何开发自己的类加载器,最后介绍了类加载器在 Web 容器和 OSGi™ 中的应用。

    深入探讨 Java 类加载器.pdf

    类加载器(class ...本文首先详细介绍了 Java 类加载器的基本概念,包括代理模式、加载类的具体过程和线程上下文类加载器等,接着介绍如何开发自己的类加载器,最后介绍了类加载器在 Web 容器和 OSGi™ 中的应用。

    JAVA_API1.6文档(中文)

    java.applet 提供创建 applet 所必需的类和 applet 用来与其 applet 上下文通信的类。 java.awt 包含用于创建用户界面和绘制图形图像的所有类。 java.awt.color 提供用于颜色空间的类。 java.awt.datatransfer ...

    libgdx-separate-context-loader:资产加载器,可让您在单独的gl上下文中加载纹理(帧缓冲区等)

    libgdx单独的上下文加载器 资产加载器,可让您在Libgdx应用程序的单独gl环境中加载纹理(帧缓冲区等)。 我在这里尝试做的是在单独的GL上下文中加载纹理,而不中断主渲染线程,然后在原始(共享)GL上下文中使用...

    Java 1.6 API 中文 New

    java.applet 提供创建 applet 所必需的类和 applet 用来与其 applet 上下文通信的类。 java.awt 包含用于创建用户界面和绘制图形图像的所有类。 java.awt.color 提供用于颜色空间的类。 java.awt.datatransfer 提供...

    JAVA上百实例源码以及开源项目

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java源码包---java 源码 大量 实例

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    JAVA上百实例源码以及开源项目源代码

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java api最新7.0

    java.applet 提供创建 applet 所必需的类和 applet 用来与其 applet 上下文通信的类。 java.awt 包含用于创建用户界面和绘制图形图像的所有类。 java.awt.color 提供用于颜色空间的类。 java.awt.datatransfer 提供...

    JavaAPI1.6中文chm文档 part1

    java.applet 提供创建 applet 所必需的类和 applet 用来与其 applet 上下文通信的类。 java.awt 包含用于创建用户界面和绘制图形图像的所有类。 java.awt.color 提供用于颜色空间的类。 java.awt.datatransfer ...

    java jdk-api-1.6 中文 chmd

    java.applet 提供创建 applet 所必需的类和 applet 用来与其 applet 上下文通信的类。 java.awt 包含用于创建用户界面和绘制图形图像的所有类。 java.awt.color 提供用于颜色空间的类。 java.awt.datatransfer ...

    JavaAPI中文chm文档 part2

    java.applet 提供创建 applet 所必需的类和 applet 用来与其 applet 上下文通信的类。 java.awt 包含用于创建用户界面和绘制图形图像的所有类。 java.awt.color 提供用于颜色空间的类。 java.awt.datatransfer ...

    java源码包4

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java源码包3

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java源码包2

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    Java典型模块

    24.3.2 Applet的上下文对象 24.4 小结 25.1 网络聊天室原理 25.1.1 项目结构框架分析 25.1.2 项目功能业务分析 25.2 网络聊天室的实现过程 25.3 知识点扩展——网络编程和UDP协议 25.3.1 网络编程涉及的基本概念 ...

    DelegatingGroovyClassloader

    简单委托 Groovy 类加载器描述这是一个使用自定义类加载器的简单项目。 简单的想法是嵌入 GroovyClassLoader... 我直接使用了 ClassLoader 但如果你想要一个更透明的使用,您可以采用更改当前线程的上下文类加载器Threa

    [Java参考文档]

    java.applet 提供创建 applet 所必需的类和 applet 用来与其 applet 上下文通信的类。 java.awt 包含用于创建用户界面和绘制图形图像的所有类。 java.awt.color 提供用于颜色空间的类。 java.awt.datatransfer ...

Global site tag (gtag.js) - Google Analytics