Why doesn't add(String) on a List pas

2020-07-06 21:12发布

问题:

Why is it possible to insert a String into a List<Integer> in the following code? I have a class which inserts numbers into a List of Integers:

public class Main {    
    public static void main(String[] args) {        
        List<Integer> list = new ArrayList<Integer>();
        list.add(2);
        list.add(3);
        list.add(4);

        Inserter inserter = new Inserter();
        inserter.insertValue(list);
        System.out.print(list);        
    }
}

Then I have a separate class which inserts a String into a List, with the numeric string value "42":

public class Inserter {    
    void insertValue(List list)
    {
        list.add(new String("42"));
    }
}

Why does the compiler not raise a compiler error, or the runtime throw a runtime exception such as *CastException, when I add the String to the List of Integer? Also, why does System.out.print(list) produce output like the following without throwing any exceptions?

[2, 3, 4, 42]

What is the fundamental reason that allows all this to happen?

回答1:

This is probably an example to illustrate type erasure for generics (I recommend reading that link to fully understand this and the crucial role it plays in Java generics).

  1. list is declared as a List<Integer>
  2. When it is passed as an argument to listValue it is cast to a raw type
  3. From this point onwards in that method the program at run time has no knowledge that it was originally a "list of Integer", so it can insert any object with no exception - within the class declaration the type variable is erased to Object
  4. In the main method the print command simply calls toString on the list, which doesn't mind what it contains, and so it prints the elements including the string.

If you want to see an exception, try adding a line:

Integer myInt = list.get(3); // try to get the string

This will throw a ClassCastException as the compiler, during erasure, inserts casts where necessary to protect type safety.

Casts of parameterized types, such as List<Integer> to the raw type, such as List, give you a compiler warning to tell you that exactly this kind of problem might be about to happen. You can suppress that warning with @SuppressWarnings("unchecked") (or "rawtypes", if it is available to you). This is a good way of "acknowledging" that you are about to do something that will lead to an unchecked runtime exception, and also helps tell other future coders that something funky might be about to happen. E.g.:

void insertValue(@SuppressWarnings("unchecked") List list)
{
    list.add(new String("42"));
}


回答2:

The compiler will throw

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 234 at com.performance.Main.main(Main.java:26)

as you specified the type here ArrayList<Integer>(); and when you are adding a string list.add(new String("42"));



标签: java generics