Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Code with generics won't compile

Tags:

java

generics

I've failed to google this problem. Why would this line produce a compilation error.

wrapper.doSmth(wrapper.getCurrent());

I'm using java 7.

public class App {
 Wrapper<?> wrapper;

 class Generic<T>{

 }

 class Wrapper<T>{
  Generic<T> current;

  public void doSmth(Generic<T> generic){
  }

  public Generic<T> getCurrent(){
   return current;
  }
 }

 public void operation(){
  wrapper.doSmth(wrapper.getCurrent());
 }
}

The error is:

Error:(25, 24) java: method doSmth in class App.Wrapper<T> cannot be applied to given types;
  required: App.Generic<capture#1 of ?>
  found: App.Generic<capture#2 of ?>
  reason: actual argument App.Generic<capture#2 of ?> cannot be converted to conf.App.Generic<capture#1 of ?> by method invocation conversion
like image 368
doctorgester Avatar asked Mar 27 '15 17:03

doctorgester


People also ask

Do generics prevent compile time errors?

Using generics in your Java development can help you detect issues during compile time rather than being confronted by them at run time. This gives you greater control of the code and makes the syntax easy to follow. Generics also improves code readability.

Are generics runtime or compile time?

Generics are checked at compile-time for type-correctness. The generic type information is then removed in a process called type erasure. For example, List<Integer> will be converted to the non-generic type List , which ordinarily contains arbitrary objects.

Do generics allow for code reuse?

In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs.


1 Answers

The compilation error should be something along the lines of "capture of ? #1 is not compatible with capture of ? #2". The cause of this error is that wrapper is a Wrapper<?>.

The compiler sees that the wrapper.getCurrent() returns a Generic<?>, and that wrapper.doSmth takes a Generic<?> as a parameter. But it won't equate the two ? wildcards, even if we can see that they come from the same instance and should be the same.

One solution here is to make the App class generic, so you can replace the wildcard.

public class App<T> {

Because of the fact that Generic and Wrapper are inner classes, T is still in scope, so you don't need to declare a generic type parameter for them any more.

    Wrapper wrapper;

    class Generic{

    }

    class Wrapper{
        Generic current;

        public void doSmth(Generic generic){
        }

        public Generic getCurrent(){
            return current;
        }
    }

    public void operation(){
        wrapper.doSmth(wrapper.getCurrent());
    }
}
like image 170
rgettman Avatar answered Oct 13 '22 13:10

rgettman