Java 类不能向下转换为具有相同字段的直接子类
我正在制作一个包含几个扑克牌类的包,它们之间的区别在于,它们在自然顺序方面有不同的自由Java 类不能向下转换为具有相同字段的直接子类,java,clone,Java,Clone,我正在制作一个包含几个扑克牌类的包,它们之间的区别在于,它们在自然顺序方面有不同的自由DefaultCard具有“默认顺序”(ace high,2
DefaultCard
具有“默认顺序”(ace high,2<3<4<…ConstantOrderingCard
允许通过构造函数设置顺序,但实例化后不能更改<代码>VariableOrderingCard允许在实例化期间和之后设置排序
类层次结构如下所示:
[AbstractCard] [Joker]
/ \
[DefaultCard] [ConstantOrderingCard]
\
[VariableOrderingCard]
为了更容易地复制数据组,我让所有这些类实现了Cloneable
,并重写了它们的clone
方法AbstractCard
、DefaultCard
和Joker
没有可变的引用类型字段,因此我用同样非常简单的方式对它们进行了重写。这就是我所做的(我以AbstractCard为例):
由于ConstantOrderingCard
确实有可变的引用类型字段,因此我返回了一个显式副本VariableOrderingCard
没有未从ConstantOrderingCard
继承的字段;它包含的都是setter。所以,我想我可以调用ConstantOrderingCard.clone,然后像上面一样向下播放它。每个类的clone
方法,但是VariableOrderingCard
编译没有错误,并且在运行时工作得很好,但是VariableOrderingCard
给了我一个ClassCastException
,说我不能将ConstantOrderingCard
转换为VariableOrderingCard
。我不知道为什么会这样,因为它没有定义自己的领域,尤其是因为它对所有其他领域都有效。对此有任何见解都将不胜感激
以下是ConstantOrderingCard
的clone
方法:
@Override
protected ConstantOrderingCard clone() throws CloneNotSupportedException
{
if (rankOrdering != DEFAULT_RANK_ORDERING &&
suitOrdering != DEFAULT_SUIT_ORDERING)
{
int[] rankOrderingCopy = rankOrdering.values().stream().mapToInt(
Integer::intValue).toArray();
int[] suitOrderingCopy = suitOrdering.values().stream().mapToInt(
Integer::intValue).toArray();
return new ConstantOrderingCard(RANK, SUIT, rankOrderingCopy,
suitOrderingCopy, compareSuitsFirst);
}
else if (rankOrdering != DEFAULT_RANK_ORDERING)
{
int[] rankOrderingCopy = rankOrdering.values().stream().mapToInt(
Integer::intValue).toArray();
return new ConstantOrderingCard(RANK, SUIT, rankOrderingCopy,
compareSuitsFirst);
}
else if (suitOrdering != DEFAULT_SUIT_ORDERING)
{
int[] suitOrderingCopy = suitOrdering.values().stream().mapToInt(
Integer::intValue).toArray();
return new ConstantOrderingCard(RANK, SUIT, suitOrderingCopy,
compareSuitsFirst);
}
else
{
return new ConstantOrderingCard(RANK, SUIT, compareSuitsFirst);
}
}
@Override
protected VariableOrderingCard clone() throws CloneNotSupportedException
{
return (VariableOrderingCard)super.clone();
}
下面是VariableOrderingCard
的克隆方法:
@Override
protected ConstantOrderingCard clone() throws CloneNotSupportedException
{
if (rankOrdering != DEFAULT_RANK_ORDERING &&
suitOrdering != DEFAULT_SUIT_ORDERING)
{
int[] rankOrderingCopy = rankOrdering.values().stream().mapToInt(
Integer::intValue).toArray();
int[] suitOrderingCopy = suitOrdering.values().stream().mapToInt(
Integer::intValue).toArray();
return new ConstantOrderingCard(RANK, SUIT, rankOrderingCopy,
suitOrderingCopy, compareSuitsFirst);
}
else if (rankOrdering != DEFAULT_RANK_ORDERING)
{
int[] rankOrderingCopy = rankOrdering.values().stream().mapToInt(
Integer::intValue).toArray();
return new ConstantOrderingCard(RANK, SUIT, rankOrderingCopy,
compareSuitsFirst);
}
else if (suitOrdering != DEFAULT_SUIT_ORDERING)
{
int[] suitOrderingCopy = suitOrdering.values().stream().mapToInt(
Integer::intValue).toArray();
return new ConstantOrderingCard(RANK, SUIT, suitOrderingCopy,
compareSuitsFirst);
}
else
{
return new ConstantOrderingCard(RANK, SUIT, compareSuitsFirst);
}
}
@Override
protected VariableOrderingCard clone() throws CloneNotSupportedException
{
return (VariableOrderingCard)super.clone();
}
Object.clone始终创建与被克隆对象相同的类的实例,但您在ConstantOrderingCard中实现的clone()未使用Object.clone,因此不会出现Java系统级的“魔术”new ConstantOrderingCard
始终创建ConstantOrderingCard的实例,而不创建其他实例
另一种方法是继续使用Object.clone,然后让您的自定义clone
方法考虑需要深度复制的字段:
@Override
protected ConstantOrderingCard clone() throws CloneNotSupportedException
{
ConstantOrderingCard copy = (ConstantOrderingCard) super.clone();
copy.rankOrdering = new HashMap<>(copy.rankOrdering);
copy.suitOrdering = new HashMap<>(copy.suitOrdering);
return copy;
}
@覆盖
受保护的ConstantOrderingCard克隆()引发CloneNotSupportedException
{
ConstantOrderingCard copy=(ConstantOrderingCard)super.clone();
copy.rankOrdering=新哈希映射(copy.rankOrdering);
copy.suiteordering=新HashMap(copy.suiteordering);
返回副本;
}
(您还没有显示ConstantOrderingCard类的其余部分,因此我不确定这是否足够,但您已经明白了。)Object.clone始终创建与被克隆对象相同的类的实例,但ConstantOrderingCard中clone()的实现没有使用Object.clone,因此没有Java系统级别“魔法”正在发生。新建ConstantOrderingCard
始终创建ConstantOrderingCard的实例,而不创建其他实例
另一种方法是继续使用Object.clone,然后让您的自定义clone
方法考虑需要深度复制的字段:
@Override
protected ConstantOrderingCard clone() throws CloneNotSupportedException
{
ConstantOrderingCard copy = (ConstantOrderingCard) super.clone();
copy.rankOrdering = new HashMap<>(copy.rankOrdering);
copy.suitOrdering = new HashMap<>(copy.suitOrdering);
return copy;
}
@覆盖
受保护的ConstantOrderingCard克隆()引发CloneNotSupportedException
{
ConstantOrderingCard copy=(ConstantOrderingCard)super.clone();
copy.rankOrdering=新哈希映射(copy.rankOrdering);
copy.suiteordering=新HashMap(copy.suiteordering);
返回副本;
}
(您还没有显示ConstantOrderingCard类的其余部分,所以我不确定这是否足够,但您已经明白了。)在继承层次结构中,VariableOrderingCard是ConstantOrderingCard,但这并不意味着ConstantOrderingCard是VariableOrderingCard
调用ConstantOrderingCard.clone()时,将创建ConstantOrderingCard类型的对象。如果子类型的对象具有超类型的引用,则可以进行向下转换。不幸的是,在这种情况下,您具有超类型的对象
假设您创建了一个字符串并将其存储为对象引用:
//will compile
Object o = new String("hello world");
String s = (String) o;
但是,VariableOrderingCard引用只能用于VariableOrderingCard对象
//will also compile
ConstantOrderingCard c = new VariableOrderingCard(...);
VariableOrderingCard v = (VariableOrderingCard) c;
但是,调用super.clone()会创建ConstantOrderingCard类型的对象,相当于:
//not gonna compile
VariableOrderingCard v = (VariableOrderingCard) new ConstantOrderingCard(...);
有关此主题的完整文章:
在继承层次结构中,VariableOrderingCard是一个ConstantOrderingCard,但这并不意味着ConstantOrderingCard是一个VariableOrderingCard
调用ConstantOrderingCard.clone()时,将创建ConstantOrderingCard类型的对象。如果子类型的对象具有超类型的引用,则可以进行向下转换。不幸的是,在这种情况下,您具有超类型的对象
假设您创建了一个字符串并将其存储为对象引用:
//will compile
Object o = new String("hello world");
String s = (String) o;
但是,VariableOrderingCard引用只能用于VariableOrderingCard对象
//will also compile
ConstantOrderingCard c = new VariableOrderingCard(...);
VariableOrderingCard v = (VariableOrderingCard) c;
但是,调用super.clone()会创建ConstantOrderingCard类型的对象,相当于:
//not gonna compile
VariableOrderingCard v = (VariableOrderingCard) new ConstantOrderingCard(...);
有关此主题的完整文章:
super.clone()
返回使用新ConstantOrderingCard(…)
创建的ConstantOrderingCard
,因此在运行时它不是VariableOrderingCard
,无法强制转换,错误是正常的
使用Java8,您可以这样做来动态创建所需类型的对象(我复制了一个类似的层次结构,只保留了基本的部分,为重要的类提供了虚拟字段,您会明白的