Why is this piece of code not compiling

There is a small piece of code here and I don't understand why javac cannot compile it. What do I miss? Are there any mistakes?

public class HelloWorld<T> {
    private static enum Type {
    }

    private T value;
    private List<Type> types = new ArrayList<>();

    public T getValue() { return value; }

    public List<Type> getTypes() { return types; }

    public static void main( String[] args ) {
        for ( Type type : new HelloWorld().getTypes() ) { // Error: Type mismatch: cannot convert from element type Object to HelloWorld.Type

        }
    }
}

      

Why does it getTypes()

return a Object

(raw) list when it should Type

list?

Link to online compiler

+3


source to share


4 answers


This looks like a compiler limitation to me. getTypes

always returns List<Type>

, so using raw HelloWorld

is irrelevant.

However, either of these two solutions will overcome the error:



  • Create a parameterized type HelloWorld

    instead of a raw type:

    for (Type type : new HelloWorld<Integer>().getTypes() ) { // any type will do, I chose 
                                                              // Integer arbitrarily to show
                                                              // that it doesn't matter
    
    }
    
          

  • Use a local variable to store the list before using it:

    List<Type> types = new HelloWorld().getTypes();
    for (Type type : types) { 
    
    }
    
          

In any case, parameterized types should always be preferred over raw types, so I'll use the first solution (with whatever type parameter makes sense in your class).

+3


source


While experimenting with your code, I noticed something very interesting. To remove the compiler error:

Error: Type Mismatch: Cannot Convert from Object Type to HelloWorld.Type

Since it states that the returned item is of type Object

, I decided to inject it in List<Type>

as shown:

public static void main( String[] args ) {
    for ( Type type : (List<Type>)new HelloWorld().getTypes() ) { 

    }
}

      

This compiled successfully with a warning, so I used -Xlint

with javac

to find out what the warning is and I found this:

HelloWorld.java:15: warning: [rawtypes] found raw type: HelloWorld
        for ( Type type : (List<Type>)new HelloWorld().getTypes() ) {
                                          ^
  missing type arguments for generic class HelloWorld<T>
  where T is a type-variable:
    T extends Object declared in class HelloWorld
HelloWorld.java:15: warning: [unchecked] unchecked cast
        for ( Type type : (List<Type>)new HelloWorld().getTypes() ) {
                                                               ^
  required: List<Type>
  found:    List
2 warnings

      

Here I was amazed to see the second warning. It states what is required List<Type>

but found List

a RAW TYPE . So this means that if you initialize an object of a raw type and call a method that returns a generic variable, that variable will also be converted to RAW TYPE . To test this, I implemented the class HelloWorldTest

as:

public class HelloWorldTest<T>{
    private T t;

    public HelloWorldTest(T t){
        this.t = t;
    }

    public T getT(){
        return t;
    }
}

      

Then I changed my code to check the condition like this:

public class HelloWorld<T> {

    private HelloWorldTest<Integer> test = new HelloWorldTest<>(1);

    public HelloWorldTest<Integer> getTest(){
        return test;
    }

    public static void main( String[] args ) {
        HelloWorldTest<Integer> hello = new HelloWorld().getTest();
    }
}

      

This compiles successfully, but with warnings, so using the switch -Xlint

to compile, I get the following warnings:

HelloWorld.java:10: warning: [rawtypes] found raw type: HelloWorld
        HelloWorldTest<Integer> hello = new HelloWorld().getTest();
                                            ^
  missing type arguments for generic class HelloWorld<T>
  where T is a type-variable:
    T extends Object declared in class HelloWorld
HelloWorld.java:10: warning: [unchecked] unchecked conversion
        HelloWorldTest<Integer> hello = new HelloWorld().getTest();
                                                                ^
  required: HelloWorldTest<Integer>
  found:    HelloWorldTest
2 warnings

      

So, here also we find that it has HelloWorldTest

been converted to a raw type.



Finally, we can conclude that: If you initialize a raw object and call a method that returns a generic variable, that variable will also be converted to RAW format .

Now that I have replaced

    HelloWorldTest<Integer> hello = new HelloWorld().getTest();

      

from

    Integer hello = new HelloWorld().getTest().getT();

      

As expected, I got the error:

HelloWorld.java:10: error: incompatible types: Object cannot be converted to Integer
        Integer hello = new HelloWorld().getTest().getT();
                                                       ^
1 error

      

Finally, if you replace the main method in my class implementation with the HelloWorld

following:

    public static void main( String[] args ) {
        String hello = (String) new HelloWorld().getTest().getT();
    }

      

It compiles successfully with a warning:

HelloWorld.java:10: warning: [rawtypes] found raw type: HelloWorld
            String hello = (String) new HelloWorld().getTest().getT();
                                        ^
  missing type arguments for generic class HelloWorld<T>
  where T is a type-variable:
    T extends Object declared in class HelloWorld
1 warning

      

This is quite misleading as it will definitely fail at runtime and again illustrates the dangers of RAW TYPE in generics.

+1


source


modify the for

loop to add a generic type for the class:

for example, for example: "I used" Type

"as an example.

for ( Type type : new HelloWorld<Type>().getTypes() ) {

      

Edit:

It can be "String" and is also indicated in the comments (thanks for that). In your case, this should be the actual type you need for this class.

The idea is that there was no generic type to add.

0


source


Inside the method main

:

for ( Type type : new HelloWorld().getTypes() ) {//Here also you did not mention the type for the new object since 
}

      

Try this in your main method:

for ( Type type : new HelloWorld<Type>().getTypes() ) {

}

      

0


source







All Articles