- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我需要提供一个通用接口(interface)以在单独的类层次结构中使用,并希望该接口(interface)支持调用链。
我曾尝试使用反射边界来做到这一点,但如果不将“this”转换为所需的类型,我似乎无法让它工作。这是我目前的做法:
public interface Operable<T extends Operable<T>> {
T prepare();
T operate();
}
public abstract class BaseOperable<T extends Operable<T>> implements Operable<T> {
@Override
public T prepare() {
System.out.println("Preparing...");
// why is this needed? "this" is a BaseOperable that implements Operable<T>
return (T) this;
}
}
public class SpecialOperable<T extends SpecialOperable<T>> extends
BaseOperable<SpecialOperable<T>> {
@Override
public T operate() {
System.out.println("Operation "
+ (Math.random() > 0.5 ? "succeeded" : "failed"));
// this seems to be required
return (T) this;
}
@Override
public T prepare() {
// if I don't override this, the supertype T is used which is
// BaseOperable and hides "specialOp" from chaining
return (T) super.prepare();
}
public T specialOp() {
System.out.println("Doing something special...");
return (T) this;
}
}
将上面下面这行代码进行编译:mySpecialOperable().prepare().operate().specialOp().operate();
我的问题是:有什么方法可以避免对每个 return 语句进行类型转换吗?是否也可以不必在最专业的级别覆盖所有内容(就像使用 prepare()
方法所做的那样)?
最佳答案
问题是您在编译器无法在编译时确定转换是否合法的地方假定类型安全。这需要您遇到警告:为了使这一点更清楚,假设:
class Foo implements Operable<Foo> { ... } // legal
class Bar implements Operable<Foo> { ... } // not intended, but also legal
Bar
类在您的抽象模型中不合法。您想要实现一个自身类型,但实际上您在 Java 中所能要求的只是要求实现给定接口(interface)的类型 T
的扩展。因此,延伸
class Bar extends BaseOperable<Foo> { ... }
基本上会在运行时执行,就好像您实现了:
class Bar implements Operable<Foo> {
@Override
public Foo prepare() {
System.out.println("Preparing...");
// Why is this needed, you ask? Because you are now expressing this:
return (Foo) this; // this is of type Bar, not Foo
}
...
}
然而,其中 this
是 Bar
的实例,而不是 Foo
的实例。这当然会导致 ClassCastException
,对于这种可能性,编译器会警告您静态类型安全失败,并且此异常可能会发生在您通常不希望出现的地方。
您通常通过添加如下方法来避免这种情况:
protected abstract T self();
然后由任何非抽象类实现。由于此方法随后使用非泛型返回类型实现,因此静态编译检查可以完成其工作并禁止您使用我们之前观察到的任何非法返回类型。上面的 prepare
方法将像这样实现:
public T prepare() {
System.out.println("Preparing...");
return self();
}
但是,如果您正在使用一个未被任何用户实现的封闭 API,并且您想走捷径(希望您有单元测试来验证任何可能的滥用),您可以使用 @SupressWarnings("unchecked")
注释该方法以告诉编译器你知道你正在处理什么。
关于java - 反射泛型类型边界和方法链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27129518/
我是一名优秀的程序员,十分优秀!