我最近看到可以声明一个也受接口限制的返回类型.考虑以下类和接口:
public class Foo {
public String getFoo() { ... }
}
public interface Bar {
public void setBar(String bar);
}
Run Code Online (Sandbox Code Playgroud)
我可以声明一个这样的返回类型:
public class FooBar {
public static <T extends Foo & Bar> T getFooBar() {
//some implementation that returns a Foo object,
//which is forced to implement Bar
}
}
Run Code Online (Sandbox Code Playgroud)
如果我调用该方法从什么地方,我的IDE告诉我,在返回类型的方法String getFoo(),以及setBar(String),但只有当我点了后面的点功能如下:
FooBar.getFooBar(). // here the IDE is showing the available methods.
Run Code Online (Sandbox Code Playgroud)
有没有办法获得对这样一个对象的引用?我的意思是,如果我做这样的事情:
//bar only has the method setBar(String)
Bar bar = FooBar.getFooBar(); …Run Code Online (Sandbox Code Playgroud) 我正在编写一个流畅的API来配置和实例化一系列"消息"对象.我有一个消息类型的层次结构.
为了能够在使用流畅的API时访问子类的方法,我使用泛型来参数化子类,并使所有流畅的方法(以"with"开头)返回泛型类型.请注意,我省略了流体方法的大部分主体; 其中有很多配置.
public abstract class Message<T extends Message<T>> {
protected Message() {
}
public T withID(String id) {
return (T) this;
}
}
Run Code Online (Sandbox Code Playgroud)
具体子类同样重新定义泛型类型.
public class CommandMessage<T extends CommandMessage<T>> extends Message<CommandMessage<T>> {
protected CommandMessage() {
super();
}
public static CommandMessage newMessage() {
return new CommandMessage();
}
public T withCommand(String command) {
return (T) this;
}
}
public class CommandWithParamsMessage extends
CommandMessage<CommandWithParamsMessage> {
public static CommandWithParamsMessage newMessage() {
return new CommandWithParamsMessage();
}
public CommandWithParamsMessage withParameter(String paramName,
String paramValue) {
contents.put(paramName, …Run Code Online (Sandbox Code Playgroud) 我正在构建一个泛型Tree<T>类,它支持子树的继承.但我遇到了一些问题.请你帮帮我吗?
让我们定义Tree类和BlueTree类,在哪里BlueTree extends Tree.
让我们定义Leaf类和RedLeaf类,在哪里RedLeaf extends Leaf.它们被用作树所包含的"数据".
A Tree<Leaf>表示类型的树Tree,其"数据"是类型Leaf.
对于继承(这不是适当的Java继承):
Tree<Leaf>可以有孩子的类型
Tree<Leaf>,Tree<RedLeaf>,BlueTree<Leaf>,和BlueTree<RedLeaf>..
Tree<RedLeaf>可以有孩子的类型
Tree<RedLeaf>,和BlueTree<RedLeaf>,Tree<Leaf>,或BlueTree<Leaf>..
BlueTree<Leaf>可以有孩子的类型
BlueTree<Leaf>,和BlueTree<RedLeaf>,Tree<Leaf>,或Tree<RedLeaf>..
BlueTree<RedLeaf>可以有孩子的类型
BlueTree<RedLeaf>,Tree<Leaf>,Tree<RedLeaf> …我长期以来在Java中使用一个成语来在其(通常是抽象的)祖先类(es)的方法中使用(非抽象)类的类信息(遗憾的是我找不到这个模式的名称):
public abstract class Abstract<T extends Abstract<T>> {
private final Class<T> subClass;
protected Abstract(Class<T> subClass) {
this.subClass = subClass;
}
protected T getSomethingElseWithSameType() {
....
}
}
Run Code Online (Sandbox Code Playgroud)
其子类的示例:
public class NonGeneric extends Abstract<NonGeneric> {
public NonGeneric() {
super(NonGeneric.class);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我在定义其子类Abstract有自己的泛型参数时遇到了问题:
public class Generic<T> extends Abstract<Generic<T>> {
public Generic() {
super(Generic.class);
}
}
Run Code Online (Sandbox Code Playgroud)
这个例子不可编译; 同样,不可能使用例如Generic<T>.class甚至使用通配符来指定泛型类型Generic<?>.
我也尝试将超T类中泛型类型的声明替换为? extends T,但这也不可编译.
有没有办法让这个模式与泛型基类一起使用?
我想知道是否有可能限制在接口上声明的方法要求类型绑定内的类型。实际上,我想提供一种在无法提供真正类型安全的情况下强制转换类型安全的方法。
例如,考虑具有Base通过中间接口继承的基本类型的层次结构。通常,人们知道一种类型是接口,FirstInterface但不知道是什么特定的类正在实现它。我想要一种方法,它允许转换到接口的任一实现,而不允许转换到其他实现,Base如下例所示:
interface Base<TYPE extends Base<TYPE>> {
default <CAST extends TYPE> CAST as(Class<? extends CAST> type) {
if (type.isInstance(this)) {
return type.cast(this);
} else {
throw new IllegalArgumentException();
}
}
}
interface FirstIface<TYPE extends FirstIface<TYPE>> extends Base<TYPE> { }
class FirstClassA implements FirstIface<FirstClassA> { }
class FirstClassB implements FirstIface<FirstClassB> { }
interface SecondIface<TYPE extends SecondIface<TYPE>> extends Base<TYPE> { }
class SecondClassA implements SecondIface<SecondClassA> { }
class SecondClassB implements SecondIface<SecondClassB> { }
interface …Run Code Online (Sandbox Code Playgroud) 假设我需要一个与泛型Comparable类型相关的类:
class A<T extends Comparable<T>> {
// this is just an example of usage of T type
List<T> comparables;
int compareSomething(T smth) {
return comparables.get(0).compareTo(smth);
}
}
Run Code Online (Sandbox Code Playgroud)
该类具有签名中具有自己的泛型的方法:
<V> Future<V> submit(Callable<V> task) {
return someExecutorService.submit(task);
}
Run Code Online (Sandbox Code Playgroud)
现在,是否有可能限制submit方法的输入只接受Callables也实现T?我第一次尝试这个:
<V, W extends T & Callable<V>> Future<V> submit(W task) {
if(compareSomething(task) != 0)
throw new RuntimeException("");
return someExecutorService.submit(task);
}
Run Code Online (Sandbox Code Playgroud)
但发现它是不可能的(由于此处所述的原因).有没有优雅的可能性绕过它?
编辑:我能想到的一个丑陋的可能性是将封装分成两种不同的类型并传递一个对象submit:
class A<T extends Comparable<T>> {
// this is just an …Run Code Online (Sandbox Code Playgroud) 我想了解以下是什么意思?
public class Bar<T extends Bar<T>> extends Foo<T> {
//Some code
}
Run Code Online (Sandbox Code Playgroud)
做这样的事情有什么好处(例如用例?).
这有点难以解释,但我到处都看,我找不到任何好的答案.
我也看过Stack Overflow问题如何引用接口在Java中实现的类类型?和如何返回相同类型的对象的实例作为类中使用Java 6过去了?,但他们无法回答我的问题.应用继承时有一个例外.
有一个例子,让它更容易理解:
假设我有一些名为SelfMaker的界面:
public interface SelfMaker <SELF>{
public SELF getSelf();
}
Run Code Online (Sandbox Code Playgroud)
A有一只狗,可以与另一只狗生育.所以狗是一个"SelfMaker",像这样:
public class Dog implements SelfMaker<Dog> {
String color;
public String toString() {
return "some " + color + " dog";
}
public Dog procreate(Dog anotherDog) {
Dog son = getSelf();
son.color = color;
return son;
}
@Override
public Dog getSelf() {
return new Dog();
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我有一只国内狗,他是一只狗,但它有一个可爱的家庭,他给他起了个名字.像这样:
public class DomesticDog extends Dog {
private String name;
public String toString() {
return …Run Code Online (Sandbox Code Playgroud) 我正在使用一个流畅的继承接口.我声明基类Constructor受到保护,所以你不能创建一个Foo <Bar>,它会在调用add()时导致ClassCastException.但我遇到了返回新Foo实例的静态方法的问题.
public class Foo<T extends Foo<T>> // if i change to extends Foo i only get warnings
{
public static Foo<Foo> createFoo() // <-- error
{
return new Foo<Foo>(); // <-- error
}
protected Foo() {}
public T add()
{
//...
return (T)this;
}
}
public class Bar extends Foo<Bar>
{
public Bar sub()
{
//...
return this;
}
}
Run Code Online (Sandbox Code Playgroud)
这主要是Fluent Interfaces,Domain-specific language和Generics中的练习(个人而不是家庭作业),所以请不要问我需要它.
编辑:Eclipse错误
Bound mismatch: The type Foo is not a valid substitute for the bounded parameter <T …Run Code Online (Sandbox Code Playgroud) 我正面临这个问题中描述的问题,但想找到一个没有所有演员和@SuppressWarning注释的解决方案(如果可能的话).
一个更好的解决方案是建立在引用的解决方案之上:
此处提供的解决方案将根据标准评分为2分.Bounty用大多数积分去解决方案,或者如果有多个积分,那么"最优雅的"积分将达到2分.