gpt4 book ai didi

java - 在这个 Java 类层次结构中,如何使用泛型来避免类型转换?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:44:27 26 4
gpt4 key购买 nike

假设我有 2 个名为 RealNumber 的类和 IntNumber ,以及一个名为 plus 的方法:

public class RealNumber<S extends RealNumber> {
public S plus(S realNumber) {
...
}
}

public class IntNumber
extends RealNumber<IntNumber> { }

使用 plus 时方法我得到一些编译器警告和错误:

RealNumber x = new RealNumber();
IntNumber y = new IntNumber();

RealNumber sum1 = x.plus(x); // Warning: Unchecked call to 'plus(S)' as a member of raw type 'RealNumber'.
RealNumber sum2 = x.plus(y); // Warning: Unchecked call to 'plus(S)' as a member of raw type 'RealNumber'.
RealNumber sum3 = y.plus(x); // Error: plus (IntNumber) in RealNumber cannot be applied to (RealNumber).
RealNumber sum4 = y.plus(y); // This works fine.
IntNumber sum5 = y.plus(x); // Error: plus (IntNumber) in RealNumber cannot be applied to (RealNumber).
IntNumber sum6 = y.plus(y); // This works fine.

为了解决这个问题,我修改了 plus方法,如下:

public <T extends RealNumber> S plus(T realNumber) {
...
}

现在一切正常。好的!但是,我现在想添加一个名为 PositiveIntNumber 的第三类延伸 IntNumber :

    public class PositiveIntNumber extends IntNumber { }

这当然行不通:

RealNumber x = new RealNumber();
IntNumber y = new IntNumber();
PositiveIntNumber z = new PositiveIntNumber();

RealNumber sum1 = x.plus(x); // Fine.
RealNumber sum2 = x.plus(y); // Fine.
RealNumber sum3 = y.plus(x); // Fine.
RealNumber sum4 = y.plus(y); // Fine.
IntNumber sum5 = y.plus(x); // Fine.
IntNumber sum6 = y.plus(y); // Fine.
RealNumber sum7 = x.plus(z); // Fine.
IntNumber sum8 = y.plus(z); // Fine.
PositiveIntNumber sum9 = z.plus(x); // Error: incompatible types: no instance(s) of type variable(s) T exist so that IntNumber conforms to PositiveIntNumber
PositiveIntNumber sum10 = z.plus(y); // Error: incompatible types: no instance(s) of type variable(s) T exist so that IntNumber conforms to PositiveIntNumber
PositiveIntNumber sum11 = z.plus(z); // Error: incompatible types: no instance(s) of type variable(s) T exist so that IntNumber conforms to PositiveIntNumber

为了再次解决这个问题,我修改了类定义,如下所示:

public class IntNumber<S extends IntNumber>
extends RealNumber<S> { }

public class PositiveIntNumber
extends IntNumber<PositiveIntNumber>
{ }

这解决了 PositiveIntNumber 的问题, 但打破了 IntNumber :

RealNumber x = new RealNumber();
IntNumber y = new IntNumber();
PositiveIntNumber z = new PositiveIntNumber();

RealNumber sum1 = x.plus(x); // Fine.
RealNumber sum2 = x.plus(y); // Fine.
RealNumber sum3 = y.plus(x); // Fine.
RealNumber sum4 = y.plus(y); // Fine.
IntNumber sum5 = y.plus(x); // Error: incompatible types: RealNumber cannot be converted to IntNumber.
IntNumber sum6 = y.plus(y); // Error: incompatible types: RealNumber cannot be converted to IntNumber.
RealNumber sum7 = x.plus(z); // Fine.
IntNumber sum8 = y.plus(z); // Error: incompatible types: RealNumber cannot be converted to IntNumber.
PositiveIntNumber sum9 = z.plus(x); // Fine.
PositiveIntNumber sum10 = z.plus(y); // Fine.
PositiveIntNumber sum11 = z.plus(z); // Fine.

转换修复它,但在我看来它应该是不必要的:

IntNumber sum5 = (IntNumber)y.plus(x);

所以,我有两个问题:

1) 自 y是一个 IntNumber , 和返回类型 S延伸IntNumber ,为什么 y.plus(...) 返回 RealNumber

2) 如何解决这个问题?

编辑:写作RealNumber<RealNumber>应该是不必要的,因为 RealNumber<IntNumber>RealNumber<PositiveIntNumber>完全没有意义。所以也许像这样使用泛型是完全错误的。我认为这回答了问题 1:y.plus(...)返回 RealNumber因为 y 是原始的,所以 Java 类型系统不再关心 S延伸IntNumber .但是,我想避免重复 plus RealNumber 的所有子类中的方法,我应该能够以某种方式使用泛型来避免这种情况。所以问题2仍然成立。我应该做什么?

注意:我的实际类不是Reals和Integers,而是其他一些复杂的业务类。将它们视为 A、B、C 类,不要质疑模型。它们是“可添加的”,是的,但是这里 X.plus(Y) 应该为每个 X 和 Y 返回类型 X。

最佳答案

我假设您要创建的是一个类型层次结构,它表示“Addables”,它返回给定两个“操作数”,两者中更通用的一个,使用继承来模拟“特殊情况”的数学关系.

在我继续之前,你应该考虑 this link它使用 Square is-a Rectangle 示例来说明为什么使用继承通常不是一个好主意,但对于像您提议的不可变对象(immutable对象),您可能没问题。

您希望 Int.plus( Real ) 和 Real.plus( Int ) 都返回 Real,并且 Int.plus( Int ) 返回 Int。相同的模式应该适用于 Nat.plus( Int ) 等。

只要所有类型都是静态已知的,那在类型方面应该是小菜一碟。

class Real {
Real plus( Real r ) { ... }
Int floor() { ... }
}
class Int extends Real {
Int plus( Int i ) {
return plus( i.asReal() ).floor();
}
Nat abs() { ... }
Real asReal() {
return this;
}
}
class Nat extends Int {
Nat plus( Nat n ) {
return plus( n.asInt() ).abs();
}
Int asInt() {
return this;
}
}

重载 plus 允许编译器确定可以静态验证的“最具体”的加操作。编译器不知道将两个恰好是整数的实数相加会得到另一个整数实数。就此而言,一些非整数加起来就是整数;我确定您不打算让类型系统以某种方式表示该事实。

在这种安排下,除了 sum5sum9sum10 之外的所有类型检查,这(在我看来)完全正确是。

顺便说一下,关于您试图演示的“奇怪的重复类型约束”模式,您做的有点不对。您需要在出现泛型类型的任何地方提供一个类型参数,即使在类型绑定(bind)本身内部也是如此:

class G< T extends G< T > > {}

你和这里的所有其他评论者和回复者,都已经离开了第二个 T

关于java - 在这个 Java 类层次结构中,如何使用泛型来避免类型转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29176090/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com