2008-10-23 52 views
2

这是一个有点lazyweb问题的,但你的声望,以便:-)如何编写一个返回“this”类型实例并在扩展时工作的Java函数?

我有一个返回自己的实例允许链接一个Java类 (如ClassObject.doStuff()。doStuff())

例如:

public class Chainer 
{ 
    public Chainer doStuff() 
    { 
     /* Do stuff ... */ 
     return this; 
    } 
} 

我想延长这一类。有没有办法,或许使用泛型,来扩展这个类而不必覆盖每个方法签名?

E.g.没有:

public class ChainerExtender extends Chainer 
{ 
    public ChainerExtender doStuff() 
    { 
     super.doStuff(); 
     return this; 
    } 
} 

我曾尝试:

public class Chainer 
{ 
    public <A extends Chainer> A doStuff() 
    { 
     /* Do stuff ... */ 
     return (A)this; 
    } 
} 

public class ChainerExtender extends Chainer 
{ 
    public <A extends Chainer> A doStuff() 
    { 
     /* Do stuff ... */ 
     return super.doStuff(); 
    } 
} 

但这并没有工作给错误:

type parameters of <A>A cannot be determined; 
no unique maximal instance exists for type variable A with upper bounds A,Chainer 

我是被迫发生类声明,如:

public class Chainer<T extends Chainer<T>> {} 
public class ChainerExtender extends Chainer<ChainerExtender> 

按照this question

回答

9

您是否尝试过直接的

public class Chainer 
{ 
    public Chainer doStuff() 
    { 
     /* Do stuff ... */ 
     return this; 
    } 
} 

public class ChainerExtender extends Chainer 
{ 
    @Override 
    public ChainerExtender doStuff() 
    { 
     /* Do stuff ... */ 
     super.doStuff(); 
     return this; 
    } 
} 

使用Java 5,你可以声明覆盖方法有共变的返回类型,这意味着正是这样说:一个子类可以有一个压倒一切的方法签名具有更具体的返回类型。

1

你可以发布一个完整的例子来看看你看到的错误消息吗?

我刚刚编译并执行以下顺利:

public class Test { 

    public static void main(String[] args) { 
     // TODO Auto-generated method stub 
     ChainerExtender c = new ChainerExtender(); 
     c.doStuff().doStuff(); 
    } 

    public static class Chainer 
    { 
     public <A extends Chainer> A doStuff() 
     { 
      /* Do stuff ... */ 
      System.out.println("Chainer"); 
      return (A)this; 
     } 
    } 

    public static class ChainerExtender extends Chainer 
    { 
     /** 
     * @see test.Test.Chainer#doStuff() 
     */ 
     @Override 
     public <A extends Chainer> A doStuff() 
     { 
      System.out.println("ChainerExtender"); 
      return super.doStuff(); 
     } 
    } 

} 

给出:

ChainerExtender 
Chainer 
ChainerExtender 
Chainer 

我已经有误解这个问题,请downvote和评论。

+0

谢谢,虽然我想我应该用super。 doStuff()? – 2008-10-23 05:36:41

+0

当我有机会时,我会检查它 - 谢谢:-)并且upvote进来一些小时数:P – 2008-10-23 06:16:31

6

为什么不让它们都返回一个接口?你必须在接口中定义所有可能的链接方法,并在基类中提供“null”实现,但是你可以链接到你的内心。

public interface IChainer 
{ 
    IChainer doStuff(); 
    IChainer doSomethingElse(); 
} 

public class Chainer implements IChainer 
{ 
    public IChainer doStuff() 
    { 
    // really do something 
    return this; 
    } 

    public IChainer doSomethingElse() 
    { 
     return this; // do nothing 
    } 
} 

public class ChainerExtender extends Chainer 
{ 
    // simply inherits implementation for doStuff() 

    public override IChainer doSomethingElse() 
    { 
     // really do something 
     return this; 
    } 
} 

注:我可能有一些上面的语法问题。过去几年我一直在使用C#编程。希望你明白这个主意。

+0

谢谢。我正在为其他原因而使用接口,但是你是对的,它可以解决问题,而且大多数情况下我都使用C#也没有问题:-)。 – 2008-10-23 06:14:26

1

我认为简单的答案是“不,你不能”。我可以看到这可能是有用的,但我认为这种继承的使用尖叫我“意想不到的后果”。有人决定在子类中添加一些额外的功能只是一个时间问题,而不是仅仅执行super.doStuff(),而且控制流将非常难以遵循。

一个可能的解决方案是为您chainers(如果他们使用的是建设者模式)返回不同的制造商类,而不是this的新实例。看看Stephen Colebourne在JSR 310中用日期创建构建器做了些什么,从API的角度来看这很聪明,尽管编写起来很笨拙。

1

自从我做了任何Java泛型以来已经有一段时间了。

关于什么:

 

<T> 
public class Chainer 
{ 
    public T doStuf() 
    { 
    } 

} 

public class ChainerDerived : extends Chainer<ChainerDerived> 
{ 
    public ChainerDerived doStuf() 
    { 
    } 
} 

我大部分时间在做C++和最近这种东西仅仅是意料之中的事。 Java泛型支持这种类型的结构吗?

我希望我能理解你的问题。

2

我是这样工作的。它使用类文字标记在运行时输入什么类型(请参阅Gilad Bracha's Generics Tutorial的第8部分)。

 
public class Chainer { 
    public <T extends Chainer> T doStuff (Class<T> foo) { 
    /* do stuff */ 
    return foo.cast (this); 
    } 
} 

public class ChainerExtender extends Chainer { 
    public <T extends ChainerExtender> doOtherStuff (Class<T> foo) { 
    /* do other stuff */ 
    return foo.cast (this); 
    } 
} 

所以调用看起来是这样的:

 
Chainer c1 = new Chainer(); 
c1 = c1.doStuff (c1.getClass()); 
// ... 
ChainerExtender ce1 = new ChainerExtender(); 
ce1 = ce1.doStuff (ce1.getClass()).doOtherStuff (ce1.getClass()); 

一个缺点这种技术的是,如果你有一个Chainer参考,你必须明确地检查,如果它实际上是一个ChainerExtender对象上调用doOtherStuff前它。不过,这是有道理的,因为在运行时尝试调用Chainer对象上的方法会产生错误。

1

请注意,“super。< A> doStuff()”会编译的工作。它暗示了你所期望的类型的泛型。

相关问题