Как сотворить общий тип из Erasure - PullRequest
0 голосов
/ 06 октября 2018

У меня есть родительский класс, Parent, с двумя дочерними классами, A и B.У меня есть интерфейс, Function<Type1 extends Parent,Type2 extends Parent>, который позволяет программисту написать определенную функцию, Type2 of(Type1 t), которая переводит Type1 в Type2.Интерфейс обернут в класс Wrapper<Type1 extends Parent,Type2 extends Parent>, который содержит полезную информацию, такую ​​как Class<Type1> type1Class и т. Д.

Моя проблема возникает, когда я пытаюсь реализовать метод add для класса Wrapper,Wrapper<Type1,Type2> add(Wrapper<Type1,Type2> additionalWrapper).Я пытаюсь сложить вместе два Function, но у меня возникают трудности с выводом Type2 вместо Parent из-за удаления.

Как мне сделать add метод вывода Type2 вместо Parent?

public class Parent {
    protected int value;
    public void setValue(int x){ value = x; }
    public int getValue(){ return value; }
    public Parent(){}
    public Parent(int x){setValue(x);}
    public Parent add(Parent p){return null;}
}


public class A extends Parent{
    public A(){ setValue(1); }
    public A(int x){ setValue(x); }
    public A(B b){ setValue( b.getValue()); }
    public A add(A a){ return new A( getValue()+a.getValue()); }
    public A add(B b){ return new A( getValue()*b.getValue()); }
}

public class B extends Parent{
    public B(){ setValue(2); }
    public B(int x){ setValue(x); }
    public B(A a){ setValue(a.getValue()); }
    public B add(B b){ return new B(getValue() + b.getValue()); }
    public B add(A a){ return new B(getValue() * a.getValue()); }
}

public interface Function <Type1 extends Parent, Type2 extends Parent> {
    public Type2 of(Type1 t);
}

public class Wrapper<Type1 extends Parent, Type2 extends Parent> {

    protected Function<Type1,Type2> function;
    protected Class<Type1> type1Class;
    protected Class<Type2> type2Class;
    public Wrapper(final Class<Type1> t1, final Class<Type2> t2, Function<Type1,Type2> x) {
        type1Class = t1;
        type2Class = t2;
        function = x;
    }

    public Type2 of(Type1 t){
        return function.of(t);
    }
    public Wrapper<Type1,Type2> add(final Wrapper<Type1,Type2> additionalWrapper){
        return new Wrapper<Type1,Type2>( type1Class, type2Class, new Function<Type1,Type2>(){
            public Type2 of(Type1 t){
                try{
                    Type2 term = function.of(t);
                    Type2 summand = additionalWrapper.of(t);
                    Type2 sum = (Type2) term.add(summand); ///Problem happens here. term and summand are both interpreted as Parent by the erasure, I think, and therefore add outputs null, setting sum=null.
                    return sum;
                } catch(Exception e){
                    e.printStackTrace();
                    return null;
                }
            }
        });
    }
}

public class Main {
    public static void main(String[] args){
        Wrapper<A, B> wrapper1 = new Wrapper<A, B>(A.class,B.class,new Function<A, B>() {
            @Override
            public B of(A a) {
                return new B(a);
            }
        });
        Wrapper<A, B> wrapper2 = new Wrapper<A, B>(A.class,B.class,new Function<A, B>() {
            @Override
            public B of(A a) {
                B b = new B();
                return b.add(a);
            }
        });
        Wrapper<A,B> wrapper3 = wrapper1.add(wrapper2);

        A a = new A(3);
        B b = wrapper3.of(a);

        System.out.println(b.getValue()); ///Error happens here because b was set to null and therefore doesn't contain int value.

    }
}

Ответы [ 2 ]

0 голосов
/ 06 октября 2018

Как предложил Луи Вассерман в комментарии, мне нужно было использовать instanceof в одной переопределенной функции Parent add(Parent p).

В классах A и B мне нужно было иметь эту функцию:

@Override
public Parent add(Parent p){
    if (p instanceof A){
        A a = (A) p;
        return add(a);
    }
    else if (p instanceof B){
        B b = (B) p;
        return add(b);
    }
    else return null;
}
0 голосов
/ 06 октября 2018

По сути, вы не можете добавить A и B двумя способами, это противоречит принципам полиморфизма или твердого тела.Вы можете создать классы, как показано ниже -

class A extends Parent{
public A(){ setValue(1); }
public A(int x){ setValue(x); }
public A(B b){ setValue( b.getValue()); }
@Override
public A add(Parent a){ return new A( getValue()+a.getValue()); }
}

class B extends Parent{
public B(){ setValue(2); }
public B(int x){ setValue(x); }
public B(A a){ setValue(a.getValue()); }
@Override
public B add(Parent b){ return new B(getValue() + b.getValue()); }
}

Поскольку add определен в Parent, достаточно только одной реализации.В текущем сценарии, поскольку сигнатуры add в классе A не совпадают с сигнатурой в Parent, и, таким образом, метод вообще не переопределяется

.узнайте, добавляете ли вы @Override в ваши методы add.Компилятор выдаст ошибки.

Надеюсь, это поможет.

...