Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/399.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java协作泛型类:我们能避免未经检查的强制转换吗?_Java_Generics_Compiler Errors - Fatal编程技术网

Java协作泛型类:我们能避免未经检查的强制转换吗?

Java协作泛型类:我们能避免未经检查的强制转换吗?,java,generics,compiler-errors,Java,Generics,Compiler Errors,编辑:对不起;我急于给大家举一个简单的例子,在我的第一个问题版本中,我没有提供足够的关于需求的信息 我有两个抽象泛型类。他们相互合作,因此相互依赖。有时,一方需要将此传递给另一方。我正试图找到一种类型安全的方法来做到这一点 public abstract class AbstractA<T extends AbstractB<? extends AbstractA<T>>> { protected void foo() { T aB

编辑:对不起;我急于给大家举一个简单的例子,在我的第一个问题版本中,我没有提供足够的关于需求的信息

我有两个抽象泛型类。他们相互合作,因此相互依赖。有时,一方需要将此传递给另一方。我正试图找到一种类型安全的方法来做到这一点

public abstract class AbstractA<T extends AbstractB<? extends AbstractA<T>>> {

    protected void foo() {
        T aB = createB();
        aB.setA(this);
    }

    /** factory method */
    abstract public T createB();

}

public abstract class AbstractB<T extends AbstractA<? extends AbstractB<T>>> {

    private T theA;

    @SuppressWarnings("unchecked")
    public void setA(AbstractA<? extends AbstractB<?>> theA) { // dreamed of parameter list (T theA)
        // Unchecked cast from AbstractA<capture#1-of ? extends AbstractB<?>> to T
        this.theA = (T) theA;
    }

    protected T getA() {
        return theA;
    }

}

class AbstractA如果我正确理解了您的意思,这应该会创建您想要的绑定

class Demo {

    public static void main(String[] args) {
        ConcreteA a = new ConcreteA();
        ConcreteB b = new ConcreteB();
        a.foo(b);
        b = (ConcreteB) a.getB();
    }
}

abstract class AbstractA<T extends AbstractB<?>>{

    private AbstractB<?> b;

    public AbstractB<?> getB(){
        return b;
    }

    void foo(AbstractB<?> aB) {
        b = aB;
        aB.bar(this);
    }
}

abstract class AbstractB<T extends AbstractA<?>> {

    private AbstractA<?> a;

    public AbstractA<?> getA(){
        return a;
    }

    public void bar(AbstractA<?> theA) {
        a = theA;
        theA.foo(this);
    }
}

class ConcreteA extends AbstractA<ConcreteB>{

}

class ConcreteB extends AbstractB<ConcreteA>{

}
类演示{
公共静态void main(字符串[]args){
ConcreteA a=新ConcreteA();
混凝土b=新混凝土b();
a、 傅(乙);;
b=(b)a.getB();
}
}
抽象类AbstractAB;
公共摘要b getB(){
返回b;
}
void foo(AbstractB aB){
b=aB;
aB.bar(本);
}
}
抽象类AbstractB a;
公共摘要a getA(){
返回a;
}
公共空白栏(AbstractA theA){
a=θ;
theA.foo(本);
}
}
类ConcreteA扩展了AbstractA{
}
类ConcreteB扩展了AbstractB{
}
我想这就是你自己的结局。我无法删除对ConcreteB的强制转换,getB()无法确定它所包含的类型。我现在明白了为什么在声明中有多个泛型语句。:)

如果你准备好了,继续搜索,如果你找到了,就发布你自己的答案,我很乐意看到


我希望解决你一半的问题对任何事情都有意义

我想我现在明白了为什么我不能在
AbstractB
中声明
public void setA(T theA)
,然后在
foo()中将其称为
aB.setA(this)
。假设我们有:

class IntermediateConcreteA extends AbstractA<ConcreteB> {

    @Override
    public ConcreteB createB() {
        return new ConcreteB();
    }

}

class SubConcreteA1 extends IntermediateConcreteA {}

class SubConcreteA2 extends IntermediateConcreteA {}

class ConcreteB extends AbstractB<SubConcreteA2> {}
class IntermediateConcreteA扩展了AbstractA{
@凌驾
公共混凝土b createB(){
返回新的concrete b();
}
}
类subcretea1扩展了IntermediateConcreteA{}
类subcretea2扩展了IntermediateConcreteA{}
类ConcreteB扩展了AbstractB{}

现在,如果我有一个
subcretea1
并调用它的
foo()
,那么
createB()
将返回一个对象,该对象可以作为
AbstractB
传递,但不能作为
AbstractB
传递。因此,它的
setA()
不应该接受
this
作为参数。编译器错误消息毕竟是合乎逻辑的。

每个抽象类都将使用两个类型参数进行参数化,一个用于A的实际具体类,另一个用于B的实际具体类:

public abstract class AbstractA<A extends AbstractA<A,B>, B extends AbstractB<A,B>> {

    protected void foo() {
        B aB = createB();
        aB.setA(getThis());
    }

    abstract public A getThis();
    abstract public B createB();

}

public abstract class AbstractB<A extends AbstractA<A,B>, B extends AbstractB<A,B>> {

    private A theA;

    public void setA(A theA) {
        this.theA = theA;
    }

    protected A getA() {
        return theA;
    }

}

public class ConcreteA extends AbstractA<ConcreteA, ConcreteB> {

    @Override
    public ConcreteA getThis() {
        return this;
    }

    @Override
    public ConcreteB createB() {
        return new ConcreteB();
    }

    public void concreteAMethod() {
        // ...
    }

}

public class ConcreteB extends AbstractB<ConcreteA, ConcreteB> {

    public void bar() {
        ConcreteA a = getA();
        a.concreteAMethod();
    }

}
公共抽象类AbstractA{
受保护的void foo(){
B aB=createB();
刚毛(getThis());
}
抽象公共A getThis();
抽象公共B createB();
}
公共抽象类AbstractB{
私人A theA;
公共无效setA(A theA){
this.theA=theA;
}
保护一个getA(){
返回theA;
}
}
公共类ConcreteA扩展了AbstractA{
@凌驾
公共混凝土{
归还这个;
}
@凌驾
公共混凝土b createB(){
返回新的concrete b();
}
公共空间{
// ...
}
}
公共类ConcreteB扩展了AbstractB{
公共空白栏(){
具体a=getA();
a、 具体方法();
}
}

工厂可以解决此问题:

public abstract class AbstractA {

    public void abstractAMethod() {
        // ...
    }

}

public abstract class AbstractB<A> {

    private A theA;

    public void setA(A theA) {
        this.theA = theA;
    }

    protected A getA() {
        return theA;
    }

}

public abstract class AbstractFactory<A extends AbstractA, B extends AbstractB<A>> {

    private A theA = createA();

    public A getA() {
        return theA ;
    }

    public B getNextB() {
        B newB = createB();
        newB.setA(theA);
        return newB;
    }

    protected abstract A createA();
    protected abstract B createB();
}
公共抽象类AbstractA{
公共空间抽象方法(){
// ...
}
}
公共抽象类AbstractB{
私人A theA;
公共无效setA(A theA){
this.theA=theA;
}
保护一个getA(){
返回theA;
}
}
公共抽象类抽象工厂{
私有A theA=createA();
公共A getA(){
返回theA;
}
公共B getNextB(){
B newB=createB();
新刚毛(theA);
返回新兵;
}
受保护的抽象A createA();
受保护的抽象B createB();
}
现在,用户可以:

public class ConcreteA extends AbstractA {

    public void concreteAMethod() {
        // ...
    }

}

public class ConcreteB extends AbstractB<ConcreteA> {

    public void bar() {
        ConcreteA a = getA();
        a.abstractAMethod();
        a.concreteAMethod();
    }

}

public class ConcreteFactory extends AbstractFactory<ConcreteA, ConcreteB> {

    @Override
    protected ConcreteA createA() {
        return new ConcreteA();
    }

    @Override
    protected ConcreteB createB() {
        return new ConcreteB();
    }

}
公共类ConcreteA扩展了AbstractA{
公共空间{
// ...
}
}
公共类ConcreteB扩展了AbstractB{
公共空白栏(){
具体a=getA();
a、 抽象方法();
a、 具体方法();
}
}
公共类ConcreteFactory扩展了AbstractFactory{
@凌驾
受保护的混凝土A createA(){
返回新的ConcreteA();
}
@凌驾
受保护的混凝土B createB(){
返回新的concrete b();
}
}
我不认为这是抽象工厂模式的典型应用,不过


@Chris Wohlert,我确实放弃了我的生产代码,因为我认为工厂太过分了,但我不能放弃理论问题。

我开始意识到我的问题其实是因为将两个不属于一起的概念塞进了AbstractA/ConcreteA层次结构中。虽然很多人可能对此不感兴趣,但我之所以发布这篇文章,有两个原因:(1)我觉得我欠Chris Wohlert我自己找到的答案(2)更重要的是,我想激励其他面临类似棘手泛型问题的人,从更高的层面来审视你的设计,而不仅仅是解决泛型和/或类类型转换问题。这当然对我有帮助。cast/泛型问题是一个信号,表明一些更基本的东西并不完全正确

public abstract class AbstractA {

    public void foo() {
        AbstractB aB = createB();
        aB.setA(this);
    }

    /** factory method */
    abstract public AbstractB createB();

}

public abstract class AbstractB {

    private AbstractA theA;

    public void setA(AbstractA theA) {
        this.theA = theA;
    }

    // methods that use theA

}
没有泛型和类强制转换。将不属于A类层次结构的内容取出到Concrete C中(没有AbstractC):

客户需要比以前多出几行。在我的真实代码中,我需要在AbstractA和Concrete C中复制最后一个字段,但这样做是有意义的。总而言之,我认为这是一个低价格的设计,否则是纯粹和简单。

“看起来有点复杂”-确实。我想知道这种嵌套对于应用程序案例是否真的是必要的(或合理地有益的)。省略最后一个
extends
已经解决了这个问题,但只要不清楚在何处实际需要这种泛型,
public abstract class AbstractA {

    public void foo() {
        AbstractB aB = createB();
        aB.setA(this);
    }

    /** factory method */
    abstract public AbstractB createB();

}

public abstract class AbstractB {

    private AbstractA theA;

    public void setA(AbstractA theA) {
        this.theA = theA;
    }

    // methods that use theA

}
public class Client {

    public void putTheActTogether() {
        ConcreteC theC = new ConcreteC();

        // the concrete A
        AbstractA theA = new AbstractA() {
            @Override
            public AbstractB createB() {
                return new ConcreteB(theC);
            }
        };
        // call methods in theA
    }

}

public class ConcreteB extends AbstractB {

    private final ConcreteC c;

    public ConcreteB(ConcreteC c) {
        super();
        this.c = c;
    }

    public void bar() {
        c.concreteCMethod();
    }

}

public class ConcreteC {

    public void concreteCMethod() { // was concreteAMethod(); moved and renamed
        // ...
    }

}