Java 使用无集合的泛型时出现类型擦除错误
我想用Java实现monad。 使用下面的代码,我得到了错误Java 使用无集合的泛型时出现类型擦除错误,java,Java,我想用Java实现monad。 使用下面的代码,我得到了错误方法other(V)的擦除与类型other中的另一个方法相同 我看不出t和V是如何被擦除为相同的类型,从而导致错误的 public class Either<T, V> { private T t; private V v; public Either(T t) { this.t = t; } public Either(V v) { this.v
方法other(V)的擦除与类型other中的另一个方法相同
我看不出t和V是如何被擦除为相同的类型,从而导致错误的
public class Either<T, V> {
private T t;
private V v;
public Either(T t) {
this.t = t;
}
public Either(V v) {
this.v = v;
}
}
公共类{
私人T;
私人V V;
公共或(T){
t=t;
}
公共关系(V){
这个,v=v;
}
}
相关帖子,但不重复:
下面的文章介绍了两个构造函数,一个是Collection
,另一个是Collection
。问题是构造函数的两个参数都将被类型擦除到集合
,因此它们具有相同的类型签名
我的文章不是重复的,因为主要类型不同
compareTo(Real r)
,另一个使用compareTo(Object o)
我的帖子不是重复的,因为类型T
和V
没有关联,至少在我看来没有关联
- 为什么会发生这种类型的擦除错误
- 如何解决此错误以在Java中实现任意一个monad
public-other(T)
->public-other(Object-T)
和具有相同类型签名的public-other(V V)
->public-other(Object V)
要解决此问题,可以执行以下操作:
public class Either<T, V> {
private T t;
private V v;
private Either(T t, V v) {
this.t = t;
this.v = v;
}
public static Either instaceOfT(T t) {
return new Either<>(t, null);
}
public static Either instaceOfV(V v) {
return new Either<>(null, v);
}
}
公共类{
私人T;
私人V V;
二等兵(T,V){
t=t;
这个,v=v;
}
公共静态或instaceOfT(T){
返回新的(t,null);
}
公共静态或instaceOfV(V){
返回新的(null,v);
}
}
如果您可以在泛型类型上使用,这将克服擦除问题。尽管如此,我知道在大多数情况下,您不希望限制这样一个类,而是以一种非常通用的方式定义它,这样它就可以在任何地方重用
public class Either<T extends String, V extends Object> {
private T t;
private V v;
private Either(T t, V v) {
this.t = t;
this.v = v;
}
public static <T extends String, V extends Object> Either<T, V> either(T t) {
return new Either<T, V>(t, null);
}
public static <T extends String, V extends Object> Either<T, V> either(V v) {
return new Either<T, V>(null, v);
}
}
公共类{
私人T;
私人V V;
二等兵(T,V){
t=t;
这个,v=v;
}
公共静态任选一(T){
返回新的(t,null);
}
公共静态或任意(V){
返回新的(null,v);
}
}
您可以在每个构造函数中引入不同类型的第二个参数,Java可以:
public class Either<T, V> {
public enum Left { Left }
public enum Right { Right }
private T t;
private V v;
public Either(T t, Left l) {
this.t = t;
}
public Either(V v, Right r) {
this.v = v;
}
}
公共类{
公共枚举左{Left}
公共枚举权限{Right}
私人T;
私人V V;
公共或公共(T,左l){
t=t;
}
公共或(V,右r){
这个,v=v;
}
}
这是合理的,因为现在第二个参数可以用作鉴别器
让我印象深刻的是发现Java完全能够推断调用哪个构造函数,即使使用以下代码:
new Either<Integer,Exception>(new Integer(2),null);
new Either<Integer,Exception>(new Exception(),null);
new或(新整数(2),null);
新的(新异常(),null);
那么,为什么它对擦除方法(V)和类型(other)中的另一种方法(other)如此挑剔呢?我不知道
我所知道的是,我不喜欢总是向我的构造函数传递一个额外的无用参数。因此,我求助于使用Java varargs的解决方案:
public class Either<T, V> {
public enum Left { Left }
public enum Right { Right }
private T t;
private V v;
public Either(T t, Left... l) {
this.t = t;
}
public Either(V v, Right... r) {
this.v = v;
}
}
公共类{
公共枚举左{Left}
公共枚举权限{Right}
私人T;
私人V V;
公共或(T,左…l){
t=t;
}
公共或(V,右…r){
这个,v=v;
}
}
当然,现在可以这样调用构造函数:
new Either<Integer,Exception>(new Integer(2),null);
new Either<Integer,Exception>(new Exception(),null,Right,nul);
new Either<Integer,Exception>(new Integer(2));
new Either<Integer,Exception>(2);
new Either<Integer,Exception>(new Exception());
new或(新整数(2),null);
新的(新异常(),null,Right,nul);
只要我不必阅读你的代码,我就不会反对。
但好处是您现在可以像这样构建任意一个实例:
new Either<Integer,Exception>(new Integer(2),null);
new Either<Integer,Exception>(new Exception(),null,Right,nul);
new Either<Integer,Exception>(new Integer(2));
new Either<Integer,Exception>(2);
new Either<Integer,Exception>(new Exception());
new或(新整数(2));
新的(2);
新的或(新的异常());
您可以在以下位置找到此类型的完整、不可变的实现:
T和V都被类型擦除为
对象,因此编译时两个构造函数具有相同的类型签名
我们可以通过遵循有效Java的建议来避免这种情况:明智地使用重载,并且更喜欢静态工厂方法而不是公共构造函数
public class Either<T, V> {
private T t;
private V v;
private Either(T t, V v) {
this.t = t;
this.v = v;
}
public static <L, R> Either<L, R> left(L leftValue) {
return new Either(leftValue, null);
}
public static <L, R> Either<L, R> right(R rightValue) {
return new Either(null, rightValue);
}
}
公共类{
私人T;
私人V V;
二等兵(T,V){
t=t;
这个,v=v;
}
公共静态或左(L leftValue){
返回新的值(leftValue,null);
}
公共静态任意权利(R rightValue){
返回新的(null,rightValue);
}
}
具有相同数量参数的方法重载通常会导致歧义,尤其是在泛型中。通过避免使用这些方法并公开不同的命名方法,您可以让编译器和API用户感到高兴。我看到这是一个自我回答的问题(很好:),但是OP在某个地方实际包含一个问题会很有帮助……其他人开发了这样一个类:。所以你可能想看看他们是如何实现的。你呃,忘了在那里分配你的v
。我应该知道不要把代码直接写进So。很好。为了将来参考,这里提供了函数式Java的源代码: