Java generic method returns another type - exception

I found some strange code where I said: "This is never called because it will throw a cast Exception class." Well, the code gets called and works.

Can someone explain to me: Why does this work ?

The getZipList () method is defined to return a list of strings, but internal logic returns a list with different objects. Also inside the main method, the list of strings is expected to be a “list”, but the list contains something else.

public class GenericMethodList{ public static void main(String [] args) { GenericMethodList o = new GenericMethodList(); List<String> list = o.getZipList(true); Iterator<?> iter = list.iterator(); while (iter.hasNext()){ ZipCode zipplace = (ZipCode) iter.next(); System.out.println(zipplace.value); } } public List<String> getZipList(boolean someParameter){ //why is this not throwing an exception at runtime? List list; if(someParameter){ list = getZipCodes();//List<ZipCode> } else { list = getZipStreets();//List<ZipStreet> } return list; } private List<ZipCode> getZipCodes(){ List<ZipCode> list = new ArrayList<ZipCode>(); list.add(new ZipCode("code1")); list.add(new ZipCode("code1")); return list; } private List<ZipStreet> getZipStreets(){ List<ZipStreet> list = new ArrayList<ZipStreet>(); list.add(new ZipStreet("street1")); list.add(new ZipStreet("street2")); return list; } public class ZipCode{ public String value; public ZipCode(String value){ this.value = value; } } public class ZipStreet { public String value; public ZipStreet(String value){ this.value = value; } } } 

Thanks so much for your explanation.

+6
source share
5 answers

You should get a "unchecked cast" compiler warning for the return list string because you are returning the raw type as a parameterized type. In this position, "uncontrolled selection" is performed from the raw type (for which there is simply no information about the type of elements) to the parameterized type declared for this method. A type parameter can be any arbitrary type - the compiler just does not know what to allow and what to prevent.

This cast is not checked in the sense that it cannot be executed at run time: at run time, parameters like list erased anyway, so the JVM does not know that you are doing a bad job.

+4
source

Because you are using a "type" of type "raw" (that is, a generic type without a given type parameter). Raw types exist for obsolete purposes, but they should be avoided in the new code, since it loses type safety, as you saw:

http://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html

0
source

You should receive a warning. Due to type erasure (the .class file does not actually list the parameterized type for backward compatibility), the List<E> runtime type is equal to the whole List , and the JVM does not see any difference. The error will appear in a remote place when someone tries to pull a String from this List and gets a ZipCode .

0
source

At compile time you should go down below.

  Note: Some input files use unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. 

Since Generics are based on erasure type implementations. Thus, at runtime, it has no information about the Generic type (usually called Non-Reifiable Types )

0
source

The problem is that you are combining RawType with a common one in your solution. You do this in the getZipList(boolean) method. Since List not of this type, you slow down type control. The next place you cheat the compiler is how you declare Iterator<?> , Since you are not declaring a generic parameter, I will store the object. So the next time you avoid the certainty that you are taking advantage of it to see where you are dropping the expected type. That is why his work. Casting is usually done by the compiler, but you implement it correctly yourself.

IF your code will look like this

  Iterator<String> iter = list.iterator(); while (iter.hasNext()){ ZipCode zipplace = (ZipCode) iter.next();// Compilation error System.out.println(zipplace.value); } 

IF your main method would look like this:

 while(String s : list) { System.out.wirteln(s); } 

A ClassCastException will be thrown. Because the code will "look like"

  Iterator<Object> iter = list.iterator(); while (iter.hasNext()){ ZipCode zipplace = (String) iter.next(); System.out.println(zipplace.value); } 

As in Java, you cannot use this method. Exception thrown.

To summarize, you created code that slows down type checking, but you have implemented its proper use. That is why his work.

0
source

Source: https://habr.com/ru/post/951385/


All Articles