Java 17 Recipes
Download 3.2 Mb. Pdf ko'rish
|
Java 17 Recipes
How It Works
The solution code demonstrates some basic use cases for generics. The examples in the GenericsDemo.java file, contained within the recipe sources, go into more detail to demonstrate the use of generics with Java collections versus showing you how to create generic types. Unless you develop a library API, you probably won’t be creating your own generic types. However, if you understand how generics are used with the Collection interfaces and classes, you can create your own generic types. Chapter 7 Data SourCeS anD ColleCtionS 263 The first thing to understand and remember about Java generics is that they are strictly a compile-time feature that aids the developer in creating more type-safe code. All the type information that you specify when you parameterize a generic type gets “erased” by the compiler when the code is compiled down to byte code. You’ll see this described as type erasure. Let’s look at an example of a generic Collection type: the List. List is an interface defined as follows. public interface List Now that is a strange syntax, especially because there is no object or type identified as E. As it turns out, the E is known as a type parameter, which is a placeholder to indicate to the compiler that a type is assigned to the object at runtime. Type parameters are typically uppercased letters that indicate the type of parameter being defined. There are a variety of different type parameters to note, but keep in mind that these are only applicable when defining a generic type. In most cases, generic types are only defined when developing a library or API. • E – Element • K – Key • N- Number • T – Type • V – Value • S, U, V, and so on—second, third, and fourth types To specify the element type for a List (or any Collection type), simply include the type name in angle brackets when declaring and instantiating objects. When you do this, you are specifying a parameterized type. The following code declares a list of integers. A variable, aList, of the parameterized type List initialized with the reference obtained from the instantiation of the parameterized type, LinkedList List Now that you’ve parameterized these types to restrict the element type to Integers, the List add(E e) method becomes boolean add(Integer e); Chapter 7 Data SourCeS anD ColleCtionS 264 If you try to add anything other than an integer to aList, the compiler generates an error. aList.add(new Integer(121)); aList.add(42); // 42 is the same as new Integer(42), due to autoboxing. aList.add("Java"); // won't compile, wrong type It’s important to note that it’s the reference type checked at compile time, so the following also results in a compiler error. Number aNum = new Integer("7"); aList.add(aNum); // won't compile, wrong type This is a compile error because aNum could reference any Number object. If the compiler were to allow this, you could end up with a set containing doubles, floats, and so on, which would violate the Integer parameter constraint specified when you created aList. Of course, a simple type cast could get you around the compiler error, but this would surely cause unintended consequences when casting between incompatible Number objects. Generics were designed to reduce the amount of explicit type casting you must do in your code, so if you find yourself using explicit type casting when using methods of parameterized types, this is a clue of potentially dangerous code. aList.add((Integer)aNum); // compiles, but don't do this. Other things to watch out for when using generic types are compiler warnings. They may indicate that you’re doing something that is not recommended and it usually indicates that your code has a potential runtime error looming. An example can help to illustrate this. The following code compile but produce two compiler warnings. List rawList = new LinkedList(); aList = rawList; First, you’re creating rawList, which is a raw type, a generic type that isn’t parameterized. When generics were introduced into the language, the language designers decided that to maintain compatibility with pregenerics code, they would need to use raw types. However, the use of raw types is strongly discouraged for newer (post–Java 5) code, so compilers generate a raw type warning if you use them. Next, rawList is assigned to aList, which was created using parameterized types. Again, the compiler allows this (due to generics type erasure and backward compatibility). Chapter 7 Data SourCeS anD ColleCtionS 265 An unchecked conversion warning is generated for the assignment to flag potential runtime type incompatibility. Imagine if rawList contained strings. Later, if you tried to retrieve integer elements from aList, you would get a runtime error. Regarding type compatibility, it doesn’t apply to generic type parameters. For example, the following is not a valid assignment. List incompatible types Although integers are numbers (Integer is a subtype of Number), and LinkedList is a subtype of List, LinkedList this won’t slip by you if you accidentally write code like this. The compiler generates an “incompatible types” warning. So you may be wondering whether there is a way to achieve a variant subtyping relationship similar to what we tried to do in the previous line of code. The answer is yes, by using a generics feature called the wildcard. A wildcard is denoted by using a question mark (?) within the type parameter angle brackets. Wildcards declare parameterized types that are either bounded or unbounded. The following is an example declaration of a bounded parameterized type. List extends Number> cList; An upper bound is established for the type parameter when a wildcard is used with the extends keyword. In this example, ? extends Number means any type that is either a Number or a subtype of a Number. Therefore, the following would be valid assignments because both Integer and Double are subtypes of Number. cList = new LinkedList cList = new LinkedList cList = new LinkedList So, cList can hold a reference to any List instance with an element type compatible with Number. cList could even reference a raw type. This makes it a challenge for the compiler to enforce type safety to allow elements to be added to cList. Therefore, the compiler does not allow elements (other than a null) to be added to a collection type that is parameterized with ? extends. The following would result in a compiler error. cList.add(new Integer(5)); // add() not allowed; cList could be LinkedList Chapter 7 Data SourCeS anD ColleCtionS 266 However, you can get an element from the list without any problem. Number cNum = cList.get(0); The only restriction here is that the reference you get from the list must be treated like a number. Remember, cList could be pointing to a list of integers, a list of doubles, or list of any other subtype of Number. A wildcard can also be used with the super keyword. In this case, a lower bound is established for the type parameter. List super Integer> dList; In this example, ? super Integer means any type that is either Integer or any supertype of it. Therefore, the following would be valid assignments because Number and Object are the only supertypes of Integer. dList = new LinkedList dList = new LinkedList dList = new LinkedList 267 You see the use of the wildcard with both extends and super throughout the collection types. You often see them used in method parameter types, such as the addAll() method, which is defined for all collections. Sometimes you see the collection types using the wildcard (?) alone as a type parameter, which is called an unbounded Download 3.2 Mb. Do'stlaringiz bilan baham: |
Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling
ma'muriyatiga murojaat qiling