类型安全:从 Object 到 List<MyObject> 的未经检查的强制转换
Posted
技术标签:
【中文标题】类型安全:从 Object 到 List<MyObject> 的未经检查的强制转换【英文标题】:Type safety: Unchecked cast from Object to List<MyObject> 【发布时间】:2022-02-03 10:43:38 【问题描述】:我有一个 ListView 列出了一个自定义对象(比如说MyObject
)。
我想通过 EditText
动态过滤它,所以我必须使用 publishResults 方法实现 getFilter()
:
@Override
protected void publishResults(CharSequence constraint, FilterResults results)
MyObjectAdapter.this.setItems((List<MyObject>) results.values);
MyObjectAdapter.this.notifyDataSetChanged();
此时,Eclipse 报错:Type safety: Unchecked cast from Object to List<MyObject>
我确信这个演员表永远是正确的,但 Eclipse 只建议添加@SuppressWarnings("unchecked")
,但我完全反对SuppressWarnings
,因为它只是隐藏问题,而不是解决方案......
我尝试添加:
if(results.values instanceof List<MyObject>)
但是 Eclipse 再次抱怨,这并没有解决任何问题......
Cannot perform instanceof check against parameterized type List<MyObject>. Use the form List<?>
我知道强制转换总是正确的,但这是确保results.values
实际上是List<MyObject>
的正确方法?
提前致谢!
【问题讨论】:
***.com/questions/262367/type-safety-unchecked-cast 【参考方案1】:如果您只需要使用Object
,那么您就无法在运行时检查您实际上是否拥有List<MyObject>
,因为泛型类型MyObject
仅用于编译时类型检查,它在运行时不可用。这就是您尝试添加instanceof
检查时收到错误的原因。
如果您确定您的 Object
确实始终是 List<MyObject>
,那么我会说 @SuppressWarnings
没问题,如果您记录了为什么您确定这不是问题。
如果您绝对想避免警告,您可以创建自己的List
实现(例如MyObjectList
),它本身不是通用的,但实现了List<MyObject>
。然后您可以在运行时对MyObjectList
进行instanceof
检查。
另一个选项是检查 List<?>
并将其转换为 instanceof
错误提示。然后您可以遍历列表中的元素并检查它们是否实际上都是 MyObject 的所有实例,并将它们复制到新的List<MyObject>
。
【讨论】:
【参考方案2】:嗯,我终于找到了解决办法。
正如@Medo42 所说:
另一种选择是检查并转换为 List 作为 instanceof 错误提示。然后您可以遍历列表中的元素并 检查它们是否实际上是 MyObject 的所有实例,并将它们复制到 一个新的列表。
尽管我没有经历过创建一个全新对象的过程以使这个特殊情况“无警告”地工作,但这是正确的方向。
所以我采用了@lokoko 的想法并将其用于新的setItems()
方法,使用Object
参数而不是List<MyObject>
以确保
结果代码如下:
public void setItems(List<MyObject> var)
this.list = var;
public void setItems(Object var)
List<MyObject> result = new ArrayList<MyObject>();
if (var instanceof List)
for(int i = 0; i < ((List<?>)var).size(); i++)
Object item = ((List<?>) var).get(i);
if(item instanceof MyObject)
result.add((MyObject) item);
setItems(result);
感谢大家的帮助!
【讨论】:
【参考方案3】:试试这样的:
List<?> result = (List<?>) results.values;
for (Object object : result)
if (object instanceof MyObject)
tempList.add((MyObject) object); // <-- add to temp
filteredItems = tempList; // <-- set filtered
【讨论】:
您的解决方案帮助我弄清楚如何解决我的问题,谢谢!【参考方案4】:您可以在将其传递给setItems()
之前执行检查。
final Object myListObj = reuslts.values;
if(myListObj instanceof List<?>)
if(((List<?>)myListObj).get(0) instanceof MyObject)
// You can safely suppress the warning here because you made sure it is a List containing MyObject
MyObjectAdapter.this.setItems((List<? extends MyObject>) myListObj);
但是,您需要相应地更改您的 setItems()
方法:
public void setItems(List<? extends MyObject> list)
// Your code here
【讨论】:
这个检查只确保列表中的第一个对象是MyObject
,所以你唯一显示的是列表可以 包含这样的元素 - 并不是它实际上是 List<MyObject>
甚至是 List<? extends MyObject>
。相反,您已经证明它是List<? super MyObject>
。
你是对的。但是,List<String>
永远不能包含Integer
的元素,对吧?如果MyObject
没有子类,这很好用。即使extends MyObject
中的对象,它们都包含MyObjectAdapter
所需的必要接口或函数,因为方法签名声明了MyObject
,而不是其他子类。
从技术上讲,List<String>
可以包含Integer
,因为在运行时不强制执行列表的泛型类型。但即使你有这样的保证,即使MyObject
没有子类,你的建议也是无效的。想象一个List<Object>
包含一个MyObject
和一个字符串。您的检查会将其转换为List<? extends MyObject>
,因为第一个元素恰好是MyObject
,但试图通过该转换列表获取第二个元素会导致ClassCastException
。以上是关于类型安全:从 Object 到 List<MyObject> 的未经检查的强制转换的主要内容,如果未能解决你的问题,请参考以下文章
怎样从jsp页面传递一个List<Map<String,Object>>的集合到Action
ArrayList和List主要区别 就是ArrayList类型不安全。
为啥我不能从 List<MyClass> 转换为 List<object>?