Java 将参数化类强制转换为参数的子类
有没有一种方法可以将某个超级类型的列表强制转换为子类型的列表?这似乎是可能的,因为如果您创建封装泛型列表的非泛型类型,则可以按预期进行强制转换。例如:Java 将参数化类强制转换为参数的子类,java,generics,casting,Java,Generics,Casting,有没有一种方法可以将某个超级类型的列表强制转换为子类型的列表?这似乎是可能的,因为如果您创建封装泛型列表的非泛型类型,则可以按预期进行强制转换。例如: class Foo {} class Bar extends Foo {} public class MyClass { public static void main(String[] args) { ArrayList<Foo> fooList = new ArrayList<>();
class Foo {}
class Bar extends Foo {}
public class MyClass {
public static void main(String[] args) {
ArrayList<Foo> fooList = new ArrayList<>();
fooList.add(new Bar());
// No can do. "Cannot cast from ArrayList<Foo> to ArrayList<Bar>"
// ArrayList<Bar> barList = (ArrayList<Bar>) fooList;
// Bar bar = barList.get(0);
FooList newAndImproveFooList = new FooList();
newAndImproveFooList.add(new Bar());
BarList barList = (BarList) newAndImproveFooList;
barList.get(0);
}
}
class FooList {
private ArrayList<Foo> list = new ArrayList<>();
// Simple delegates
public void add(Foo foo) { list.add(foo); }
public Foo get(int index) { return list.get(index); }
}
class BarList extends FooList {
public Bar get(int index) { return (Bar) super.get(index); }
}
class Foo{}
类栏扩展了Foo{}
公共类MyClass{
公共静态void main(字符串[]args){
ArrayList傻瓜列表=新的ArrayList();
添加(新条());
//不行。“无法从ArrayList转换到ArrayList”
//ArrayList barList=(ArrayList)傻瓜列表;
//Bar Bar=barList.get(0);
傻瓜主义者new和改良傻瓜主义者=新傻瓜主义者();
添加(newbar());
BarList BarList=(BarList)新建和修改列表;
获取(0);
}
}
阶级愚人{
private ArrayList list=new ArrayList();
//简单代表
public void add(Foo-Foo){list.add(Foo);}
public Foo-get(int-index){return list.get(index);}
}
类BarList扩展了愚人主义{
公共条get(int-index){return(Bar)super.get(index);}
}
这段代码的目的是显示这个铸造问题可以“轻松”解决。当然,我们可以强制转换不同类型的数组(因此,dublist
可以包含Foo
s而不是Bar
s这一事实不应该成为问题
似乎这个问题的唯一解决方案是不使用泛型,但接下来您必须为需要创建列表的每种类型创建此列表的实例,这正是泛型想要解决的问题
我们可以对列表的所有访问进行强制转换,但是当前程序的布局(并且不能轻易改变)将导致数千次强制转换,如果我们可以对列表进行强制转换,我们只需要在几个地方进行几次强制转换
我们不能复制列表,因为它在某些地方被修改。最简单的方法是做一些与
ArrayList<Bar> barList = (ArrayList<Bar>) (ArrayList<? extends Foo>) fooList;
但这并不意味着它是安全的。明智地使用它。泛型的一个要点是你不能强制转换。如果你正确地使用泛型,那么所有涉及的类型都可以静态地(足够接近地)确定 在您的特定情况下,您无法将
列表
强制转换为列表
,因为它可能包含Foo
s,而在强制转换时或稍后的某个时间它不是Bar
s。同样,您无法将列表
强制转换为列表
,因为这样就可以添加Foo
不是条形图
。类型参数并不是专门针对对象的当前状态;相反,它是对象类型的一个方面,影响所有可能的当前和未来状态的空间
您可以通过使用裸类型而不是参数化类型来完全避免类型安全检查,这是正确的。如果参数化妨碍了您的工作,那么这也许是您应该做的,但这是代码脆弱性的标志(因为您的代码依赖于无法静态检查的假设)
您可以通过使用纯中间类型在不兼容的参数化类型之间进行强制转换来击败类型检查(以牺牲一些警告为代价),但这并不意味着您应该这样做,也不意味着Java应该接受不兼容类型之间的直接强制转换
对于遗留代码,您可以使用类型边界和协变返回类型至少取得一些进展:
abstract class Thing {
public List<? extends Thing> getAgentList() {
return Collections.<Thing>emptyList();
}
public List<? extends Thing> getHouseholdList() {
return Collections.<Thing>emptyList();
}
}
class Agent extends Thing {
public List<Agent> getAgentList() {
// ...
}
}
class Household extends Thing {
public List<Household> getHouseholdList() {
// ...
}
}
P>个人,只要你正在处理这段代码,我会考虑利用这个机会把整个混乱情况转化成一点不那么复杂的事情。你可以用通配符做一些转换,然后用具体的类型来做,但是这会引发各种各样的警告。你为什么要这么做?只是为了<代码> CasasStExcExc< <代码>当试图查询
列表中的元素时,
?@SotiriosDelimanolis,我想你的意思是像ArrayListRight一样,这就是编译时类型检查的目的。你试图做什么?@SotiriosDelimanolis,仔细想想,我可以转换到特定的类型(这是众所周知的)当通过getter访问列表并修改该强制转换列表时。只有getter才会强制转换。@SotiriosDelimanolis,至于我所做的,这是一个遗留代码,其中一组类扩展了一个抽象类。抽象类声明了获取这些扩展类的列表的方法(getAgentList()
,getHouseholdList()
,等等),但正在返回其超类的列表(但您希望得到子类)。超类是由(1)遗留代码混乱和(2)具有超类类型的“子代理
”的某个共享字段返回的(因为每个子类的类型不同).简短回答:遗留代码。
abstract class Thing {
public List<? extends Thing> getAgentList() {
return Collections.<Thing>emptyList();
}
public List<? extends Thing> getHouseholdList() {
return Collections.<Thing>emptyList();
}
}
class Agent extends Thing {
public List<Agent> getAgentList() {
// ...
}
}
class Household extends Thing {
public List<Household> getHouseholdList() {
// ...
}
}
abstract class Thing {
public List<Agent> getAgentList() {
return Collections.<Agent>emptyList();
}
public List<Household> getHouseholdList() {
return Collections.<Household>emptyList();
}
}