【问题标题】:Glorified classes in the Java languageJava 语言中的美化类
【发布时间】:2010-08-11 12:39:12
【问题描述】:

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

我马上想到的是:

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

我想像这样的所有类都在 JLS 中以一种或另一种方式提及。如果我错了,请纠正我。

不管怎样,还有哪些这样的类? Java 语言中是否有完整的“美化类”列表?

【问题讨论】:

  • Generics 几乎适合,但不完全。它们是使用编译器技巧实现的,但它们并不孤立于一个类。
  • 都是崇敬类型。 ;-)
  • “thread.start”神奇吗?当然,这只是调用了一些本机代码来执行此操作吗?
  • 这个想法也让我印象深刻。也许仅 JNI 就足以实现 Thread 类。我想如果我尝试这样做,我会使用一些操作系统级别的线程 api,在 start() 方法的实现中分叉执行,在分叉的线程中执行 run() 方法,然后返回。但随后 my 操作系统线程将继续运行。这会与 JVM 创建的线程一起顺利运行吗?并尊重 JLS 内存模型等等?
  • 根据规范,创建线程的唯一方法是从 Thread 类 (java.sun.com/docs/books/jvms/second_edition/html/…)。当然,它依赖于与 JVM 的一些原生级别的通信,但如果你自己做 JNI,你可能会启动一个线程,但你不会让 JVM 理解你在做什么(锁、内存模型等)。 )。线程具有特权,因为规范为其分配了特殊特权 - 启动线程的唯一方式。

标签: java


【解决方案1】:

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

类

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

接口

  • Iterable - 唯一可以在增强的 for 循环中使用的接口

荣誉奖:

  • java.lang.reflect.Array - 无法创建由 Class 对象定义的新数组。
  • 注解 它们是一种特殊的语言功能,在运行时表现得像一个界面。你当然不能定义另一个 Annotation 接口,就像你不能定义 Object 的替代品一样。但是,您可以实现它们的所有功能,并且只有另一种方法来检索它们(以及一大堆样板文件)而不是反射。事实上,在引入注解之前,已经有很多基于 XML 和基于 javadoc 标签的实现。
  • ClassLoader - 它当然与 JVM 有特权关系,因为没有语言方式来加载类,尽管有字节码方式,所以它就像 Array 那样。它还具有被 JVM 回调的特权,尽管这是一个实现细节。
  • Serializable - 您可以通过反射来实现该功能,但它有自己的特权关键字,在某些情况下您会花费大量时间来熟悉 SecurityManager。

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

数组是有争议的 - 它们继承 Object,具有可理解的层次结构(Object[] 是 String[] 的超类型),但它们是一种语言特性,而不是单独定义的类。

【讨论】:

  • @Donal,非常正确,我在考虑运行时注释,但源代码级别的注释确实是这样做的(xdoclet 最引人注目,甚至在带有@deprecated 的核心 java 中)
  • 我刚刚在一堆代码中奋力拼搏,这些代码最初是用 xdoclet 处理编写的,然后转换为注释。哦,我更喜欢注释(尽管使用合适的 maven 咒语,最终效果是一样的)。
  • @KK_07k11A0585,Collections 是一个标准的 api,任何人都可以用不同的方式构建(事实上,还有一些针对原语的替代实现,以及一个非常著名的谷歌项目来增强它们)。他们得到的唯一特别的是Iterable,答案中提到了。可以肯定,它们是 Java 编程的基础,但它们只是普通类,没有特殊权限。
  • @Yishai 在开发任何应用程序时,最重要的是数据管理。我们都可以用不同数量的方式来完成一项任务,但优化的方式是占用更少的内存并且使用更少的不必要的引用。通过使用集合,我们可以对大量数据进行排序、搜索和比较,它提供了预定义的算法,如二分搜索、合并排序等。它还为我们提供了比较器和可比较接口来定制我们的技术。 Collections类可能不是java中最好的类,但它无疑是一个美化的类。
  • SecurityManager 怎么样?或者任何与反射或序列化有关的东西?
【解决方案2】:

Class,当然。它有自己的文字(与String 的区别,顺便说一句),并且是所有反射魔法的起点。

【讨论】:

  • 啊,好点子。那么类文字的示例是什么?你指的是 MyClass.class 吗?
  • @aioobe:完全正确。请注意,您还有 int.class、char.class 等。
【解决方案3】:

sun.misc.unsafe 是所有肮脏、破坏语言精神的黑客之母。

【讨论】:

    【解决方案4】:
    1. 枚举。你不能继承它,但编译器可以。
    2. java.util.concurrent 下的许多东西可以在没有 JVM 支持的情况下实现,但效率会低很多。

    【讨论】:

    • 您可以匿名继承枚举(这是访问者模式实现的基础。枚举值)。但是,是的,你不能完全继承枚举 ;-)
    【解决方案5】:

    所有Number classes 都有一点Autoboxing 形式的魔力。

    【讨论】:

    • 您的意思是包装原语的类-还包括布尔值和字符;但不包括 BigInteger。
    • @emory:对,只是原始包装类。不幸的是,这不包括 BigInteger。
    【解决方案6】:

    既然提到了重要的类,我再提一些接口:

    Iterable 接口(从 1.5 开始) - 它允许对象参与 foreach 循环:

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

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

    【讨论】:

    • 没错,虽然它们是接口,但它们不需要任何“特殊”实现。 (类似于 Throwable。)
    • Serializable 实际上确实需要特殊实现。这是一个接口,你应该有两种方法(我忘记了名字......我可以谷歌它......)但它们不是必需的或在标准接口方案中定义。
    • @glowcoder:然而,曾经有人认为 Serializable 的所有特殊性都与 Java 语言无关,只与 ObjectOutputStream 和 ObjectInputStream 的实现有关。
    • @Michael Borgwardt - transient 关键字
    • 我不这么认为——Comparable 不参与任何内部事务。您可以轻松编写具有相同功能的NewComparable 和新的NewArrays.sort(..)
    【解决方案7】:
    1. 可抛出、RuntimeException、错误 断言错误
    2. 引用 WeakReference、SoftReference、PhantomReference
    3. 枚举
    4. 注释

    【讨论】:

    • 不错的清单。 +1,Annotation 虽然是一个接口,但没有实现。
    • 编译器对注解的处理方式与普通接口不同。与 enum 类似,它们都扩展了 Annotation,编译器会自动执行此操作。来自 Annotation 的 JavaDoc:所有注解类型扩展的公共接口。请注意,手动扩展此接口的接口未定义注释类型。另请注意,此接口本身并不定义注释类型。所以你不能使用正常的语法来创建注解,他们需要改变编译器来添加它们。
    【解决方案8】:

    int[].class 中的 Java 数组

    【讨论】:

    • 啊,好一个! [I 类;)虽然它不是 API 类。
    【解决方案9】:

    java.lang.ClassLoader,虽然实际的脏活是由一些未提及的子类完成的(参见12.2.1 The Loading Process)。

    【讨论】:

      【解决方案10】:

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

      【讨论】:

      • 你是对的,它们不能用纯Java实现。它们需要通过 JNI 实现(就像任何其他需要进行系统调用的类一样)。然而,除此之外,它们不需要编译器或 jvm 的特殊支持。
      【解决方案11】:

      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) {
         ...
      }
      

      【讨论】:

      • 嘿,你的第二部分答案是什么意思?
      【解决方案12】:

      好吧,既然已经提到了 assert 的特殊处理。以下是 jvm 特殊处理的更多异常类型:

      • NullPointerException
      • 算术异常。
      • 堆栈溢出异常
      • 各种OutOfMemoryErrors
      • ...

      异常并不特殊,只是jvm在特殊情况下使用,所以不自己写jvm是无法实现的。我敢肯定还有更多特殊的例外。

      【讨论】:

        【解决方案13】:

        这些类中的大多数并不是在编译器或 JVM 的“特殊”帮助下真正实现的。 Object 确实注册了一些在内部 JVM 结构周围戳的本机,但您也可以为自己的类这样做。 (我承认这是受语义的限制,“调用一个在JVM中定义的native”可以认为是对JVM的特殊支持。)

        /is/ 的特殊之处在于“new”和“throw”指令在初始化这些内部结构时的行为。

        注解和数字都非常怪异。

        【讨论】:

        • aioobe 是指您自己无法实现的类,因为它们具有特殊的内置支持。如果不继承 java.lang.Object 形式,就无法创建自己的 Object 类作为类型系统的根。 Object 得到编译器和 jvm 的特殊支持,以确保它是根类。本地调用不足以解决这个问题。
        猜你喜欢
        • 2012-03-15
        • 1970-01-01
        • 2013-03-26
        • 1970-01-01
        • 1970-01-01
        • 2018-11-12
        • 1970-01-01
        • 2013-01-31
        • 2012-03-30
        相关资源
        最近更新 更多