【问题标题】:Java Raw Types (ex. List vs List<Object> )Java 原始类型(例如 List 与 List<Object> )
【发布时间】:2015-12-27 04:08:25
【问题描述】:

我们的应用程序有数百条警告“xxx 是原始类型。对泛型类型 xxx 的引用应该被参数化”

我的问题,在那些没有指定类型的地方简单地将类型设置为 Object 是否安全?

一些例子:

List list = new List();
Iterator i;

改为:

List<Object> = new ArrayList<Object>();
Iterator<Object> i;

【问题讨论】:

  • 那是等价的,不是吗?
  • 如果你在生产环境中运行Java 1.5或更高版本,这是完全可以的
  • btw new List() 是错误的。您不能实例化抽象类或接口。
  • 我会说是的,它是安全的,但另一方面。你有Object的列表有什么好的理由吗
  • 存在差异。但对于List,它大多工作正常。

标签: java list object generics collections


【解决方案1】:

是的,这将达到相同的结果,因为Object 位于继承链的顶部,而原始类型充当Object 类型。

唯一需要注意的是,您随后需要使用 Java 5 或更高版本进行编译和运行。

您可以随时@SuppressWarnings("rawtypes") 否则。

【讨论】:

  • OP 询问执行这种“简单”更改是否安全。我怀疑是这样,正是因为警告是建议他/她谨慎选择类型,而不是一般。
  • @LittleSanti 它安全的,因为它是等价的。我并不是说将参数化类型更改为 Objects 在功能上是理想的(而不是使用正确的类型),只是它是安全的。
  • 我在我的帖子中包含了一段说明为什么用显式对象类型替换原始类型并不总是安全的。
【解决方案2】:

如果所有您对List(和其他可泛化的类)的使用都是原始使用,是的,它是安全的。

如果您的代码将通用定义与原始定义混合在一起,您必须谨慎行事。可以使用原始类代替任何通用类,但反之则不行。因此,例如,如果您有一个带有 List&lt;String&gt; 参数的方法,而您当前正在将原始 List 传递给该方法,则将其更改为 List&lt;Object&gt; 会破坏您的编译。

【讨论】:

    【解决方案3】:

    如果泛型变量是类型绑定的,这并不总是可能的。比如你有MyType&lt;T extends Number&gt;,把MyType替换成MyType&lt;Object&gt;会导致编译错误。

    另请注意,添加 &lt;Object&gt; 只是消除警告,实际上并没有使您的代码更安全。

    【讨论】:

    • @bayou.io,可能会出现更复杂的情况。例如MyType&lt;T extends Number&gt; implements List&lt;T&gt;,所有列表都已转换为List&lt;Object&gt;
    • 那么问题就变成了强制MyType转换为List&lt;Object&gt;是否安全......
    【解决方案4】:

    完全没问题,但是如果列表包含不同类型的值(即带有字符串的布尔值),您的代码中可能会出现转换错误。简单的例子:如果你添加一个布尔值和一个字符串,当你尝试在控制台上打印它时,你会得到ClassCastException

    List l = new ArrayList();
    l.add("My string"); // Completely fine!
    l.add(true); // fine
    System.out.println(l.get(0)); // will output 'My string'
    System.out.println(l.get(1)); // will raise ClassCastException
    

    【讨论】:

      【解决方案5】:

      没有。因为 Object 在功能上不能用于任何事情。即使您将原始类型转换为基于对象的类型,迟早在您的代码中,您仍需要执行强制转换以将这些普通对象转换为您的程序中更有意义的东西。而泛型的构思正是为了让程序员避免在代码中进行强制转换,因为强制动态地执行了强制转换(所以,如果它失败了,你不会注意到,直到执行)。相反,在编译期间检查泛型类型,确保程序中的所有类型都是一致的,并且在执行过程中不会产生任何 ClassCastExceptions。

      为什么用显式对象类型替换原始类型并不总是安全的:

      假设我们有一个老式的容器:

      public class MyProvider
      {
          private List list;
      
          public List getList()
          {
              return list;
          }
      
          public void setList(List list)
          {
              this.list=list;
          }
      }
      

      还有一个客户端类(它可能在另一个库中并且依赖于您的代码,但仍然不受您的控制):

      public class MyClient
      {
          public void test()
          {
              MyProvider provider=new MyProvider();
              List<String> myList1=new ArrayList<String>();
              provider.setList(myList1);
              List<String> myList2=provider.getList();
          }
      }
      

      这个方案在提供者和客户端都产生警告,仍然可以编译和执行。

      但如果我们将提供者的公共 API 更改为基于对象:

      public class MyProvider
      {
          private List<Object> list;
      
          public List<Object> getList()
          {
              return list;
          }
      
          public void setList(List<Object> list)
          {
              this.list=list;
          }
      }
      

      ...提供者部分将放弃所有警告并编译正常,但客户端部分将出现编译错误

      道德:如果您无法控制某些依赖的第三方代码,切勿更改公共 API。

      【讨论】:

        猜你喜欢
        • 2021-09-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-15
        • 1970-01-01
        • 2023-03-14
        • 2018-11-12
        相关资源
        最近更新 更多