Java语言中的荣耀类


96

标准Java API中的某些类与其他类略有不同。我说的是那些没有编译器和/或JVM的特殊支持就无法实现的类。

我马上想到的是:

  • Object (很明显),因为它没有超级类。
  • String 因为该语言对+运算符有特殊支持。
  • Thread 因为尽管没有字节码指令“分叉”执行,但它具有神奇的start()方法。

我想所有类似的类都在JLS中提到过。如我错了请纠正我。

无论如何,还存在其他此类类吗?Java语言中是否有完整的“通用类”列表?


2
泛型几乎合适,但不太合适。它们是使用编译器技巧实现的,但它们并不孤立于一个类。
比尔蜥蜴

2
它们都是崇敬类型。;-)
starblue 2010年

1
“ thread.start”具有魔力吗?当然,这只是一些本机代码被调用了吗?
jcoder

这种想法也打动了我。也许仅JNI就足以实现Thread类。我想如果我想这样做,我将使用一些OS级线程api,在start()方法的实现中派生执行,在派生线程中执行run()方法,然后返回。但是,我的 OS线程将继续运行。这样可以与JVM创建的线程一起顺利运行吗?并尊重JLS内存模型等等?
aioobe

2
根据规范,创建线程的唯一方法是从Thread类(java.sun.com/docs/books/jvms/second_edition/html/…)。当然,它依赖于与JVM的某些原始级别的通信,但是,如果您执行了自己的JNI,则可以启动一个线程,但是您将无法使JVM理解您的工作(锁,内存模型等)。 )。线程享有特权,因为规范为它分配了特殊特权-启动线程的唯一方法。
Yishai 2010年

Answers:


35

有很多不同的答案,所以我认为收集所有答案(并添加一些答案)会很有用:

班级

  • AutoBoxing类-编译器仅允许特定类
  • -有自己的文字(例如int.class)。我还将添加其通用类型而无需创建新实例。
  • 字符串 -具有重载的+运算符和文字的支持
  • 枚举 -可以在switch语句中使用的唯一类(很快也将授予String特权)。它也可以做其他事情(自动静态方法创建,序列化处理等),但理论上可以用代码来完成-这只是很多样板,而且某些约束不能在子类中强制执行(例如特殊的子类化规则),但是如果没有枚举的特权状态,您将永远无法完成将其包含在switch语句中的工作。
  • 对象 -所有对象的根(我将添加其克隆和finalize方法无法实现)
  • 参考:WeakReference,SoftReference,PhantomReference
  • 线程 -语言没有为您提供启动线程的特定指令,而是神奇地将其应用于start()方法。
  • Throwable-可用于throw,throw和catch的所有类的根,以及编译器对Exception vs. RuntimeException和Error的理解。
  • NullPointerException和其他异常(例如ArrayIndexOutOfBounds)可以由除抛出以外的其他字节码指令抛出。

介面

  • 可迭代 -唯一可用于增强型for循环的接口

值得一提的是:

  • java.lang.reflect。数组 -无法创建由Class对象定义的新数组。
  • 注释它们是一种特殊的语言功能,在运行时的行为类似于界面。您当然不能定义另一个Annotation接口,就像您不能定义Object的替换一样。但是,您可以实现它们的所有功能,而只有另一种方法来获取它们(以及一大堆样板),而不是反射。实际上,在引入注释之前,有许多基于XML和基于Javadoc标记的实现。
  • ClassLoader-它与JVM当然具有特权关系,因为没有语言方法可以加载类,尽管有字节码方法,所以它就像Array。它还具有被JVM调用的特殊特权,尽管这是实现细节。
  • 可序列化 -您可以通过反射实现功能,但是它具有自己的特权关键字,在某些情况下,您将花费大量时间与SecurityManager保持亲密关系。

注意:我没有提供JNI的东西(例如IO),因为如果您愿意的话,您总是可以实现自己的JNI调用。但是,以特权方式与JVM交互的本机调用是不同的。

数组是值得商-的-它们继承Object,具有可理解的层次结构(Object []是String []的超类型),但它们是语言功能,而不是单独定义的类。


@Donal,非常正确,我当时在考虑运行时批注,但是确实以这种方式完成了源级别的批注(最著名的是xdoclet,甚至在带有@deprecated的核心java中)
Yishai 2010年

我一直在通过最初由xdoclet处理编写的代码丛,然后转换为注释的方式进行斗争。噢,我更喜欢注释(即使使用适当的行家咒语,其净效果是相同的)。
Donal Fellows 2010年

@ KK_07k11A0585,Collections是一个标准的api,任何人都可以用不同的方式来构建它(实际上,有一些针对基元的替代实现,还有一个非常著名的Google工程来增强它们)。他们唯一的特别之处是可迭代,在答案中提到。可以肯定,它们是Java编程的基础,但是它们只是常规类,没有特殊特权。
Yishai 2012年

@Yishai在开发任何应用程序时,最重要的是数据管理。我们每个人都可以用多种方法来完成一项任务,但是优化的方法是占用较少的内存并且较少使用不必要的引用。通过使用Collections,我们可以对大量数据进行排序,搜索和比较,从而提供了预定义的算法,例如二进制搜索,合并排序等。它还为我们提供了Comparator和Comparable Interfaces来定制我们的技术。Collections类可能不是Java中最好的类,但无疑是美化质量的类。
KK_07k11A0585 2012年

1
SecurityManager呢 还是与反射或序列化有关的任何内容?
锑2012年

19

Class, 当然。它有自己的文字(与StringBTW 有区别),并且是所有反射魔术的起点。


啊,好点。那么类文字的例子是什么?您是指MyClass.class吗?
aioobe 2010年

4
@aioobe:完全正确。请注意,你也有int.class,char.class等
迈克尔博格瓦特


12
  1. 枚举 您不可以对其进行子类化,但是编译器可以。
  2. 在没有JVM支持的情况下,可以实现java.util.concurrent下的许多东西,但是它们的效率要低得多。

1
您可以匿名子类化枚举(枚举值的访问者模式实现的基础)。但是,是的,您不能完全将枚举归为一类;-)
Thierry


10

由于提到了重要的,因此我将提及一些接口:

Iterable接口(自1.5) -它允许一个对象参与foreach循环:

Iterable<Foo> iterable = ...;
for (Foo foo : iterable) {

}

Serializable接口具有非常特殊的含义,与标准接口不同。您可以定义将要考虑的方法,即使它们未在接口中定义(如readResolve())。该transient关键字是影响行为的语言元素Serializable实现者。


没错,尽管它们是接口,所以每次看到它们都不需要“特殊”实现。(类似于Throwable。)
aioobe 2010年

可序列化实际上确实需要特殊的实现。这个接口应该有两种方法(我忘了名字...我可以用谷歌搜索...),但是标准接口方案中并不需要或没有定义它们。
corsiKa 2010年

@glowcoder:但是,曾经有人认为Serializable的所有特殊性都与Java语言无关,而仅与ObjectOutputStream和ObjectInputStream的实现无关。
Michael Borgwardt

5
@迈克尔博格瓦特它有-的transient关键字
Bozho

1
我不这么认为- Comparable不参与任何内部活动。您可以轻松编写NewComparableNewArrays.sort(..)使用相同的功能进行更新
Bozho 2010年

6
  1. Throwable,RuntimeException,Error AssertionError
  2. 参考 WeakReference,SoftReference,PhantomReference
  3. 枚举
  4. 注解

不错的清单。+1,注解虽然是一个接口,但没有实现。
aioobe 2010年

1
编译器与常规接口对注释的处理方式不同。与枚举类似,它们都扩展了Annotation,并且编译器自动执行此操作。来自注释的JavaDoc:由所有注释类型扩展的通用接口。请注意,手动扩展该接口的接口未定义注释类型。另请注意,此接口本身并不定义注释类型。因此,您无法使用常规语法创建注释,它们需要更改编译器以添加它们。
2010年



2

对此不确定。但是我想不出一种手动实现IO对象的方法。


没错,它们不能用纯Java实现。它们需要通过JNI实现(就像需要进行系统调用的任何其他类一样)。但是除此之外,它们不需要编译器或jvm的特殊支持。
aioobe

2

System班上有一些魔术。

System.arraycopy 是对本机代码的迷恋

public static native void arraycopy(Object array1, int start1, 
  Object array2, int start2, int length);

但...

/**
 * Private version of the arraycopy method used by the jit
 * for reference arraycopies
 */
private static void arraycopy(Object[] A1, int offset1,
  Object[] A2, int offset2, int length) {
   ...
}

1
嘿,答案的第二部分是什么意思?
Pacerier,2011年

1

好吧,因为已经提到了assert的特殊处理。这是jvm对其进行特殊处理的更多异常类型:

  • 空指针异常
  • ArithmeticException。
  • StackOverflowException
  • 各种OutOfMemoryErrors
  • ...

异常不是很特殊,但是jvm在特殊情况下会使用它们,因此您必须自己编写自己的jvm才能实现它们。我确信周围还有更多特殊的例外。


0

这些类中的大多数并没有真正在编译器或JVM的“特殊”帮助下实现。Object确实会注册一些本机,这些本机会在内部JVM结构周围发生故障,但是您也可以针对自己的类进行操作。(我承认这受语义限制,“调用JVM中定义的本机”可以被视为对JVM的特殊支持。)

/ is /的特殊之处在于“新”的行为以及“掷”指令如何初始化这些内部结构。

注释和数字几乎全是怪异的。


4
aioobe指的是您无法实现的类,因为它们具有特殊的支持。如果不继承java.lang.Object形式,则不能创建自己的Object类作为类型系统的根。对象具有来自编译器和jvm的特殊支持,以确保它是根类。本地调用不足以解决此问题。
josefx
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.