简体   繁体   中英

Java Generics type safety

I once read that Java Generics brings the type safety that was previously missed with handling Object references and including explicit casts by making all casts implicit and automatic . I studied Generics and understand its mechanics, but I still can't see how automatically generated implicit casts brings type safety over explicit casts that were used prior to Generics - I mean, I still could use explicit casts and achieve the same effect.. ?

Generics seems to have simply streamlined the process by taking what had been a sole programming approach on the programmer's side and make into a feature of the language, simplifying the process by really handling/adjusting code for the programmer..?

but I still can't see how automatically generated implicit casts brings type safety over explicit casts that were used prior to Generics -

You have not a automatically generated implicit cast (downcast) in raw types, you have to explicit cast from Object to a specific type as a raw type can take any Object and the problem is there.

For example here you don't have type safety as you can put anything in a List that functionally should contain only String :

List listOfString = new ArrayList();
listOfString.add("myString"); // compile 
listOfString.add(5); // compile (not a String)
String expectedStringButNot = (String) listOfString.get(1); // ClassCastException at runtime

With generics, you have type safety as you could not put anything in a List that functionally should contain only String as the compiler will stop before :

List<String> listOfString = new ArrayList<>();
listOfString.add("myString"); // compile 
listOfString.add(5); // doesn't compile (not a String)

To answer your question: indeed, generics are in fact designed to provide additional compile-time checking. Stronger than that, generic types are erased at runtime. They provide no additional "functionality" to Java itself.

Generic kind of 'replaced' some casts that were needed when generic weren't there.

// My list of strings
List list = new ArrayList();
list.add("Hello");
String str1 = list.get(0); // Won't work
String str2 = (String) list.get(0);

The compiler was simply not sure that the list only contained String object, although the programmer was sure he only put Strings in it.

// My list of strings
List<String> list = new ArrayList<>(); // <> means <String> in this case
list.add("Hello");
String str1 = list.get(0); // works
String str2 = (String) list.get(0); // The typecast is unnecessary,
                                    // for the compiler already knows
                                    // that the list could only contain
                                    // strings

So in the first code snippet, the typecast to String was necessary because you simply got an Object from the list. In the second snippet however, the typecast is made unnecessary.

Consider the example

HashMap<String, Integer> map = new HashMap<String, Integer>();
Set<String> st = map.keySet(); // This will only contain String objects

In this example it ensures that st will only contain String objects. This reduces the possibility of run time errors due casting.

Additionally

Set<String> st = new Set<String>();
st.add("a");  // allowed
st.add('a');  // compile time error

Here the compile time error will identify the problem, so hours debugging can be avoided.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM