Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/396.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么openjdk使用不安全的构造?_Java_Generics_Openjdk_Raw Types - Fatal编程技术网

Java 为什么openjdk使用不安全的构造?

Java 为什么openjdk使用不安全的构造?,java,generics,openjdk,raw-types,Java,Generics,Openjdk,Raw Types,通过阅读openjdk7的一些代码,我发现方法Collections.reverse实现为(我删除了一些对随机访问列表的优化): 公共静态无效反向(列表){ int size=list.size(); ListIterator fwd=list.ListIterator(); ListIterator rev=list.ListIterator(大小); 对于(int i=0,mid=list.size()>>1;i>1;i

通过阅读openjdk7的一些代码,我发现方法Collections.reverse实现为(我删除了一些对随机访问列表的优化):

公共静态无效反向(列表){
int size=list.size();
ListIterator fwd=list.ListIterator();
ListIterator rev=list.ListIterator(大小);
对于(int i=0,mid=list.size()>>1;i
ListIterator的两个初始化都会生成未检查的警告(代码中没有@SupersWarnings选项)

对我来说,节省和简单的实施方法是:

public static <E> void reverse2(List<E> list) {
    int size = list.size();
    ListIterator<E> fwd = list.listIterator();
    ListIterator<E> rev = list.listIterator(size);
    for (int i = 0, mid = list.size() >> 1; i < mid; i++) {
        E tmp = fwd.next();
        fwd.set(rev.previous());
        rev.set(tmp);
    }
}
publicstaticvoidreverse2(列表){
int size=list.size();
ListIterator fwd=list.ListIterator();
ListIterator rev=list.ListIterator(大小);
对于(int i=0,mid=list.size()>>1;i
这是完全安全的

我的问题是:

  • 为什么openjdk使用原始类型的不安全代码
  • 为什么警告没有被抑制

    • 这是一种权衡。JDK开发人员接受一个警告,以减少对其他开发人员的警告。如果您使用
      列表编译旧代码,即作为原始类型,则可以将其传递给
      集合。reverse()
      ,而不发出警告,因为这是安全的。但是,如果
      Collections.reverse()
      具有类似于
      public static void reverse(List List)
      的类型参数,则在尝试使用原始类型
      List

      FWIW调用它时,您会收到一条警告,我在泛型常见问题解答中找到了答案:


      从概念上讲,
      reverse()
      只接受任何参数的
      列表。它根本不在乎,也不需要将参数与其他类型关联。因此,
      void reverse(List)
      是最简单(因此也是最好)的签名

      现在,为了在泛型中正确地编写它,在
      reverse
      的实现中,需要使用列表的type参数,因为我们需要从列表中获取一个元素,并将其放回,我们需要一个类型来表示这个临时值

      在Java中实现这一点的唯一方法是为整个方法声明一个泛型参数,使其成为一个泛型方法,就像您的
      reverse2
      所做的那样:
      void reverse2(List List)

      但是,这会更改签名(外部可见)。此处的
      E
      仅用于参数中的一个位置,从类型的角度来看基本上是不必要的。我们需要在内部使用
      E
      这一事实是外部代码不需要关心的实现细节

      有一种方法可以做到这一点,它使用完全安全的构造并保留签名
      void reverse(List)
      :使用捕获助手。i、 e.创建一个helper方法,它接受
      列表
      ,它所做的只是调用泛型方法(然后可以将泛型方法设置为私有):

      公共静态无效反向(列表){
      2(清单);
      }
      
      (如果您不理解为什么在泛型下这是正确的,请提示:这是由于捕获。)

      尽管这似乎是两全其美(更简单的签名+安全构造),但缺点是,从运行时的角度来看,这是一种浪费。我们有一个取一个参数的方法,它所做的只是将它直接传递给另一个取一个参数的方法。这似乎完全无关。在类型擦除之后——您将有一个方法使用
      List
      调用另一个方法使用
      List
      。(如果我向您展示了这样一个函数,而您不知道泛型,您可能会立即认为它是不必要的。)


      因此,为了提高效率,他们决定牺牲内部代码中完全安全的结构,以保留更简单的签名和单个函数调用而不是两个函数调用的效率。他们使用的构造无论如何都在内部代码中,因此除了Java库开发人员之外,没有人应该关心它;在类型擦除之后,代码与安全代码完全相同,因此二进制代码不会有任何差异。然而,编译代码的签名和效率都会影响库的用户。

      我认为关键在于避免命名类型变量。谢谢。这很有道理。
      public static <E> void reverse2(List<E> list) {
          int size = list.size();
          ListIterator<E> fwd = list.listIterator();
          ListIterator<E> rev = list.listIterator(size);
          for (int i = 0, mid = list.size() >> 1; i < mid; i++) {
              E tmp = fwd.next();
              fwd.set(rev.previous());
              rev.set(tmp);
          }
      }
      
      public static void reverse(List<?> list) {
          reverse2(list);
      }