Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/339.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_Inheritance_Type Safety - Fatal编程技术网

Java泛型方法擦除和继承

Java泛型方法擦除和继承,java,generics,inheritance,type-safety,Java,Generics,Inheritance,Type Safety,我遇到了javas泛型和重写方法的问题。想象一下,我有一个深树状的类层次结构。顶级类定义了一个方法foo,该方法接受Strategy类型的1个参数。策略有一个泛型类型参数 我的类层次结构中的每个类都需要重写foo,以限制它可以传递的策略类型,以便策略的泛型类型参数与声明的类匹配。以下是一个例子: abstract static class TopLevelClass { static final Strategy<TopLevelClass> s1 = tlc ->

我遇到了javas泛型和重写方法的问题。想象一下,我有一个深树状的类层次结构。顶级类定义了一个方法foo,该方法接受Strategy类型的1个参数。策略有一个泛型类型参数

我的类层次结构中的每个类都需要重写foo,以限制它可以传递的策略类型,以便策略的泛型类型参数与声明的类匹配。以下是一个例子:

abstract static class TopLevelClass {

    static final Strategy<TopLevelClass> s1 = tlc -> System.out.println(tlc.getTopLevelAtt());

    String getTopLevelAtt() {
        return "TopLevelAtt";
    }

    void foo(Strategy<TopLevelClass> s) {s.bar(this);}
}
static class MidLevelClass extends TopLevelClass {

    static final Strategy<MidLevelClass> s2 = mlc -> System.out.println(mlc.getMidLevelAtt());

    String getMidLevelAtt() {
        return "MidLevelAtt";
    }

    void foo(Strategy<MidLevelClass> s) {s.bar(this);}
}
static class LowLevelClass extends MidLevelClass  {

    static final Strategy<LowLevelClass> s3 = llc -> System.out.println(llc.getTopLevelAtt());

    String getLowLevelAtt() {
        return "LowLevelAtt";
    }

    void foo(Strategy<LowLevelClass> s) {s.bar(this);}
}
static interface Strategy<X> {
    void bar(X x);
}
抽象静态类TopLevelClass{
静态最终策略s1=tlc->System.out.println(tlc.gettoplavelatt());
字符串gettoplavelatt(){
返回“TopLevelAtt”;
}
void foo(策略s){s.bar(此);}
}
静态类MidLevelClass扩展了TopLevelClass{
静态最终策略s2=mlc->System.out.println(mlc.getMidLevelAtt());
字符串getMidLevelAtt(){
返回“MIDLEVEATT”;
}
void foo(策略s){s.bar(此);}
}
静态类LovelClass扩展了MiddlevelClass{
静态最终策略s3=llc->System.out.println(llc.gettoplavelatt());
字符串getLowLevelAtt(){
返回“LowLevelAtt”;
}
void foo(策略s){s.bar(此);}
}
静态接口策略{
空心钢筋(X X);
}
在这个例子中,我希望能够调用LowLevelClass实例上的foo,这些实例具有分别在TopLevelClass、MidLevelClass和LowLevelClass中定义的任何静态引用s1、s2和s3。理想情况下,我不必根据参数调用不同的方法foo1、foo2或foo3

上面的代码不是用java编译的。编译时错误为:

名称冲突:MidLevelClass类型的方法foo(Strategy)与TopLevelClass类型的方法foo(Strategy)具有相同的擦除,但不会覆盖它

我怀疑这个问题很难解决。我可以只使用原始类型并依赖于运行时的类型检查,但我宁愿保持类型安全。如何在不牺牲类型层次结构或类型安全性的情况下实现这一点?请注意,在构造函数中传递策略不是我的选择!必须能够在对象的生命周期内多次调用foo

编辑:
我意识到,在不了解周围环境的情况下,这个问题可能很难理解。我在这里提出了一个更详细的问题,解释了我的问题的背景:

如果您担心擦除,那么只需为单独的方法使用单独的方法名即可:

abstract class TopLevelClass {
    void fooTop(Strategy<TopLevelClass> s) {/*...*/}
}
class MidLevelClass extends TopLevelClass {
    void fooMid(Strategy<MidLevelClass> s) {/*...*/}
}
class LowLevelClass extends MidLevelClass  {
    void fooLow(Strategy<LowLevelClass> s) {/*...*/}
}
因此,通过方法重写来执行同样的操作是没有意义的。(当然,
bar(TopLevelClass)
不能覆盖
bar(MidLevelClass)
,尽管从1.5开始就存在协变返回类型,这也是事实。)

向类中添加类型参数以用作方法中的类型参数

abstract class TopLevelClass<T extends TopLevelClass<T>> {
    void foo(Strategy<T> s) {/*...*/}
}
class MidLevelClass<T extends MidLevelClass<T>> extends TopLevelClass<T> {
    void foo(Strategy<T> s) {/*...*/}
}
class LowLevelClass<T extends LowLevelClass<T>> extends MidLevelClass<T>  {
    void foo(Strategy<T> s) {/*...*/}
}
静态
字段的类型需要通配符:

static final Strategy<? extends TopLevelClass<?>> s1 =
    tlc -> System.out.println(tlc.getTopLevelAtt());
静态最终策略>s1=
tlc->System.out.println(tlc.gettoplavelatt());

(更好的设计更喜欢组合而不是继承。)

如果您担心擦除,那么只需为单独的方法使用单独的方法名称:

abstract class TopLevelClass {
    void fooTop(Strategy<TopLevelClass> s) {/*...*/}
}
class MidLevelClass extends TopLevelClass {
    void fooMid(Strategy<MidLevelClass> s) {/*...*/}
}
class LowLevelClass extends MidLevelClass  {
    void fooLow(Strategy<LowLevelClass> s) {/*...*/}
}
因此,通过方法重写来执行同样的操作是没有意义的。(当然,
bar(TopLevelClass)
不能覆盖
bar(MidLevelClass)
,尽管从1.5开始就存在协变返回类型,这也是事实。)

向类中添加类型参数以用作方法中的类型参数

abstract class TopLevelClass<T extends TopLevelClass<T>> {
    void foo(Strategy<T> s) {/*...*/}
}
class MidLevelClass<T extends MidLevelClass<T>> extends TopLevelClass<T> {
    void foo(Strategy<T> s) {/*...*/}
}
class LowLevelClass<T extends LowLevelClass<T>> extends MidLevelClass<T>  {
    void foo(Strategy<T> s) {/*...*/}
}
静态
字段的类型需要通配符:

static final Strategy<? extends TopLevelClass<?>> s1 =
    tlc -> System.out.println(tlc.getTopLevelAtt());
静态最终策略>s1=
tlc->System.out.println(tlc.gettoplavelatt());

(更好的设计更喜欢组合而不是继承。)

我觉得这种设计有几个困难:

  • 由于每个类都只使用同一类中的方法来实现自己的
    策略
    ,因此不需要
    Strategy.bar()
    来获取该类的实例。参数的传递是妨碍整洁地实现此功能的原因之一
  • 由于
    foo()
    的所有实现都在做完全相同的事情,因此不需要多个实现
  • 下面是一段有部分解决方案的代码。部分原因是,在一个好的解决方案中,您应该能够在更改的
    foo()
    方法中传递
    TopLevelClass
    的引用。如果你能想出一个办法,我想那会很棒。在这个解决方案中,类层次结构不是一个因素,因为我们使用的是特定的引用类型

    我已经在“更改”开头对更改的部分进行了注释

    公共类擦除1{
    公共静态void main(字符串[]args){
    LowLevelClass slc=new LowLevelClass();//“slc”必须与实例的类型完全相同。这是此解决方案的一个限制。理想情况是此引用的类型为TopLevelClass。
    slc.foo(低层类s3,slc);
    }
    抽象静态类TopLevelClass{
    静态最终策略s1=tlc->System.out.println(tlc.gettoplavelatt());
    字符串getToLevel(){return“TopLevelAtt”;}
    /*更改1:必须传递TopLevelClass子类型的实例,因为
    *Strategy.bar()不接受通配符。将其更改为接受“t”以传递给bar()。
    *此外,由于现在将“T”作为参数,因此该方法很可能是一个
    *实用程序类中的静态方法*/
    void foo(策略s、T tlc){
    s、 薄层色谱法;
    }
    }
    静态类MidLevelClass扩展了TopLevelClass{
    静态最终策略s2=mlc->System.out.println(mlc.getMidLevelAtt());;
    字符串getMidLevelAtt(){返回“MidLevelAtt”;}
    /*更改2:由于此方法与其父方法没有任何不同,因此不需要这样做*/
    //void foo(策略s){s.bar(此);}
    }
    静态类低级类
    
    public class Erasure1{
    
        public static void main( String[] args ){
            LowLevelClass slc = new LowLevelClass(); //'slc' must be exactly the same type as the instance. This is a limitation with this solution. Ideal thing would have been that this reference be of type TopLevelClass.
            slc.foo( LowLevelClass.s3, slc );
        }
    
        abstract static class TopLevelClass{
    
            static final Strategy<TopLevelClass> s1 = tlc -> System.out.println( tlc.getTopLevelAtt() );
    
            String getTopLevelAtt(){ return "TopLevelAtt"; }
    
            /* CHANGE 1: It is necessary that the instance of TopLevelClass subtype be passed since 
             * Strategy.bar() doesn't accept wildcards. Changing it to accept a 'T' to pass to bar().
             * Also, since, this is now taking 'T' as a parameter, this method could very well be a 
             * static method in a utility class. */
            <T> void foo( Strategy<T> s, T tlc ){
                s.bar( tlc );
            }
        }
    
        static class MidLevelClass extends TopLevelClass{
            static final Strategy<MidLevelClass> s2 = mlc -> System.out.println(mlc.getMidLevelAtt());;
    
            String getMidLevelAtt(){ return "MidLevelAtt"; }
    
            /* CHANGE 2: Since this method is not doing anything different from its parent, this is not required. */
            //void foo(Strategy<MidLevelClass> s) {s.bar(this);}
        }
    
        static class LowLevelClass extends MidLevelClass{
    
            static final Strategy<LowLevelClass> s3 = llc -> System.out.println( llc.getLowLevelAtt() );
    
            String getLowLevelAtt(){ return "LowLevelAtt"; }
    
            /* CHANGE 2: Since this method is not doing anything different from its parent, this is not required. */
            //void foo(Strategy<LowLevelClass> s) {s.bar(this);}
        }
    
        static interface Strategy<X> {
            void bar( X x );
        }
    }