Java语言中的赞扬类

96

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

我能想到的是:

  • Object(显然)因为它在其他事物之外没有超类。
  • String 因为该语言对+运算符有特殊支持。
  • Thread 因为它有这个神奇的start()方法,尽管没有字节码指令可以“分叉”执行。

我想所有这些类都以某种方式在JLS中提到了。如果我错了,请纠正我。

无论如何,还有哪些这样的类存在?Java语言中是否有完整的“受人尊敬的类”列表?


2
泛型几乎符合要求,但并非完全如此。它们是使用编译器技巧实现的,但它们并不仅限于一个类。 - Bill the Lizard
2
它们都是引用类型。;-) - starblue
1
“thread.start” 是神奇的吗?它只是一些本地代码被调用来执行这个操作,对吧? - jcoder
我也有这个想法。也许仅使用JNI就足以实现Thread类。我想,如果我要尝试这样做,我会使用一些操作系统级别的线程API,在start()方法的实现中分叉执行,将run()方法在分叉的线程中执行,然后返回。但是,我的操作系统线程将继续运行。它能够与JVM创建的线程平稳运行吗?并且遵守JLS内存模型等规定吗? - aioobe
2
根据规范,创建线程的唯一方法是从Thread类中创建(http://java.sun.com/docs/books/jvms/second_edition/html/Threads.doc.html#22488)。当然,它依赖于与JVM的某些本地级别通信,但如果您自己使用JNI,可能会启动一个线程,但您无法让JVM理解您正在做什么(锁定,内存模型等)。 Thread在特权方面具有特殊特权-规范将其分配为启动线程的唯一方式。 - Yishai
13个回答

35

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

  • AutoBoxing 类 - 编译器只允许特定的类。
  • Class - 有自己的字面量(例如 int.class)。我还会添加其泛型类型而无需创建新实例。
  • String - 具有重载的 +-运算符和对字面量的支持。
  • Enum - 仅限于可以在 switch 语句中使用的类(很快将赋予 String 特权)。它还可以做其他事情(自动静态方法创建、序列化处理等),但这些理论上可以通过代码完成——只是很繁琐,其中一些限制可能无法强制执行子类中(例如特殊的子类规则)。但你永远无法在 switch 语句中包括它,除非具有 enum 的特权状态。
  • Object - 所有对象的根源(我会添加 clone 和 finalize 方法不是你可以实现的内容)。
  • References: WeakReference、SoftReference、PhantomReference
  • Thread - 语言没有给你一个特定的指示来启动线程,而是神奇地将其应用于 start() 方法。
  • Throwable - 所有可以使用 throw、throws 和 catch 进行工作的类的根源,以及编译器对 Exception vs. RuntimeException 和 Error 的理解。
  • NullPointerException 和其他异常(例如 ArrayIndexOutOfBounds),可以由其他字节码指令引发而不是 athrow 指令。

接口

  • Iterable - 仅限于可以在增强 for 循环中使用的接口。

荣誉提名:

  • java.lang.reflect.Array - 创建由 Class 对象定义的新数组将无法实现。
  • Annotations是一种特殊的语言功能,它在运行时表现得像一个接口。你肯定不能定义另一个Annotation接口,就像你不能为Object定义替换一样。但是,你可以实现它们的所有功能,并通过另一种方式检索它们(以及整个大量的样板代码),而不是使用反射。事实上,在引入注释之前,有许多基于XML和javadoc标记的实现。
  • ClassLoader -它与JVM有特权关系,因为没有语言方法来加载类,虽然有字节码方法,所以它就像Array一样。它还具有JVM回调的特权,虽然这是一个实现细节。
  • Serializable - 你可以通过反射实现功能,但它有自己的特权关键字,并且在某些情况下你需要花费很多时间与SecurityManager交流。
  • 注意:我在列表中省略了提供JNI的内容(例如IO),因为如果你愿意,你总是可以实现自己的JNI调用。然而与JVM以特权方式交互的本地调用是不同的。

    Arrays是有争议的-它们继承自Object,有一个理解的层次结构(Object[]是String[]的超类型),但它们是语言功能,而不是独立定义的类。


    @KK_07k11A0585,集合是一个标准的API,可以由任何人以不同的方式构建(实际上还有针对原始类型的替代实现,以及一个非常著名的Google项目来增强它们)。它们得到的唯一特殊之处就是可迭代性,在答案中提到了。它们确实是Java编程的基础,但它们只是普通的类,没有特殊的特权。 - Yishai
    @Yishai 在开发任何应用程序时,最重要的事情是数据管理。我们可以用不同的方式完成任务,但优化的方式是占用更少的内存和减少不必要引用的方式。通过使用集合,我们可以对大量数据进行排序、搜索和比较,这提供了预定义的算法,如二分查找、归并排序等。它还为我们提供了比较器和可比接口来自定义我们的技术。集合类可能不是Java中最好的类,但无疑是一个充满荣耀品质的类。 - KK_07k11A0585
    @Yishai 嗯嗯嗯……这意味着集合是很重要的,但它并不是一种仅能由JVM开发的(独特)类。这是你想要表达的吗? - KK_07k11A0585
    1
    SecurityManager怎么样?或者与反射或序列化有关的任何内容呢? - Antimony
    @Antimony,我其实不确定。我一时也不知道有什么特别的,但也许有。 - Yishai
    显示剩余4条评论

    19

    Class,当然。它有自己的字面值(这一点与String相同),并且是所有反射魔法的起点。


    啊,说得好。那么类字面值的例子是什么?你是指MyClass.class吗? - aioobe
    4
    @aioobe说得没错。请注意,您还可以使用int.class、char.class等。 - Michael Borgwardt

    13

    sun.misc.unsafe 是所有肮脏的、违背编程语言精神的黑科技之母。


    12
    1. 枚举类型。虽然编译器可以对其进行子类化,但是在代码中不能手动实现。
    2. java.util.concurrent 下的许多功能可以不依赖JVM支持来实现,但效率会大打折扣。

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

    11

    你是指包装基本类型的类 - 这也包括布尔和字符;但不包括 BigInteger。 - emory
    1
    @emory:没错,只是原始包装类。不幸的是,这确实排除了 BigInteger。 - Bill the Lizard

    10

    既然提到了重要的,那么我就提一下一些接口:

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

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

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


    是的,它们是接口,因此它们不需要“特殊”的实现。 (类似于Throwable。) - aioobe
    5
    @Michael Borgwardt它具有transient关键字。 - Bozho
    既然你提到了Iterable,那我们能否在接口列表中考虑Comparable呢? - m_pGladiator
    1
    我不这么认为 - Comparable 不参与任何内部操作。你可以轻松地编写 NewComparable 和新的 NewArrays.sort(..),并具有相同的功能。 - Bozho
    我同意@Bozho的观点 - 它并不是集成的(尽管它很普遍和有用!) - corsiKa
    显示剩余4条评论

    6
    1. Throwable、RuntimeException和Error是Java中的异常类,它们都继承自Throwable类。AssertionError也是一个异常类。
    2. References、WeakReference、SoftReference和PhantomReference是Java中用于垃圾回收的引用类型。
    3. Enum是Java中的枚举类型。
    4. Annotation是Java中的注解类型。

    不错的列表。+1,注释是一个接口,没有实现。 - aioobe
    1
    注释与普通接口的编译处理方式不同。与枚举类似,它们都继承自Annotation,并由编译器自动完成。根据Annotation文档所述:所有注释类型所扩展的公共接口。请注意,手动扩展此接口的接口不会定义注释类型。还要注意,此接口本身不定义注释类型。因此,您无法使用常规语法创建注释,需要更改编译器以添加它们。 - Andrei Fierbinteanu

    6

    Java数组,如int[].class


    啊,不错![I 类;)虽然它不是一个 API 类。 - aioobe

    4

    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

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接