【问题标题】:Type safety: Unchecked cast from Object to List类型安全:从对象到列表的未经检查的强制转换
【发布时间】:2014-11-17 16:16:16
【问题描述】:
SqlOutParameter out = new SqlOutParameter("out_refcursor",OracleTypes.CURSOR
                                           ,new StudentRowMapper());

// 一些代码..

MapSqlParameterSource parameters = createMapSqlParameterSource();
parameters.addValue("in_studentid","101"); 

Map<String, Object> result = simpleJdbcCall.execute(parameters);
List<Student> students = (List<Student>) result.get("out_refcursor"); // here I get a warning

execute()方法的定义:

Map<String, Object> org.springframework.jdbc.core.simple.SimpleJdbcCall.execute(SqlParameterSource parameterSource)

“执行存储过程并返回输出参数的映射,按参数声明中的名称作为键..”

上一行的警告:List&lt;Student&gt; students = (List&lt;Student&gt;) result.get("out_refcursor"); 是:

类型安全:从对象到列表的未经检查的强制转换

我知道这只是一个编译时警告,当然我可以通过@SuppressWarnings("unchecked") 来抑制它。

问题:但是我该如何正确地投射它呢?

  1. 我尝试过的一种方法是

    List<Student> students = castObject( result.get("out_refcursor"));
    
    @SuppressWarnings("unchecked")
        private static <T extends List<?>> T castObject(Object obj){
        return (T)obj;
    }
    

我仍然必须将@SuppressWarnings("unchecked") 放入castObject() 方法中。而且我不知道这是否是正确的做法。

  1. 我尝试的第二种方法是,

    List<?> students = castObject( result.get("out_refcursor"));
    
    Student student = (Student)students.get(0);
    
    private static <T extends List<?>> List<?> castObject(Object obj){
          if(obj instanceof List<?>) {
               return (List<Student>)obj;
          }
          return null;
     }
    

欢迎任何建议/建议。

【问题讨论】:

  • 如果你知道返回的值是List&lt;Student&gt;,那就没问题了。
  • 第一种方法很好,如果你知道它总是返回 List 如果你不确定它会返回什么,你应该使用你的第三种方法......
  • 我知道它总是会返回List&lt;Student&gt;,所以在这种情况下放置@SupressWarnings("unchecked") 是干净的编码吗?第三种方法也可以避免警告,但我觉得代码太多

标签: java generics


【解决方案1】:

只要您知道List 元素的类名,类似的事情就可以工作。这里有一个问题,硬编码的ArrayList 实例化。

public static <T> List<T> castList(Object obj, Class<T> clazz)
{
    List<T> result = new ArrayList<T>();
    if(obj instanceof List<?>)
    {
        for (Object o : (List<?>) obj)
        {
            result.add(clazz.cast(o));
        }
        return result;
    }
    return null;
}

用法:

List<Student> students = castList(result.get("out_refcursor"), Student.class);

【讨论】:

  • +1 表示通用castList() 以供我理解
【解决方案2】:

您的第二个解决方案无济于事(由于Type Erasure),并且还会导致其他问题,因此可能不是一个好主意。

第一种方法在实践中可能会奏效,但确实有点狡猾。在Java 中子类化泛型类型子类化它们的参数之间有一个微妙(但巨大)的区别——即ArrayList&lt;Integer&gt;不是ArrayList&lt;Object&gt;的子类,而是@ 987654326@ 是Collection&lt;String&gt; 的子类型:参见a more fun example。更正式的计算机科学背景Wikipedia entry on Covariance

因此,IMO 您应该将铸件保留在那里,保留(必要的)注释,并捕获 ClassCastException 以确保涵盖异常(因此得名)案例。

【讨论】:

  • 感谢您提供的所有参考资料。但是我怎样才能将其保留为List&lt;Object&gt;,因为result.get("out_refcursor") 返回Object 而不是对象列表
  • 哦对,误会了,抱歉。我认为您不妨立即将其转换为 List&lt;Student&gt; 并直接在调用中保留注释(可能会评论为什么它是安全的),因为其他方法并不能使它更安全,或者删除警告.如果您愿意,您可以随时捕获ClassCastException 并处理那个实际错误情况...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-02-03
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 2015-06-20
  • 1970-01-01
相关资源
最近更新 更多