1

Something I live with for long but I didn't ever understood..

The question is the comment :

import java.util.ArrayList;
import java.util.List;

    public class Test {

        public static class Test1 {
            public List<String> getStrings(){
                List<String> s  = new ArrayList();
                s.add("test1");
                return s;
            }
        }

        public static class Test2<PARAM> {
            public List<String> getStrings(){
                List<String> s  = new ArrayList();
                s.add("test2");
                return s;}
        }

        public static void main(String[] args) {
            Test1 test1 = new Test1();
            Test2 test2 = new Test2();
            for (String string : test1.getStrings()) {
                System.out.println(string);
            }
            // Why do I need this cast (List<String>) ?
            for (String string : (List<String>)test2.getStrings()) {
                System.out.println(string);
            }
        }
    }

So why do I need the cast (List) ?

Franck

  • Because `Test2` is generic and you use it with a raw type – Eran Dec 12 '19 at 13:49
  • Mmm . doesn't calm my undestanding appetite ;). Found this post in the interval : https://stackoverflow.com/questions/11007723/combining-raw-types-and-generic-methods – Franck Lefebure Dec 12 '19 at 13:59
  • That's a good interview question – Bentaye Dec 12 '19 at 14:00
  • Read this - https://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it - if you want the whole story. – Eran Dec 12 '19 at 14:01
  • The link you found is correct, declaring `Test2 test2 = new Test2<>();` works you don't need the cast anymore – Bentaye Dec 12 '19 at 14:02

3 Answers3

0

Instantiate it like this

Test2<String> test2 = new Test2<>();

I used <String> as a type for demonstration purposes

As mentioned before, you need to specify the type of Test2

Benjamin Slabbert
  • 511
  • 2
  • 9
  • 9
  • 2
    maybe use `Test2 test2 = new Test2<>();` as an example to show that the type of the class is not linked to the type of the list – Bentaye Dec 12 '19 at 14:03
0

You need to specify all with generic parameter types, as otherwise the compiler reverts to pre-<> semantics, where List gives only Object elements.

    public static class Test1 {
        public List<String> getStrings(){
            List<String> s  = new ArrayList<>(); // ***
            s.add("test1");
            return s;
        }
    }

    public static class Test2<PARAM> {
        public List<String> getStrings(){
            List<String> s  = new ArrayList<>(); // ***
            s.add("test2");
            return s;}
    }

    public static void main(String[] args) {
        Test1 test1 = new Test1();
        Test2<Integer> test2 = new Test2<>(); // ***
        for (String string : test1.getStrings()) {
            System.out.println(string);
        }
        // Why do I need this cast (List<String>) ?
        for (String string : test2.getStrings()) { // ***
            System.out.println(string);
        }
    }
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
0

I think this is a quirk in the compiler with generics and type erasure. When a compiler compiles a generic class it does all the type checking then strips all the <> and creates byte code that basically looks like

List list = new ArrayList();

Notice no type parameters.

the class will compile to

public static class Test2 {

}

if you have type parameters:

public T returnT(){
    return T;
}

compiles to

public Object returnT(){
   return Object;
}

It appears that if you create a generic class without a type

Test2 test2 = new Test2<>();

the compiler knows theres something wrong and asks you to explicitly cast.

 for (String string : (List<String>)test2.getStrings()) {
                System.out.println(string);
            }

If you add the type

Test2<Integer> test2 = new Test2<>(); // can put any type here as we're not actually using the type

the compiler can do some type checking and it deduces that the getStrings is of type String so it compiles

  for (String string : test2.getStrings()) {
            System.out.println(string);
        }

take a look here for further reading

Cwrwhaf
  • 324
  • 3
  • 5