Java generics name clash , has the same erasure

前端 未结 6 1571
[愿得一人]
[愿得一人] 2020-12-15 03:56

I have superclass Foo. And a class Bar extending it.

public class Bar extends Foo

Function in Foo:

protected void saveAll(C         


        
相关标签:
6条回答
  • 2020-12-15 04:09

    You just overriding methods with different Signatures.

    What will be good idea is to use PECS (Producer - Extends, Consumer - Super) rule described in Effective Java Second Edition by Joshua Bloch.

    according to this rule it should looks like this.

    In Foo class:

    public class Foo<E>{
    
    protected void saveAll(Collection<? super E> many){....}
    
    protected void getAll(Collection<? extends E> many){....}
    
    }
    
    0 讨论(0)
  • 2020-12-15 04:12

    You are overriding the saveAll method with an incompatible type. Perhaps you want to do something like:

    public class Bar extends Foo<MyClass>
    

    Function in Foo<E>

    protected void saveAll(Collection<E> many)
    

    and function in Bar:

    public void saveAll(Collection<MyClass> stuff) {
       super.saveAll(stuff);
    }
    
    0 讨论(0)
  • 2020-12-15 04:24

    While the existing answers are correct, this error easily occurs when you declare the actual type not in the "extends ..." clause but in the actual class name:

    Wrong:

    public class Bar<MyClass> extends Foo
    {
        ...
    }
    

    Correct:

    public class Bar extends Foo<MyClass>
    {
        ...
    }
    
    0 讨论(0)
  • 2020-12-15 04:30

    When the compilers compiles to byte code a process called Erasure happens. This remove the type information from the collections. I believe it will manually do the casts etc as part of the process of generating the byte code. If you remove the generic parts of your class (ie the <..> ) then you will see you have two saveAll methods. The error is that you have two save all methods will the same signature. The collections have type object in the byte code.

    Try removing the <..> which might make it clearer. When you put the <...> back in then consider the name of the methods. If they are different it should compile.

    Also I dont think this is a hibernate problem so this tag should be removed. It is a java generic problem you have.

    What you could do here is type the class

    public class Bar extends Foo<MyClass>
    

    and then have the method types to T

    public void saveAll(Collection<MyClass> stuff) {
       super.saveAll(stuff);
    }
    

    and then the declaration of Foo would be something like

    public abstract class Bar extends Foo<T> {
        public void saveAll(Collection<T> stuff) {
    }
    
    0 讨论(0)
  • 2020-12-15 04:31

    At runtime, the parameter types are replaced by Object. So saveAll(Collection<?>) and saveAll(Collection<MyClass>) are transformed to saveAll(Collection). This is a name clash. Look here for details.

    You could do this :

    public class Foo<T> {
        protected void saveAll(Collection many) {
            // do stuff
        }
    }
    
    public class Bar extends Foo<MyClass> {
    }
    
    0 讨论(0)
  • 2020-12-15 04:32

    Due to the type erasure feature of Java, the JVM will not be able to know whether it is the method that has the parametrized type MyClass or the first one that should be called.

    If possible or applicable, the most commonly used pattern I've seen to avoid this is to change the class Foo to have a parametrized type as well:

    public class Foo<T> {
        protected void saveAll(Collection<T> many) {}
    }
    

    and then have Bar simply implement Foo for your specific type:

    public class Bar extends Foo<MyClass> {
        public void saveAll(Collection<MyClass> many) {
            super.saveAll(many);
        }
    }
    
    0 讨论(0)
提交回复
热议问题