Java generic learning and practice (4), java generic
Introduction
The first three sections describe the common declarations and usage of generics. Generics can be declared on classes or on a single method, the two cases are summarized respectively. Next we will learn about generic extension.
Extended the previous Runnable interface, Buick class, Ford class, Driver Class, and added a new car container class CarContainer
First version
The Code is as follows:
public interface Runnable { public void run();}
public class Buick implements Runnable { @Override public void run(){ System.out.println("buick run"); } public void autoRun(){ System.out.println("buick auto-run"); }}
public class Ford implements Runnable { @Override public void run(){ System.out.println("ford run"); } public void fly(){ System.out.println("ford fly"); }}
<pre name="code" class="java">public class Driver<T extends Runnable> { private T car; public void drive(T car){ this.car = car; System.out.println("I am driving a " + car); car.run(); } public T getDrivingCar(){ return car; }}
public class CarContainer<E extends Runnable> { private List<E> container = new ArrayList<E>(); public void add(E e) { container.add(e); } public void add(Driver<E> producer) { container.add(producer.getDrivingCar()); } public static void main(String[] args) { CarContainer<Runnable> container = new CarContainer<Runnable>(); Buick buick = new Buick(); container.add(buick); Driver<Runnable> driver = new Driver<Runnable>(); driver.drive(buick); container.add(driver); }}
The first three classes are not mentioned. For details, refer to the first three sections. Let's talk about the CarContainer class. The add method receives generic E-type objects and adds cars to containers. The other overload add method receives the Driver <E> parameter, obtains the drivingCar, and adds it to the container.
The main static method demonstrates the use of the two add methods. First, let's look at the use of the first add method. Because the Buick class implements the Runnable interface, the container. add (buick) is called in this way, and the second add method is used: first, driver. drive (buick) is no problem, the principle is the same as above; then look at the container. add (driver), because the element type of the container is the Runnable interface, and the element type of the driver is also the Runnable interface, the type is completely matched, so there is no problem in running the program, it looks wonderful.
If there is a Driver <Buick>, you can think about this call.
Driver<Buick> driver = new Driver<Buick>(); driver.drive(buick); container.add(driver);
The result is no. the following error is prompted during compilation:
The method add (Runnable) in the type CarContainer <Runnable> is not applicable for the arguments (Driver <Buick>)
Logically, this call should be possible, because the Buick implements the Runnable interface, but it does not actually work. Fortunately, there is a solution. JAVA provides a special parameter type called bounded wildcard type to handle similar situations. Our idea is that the parameter received by the second add method should be "a sub-type Driver of E? Extends E> implementation .? Represents any unknown type. The extends E restriction is added, indicating that the unknown type must be a subclass of E or its own. The modified code is as follows:
Version 2
public void add(Driver<? extends E> producer) { container.add(producer.getDrivingCar()); }
After this modification, the demo program can be compiled and run normally, which indicates that the type is safe.
What is the first wildcard related to generics ?, Unknown type. The usage is described below.
?
? It usually appears in the method parameter, representing the unknown type. Note that it is different from the efield in the generic declaration. Generic E is equivalent to a type placeholder. It can appear in multiple places in the class and means that the specific types in the future are the same (for example, the generic type in the Driver class and the CarContainer); and? Represents an unknown specific type. It appears in multiple places of the class? There is no association.
? Supported <? Extends Parent> usage, which indicates that the unknown type must be a subclass of the Parent or its own, which is similar to <E extends Parent> in the generic type.
? <? Super Child> usage indicates that the unknown type must be Child's superclass or itself. This usage does not exist in the generic type (because it is meaningless). Note that.
<? Super Child> usage. Next, let's take a look at the usage scenarios of super.
For the CarContainer class, we add a pop method corresponding to the add method, as follows:
public void pop(Set<E> consumer){ consumer.add(container.remove(container.size())); }
Receives the consumer parameter of the Collection class. The method body removes the last element from the container and adds it to the consumer. Example:
CarContainer<Runnable> container = new CarContainer<Runnable>(); Buick buick = new Buick(); container.add(buick); Set<Runnable> consumer = new HashSet<Runnable>(); container.pop(consumer);
If you have another Set <Object> consumer = new HashSet <Object> (), if you follow the above call, a compilation error occurs:
The method pop (Set <Runnable>) in the type CarContainer <Runnable> is not applicable for the arguments (Set <Object>)
Our idea is that the parameter application received by pop is "a super Set of E", through? This can be achieved with the super keyword, that is, Set <? Super E>. The modified code is as follows:
Third Edition
public void pop(Set<? super E> consumer){ consumer.add(container.remove(container.size())); }
After modification, the Set <Object> consumer call method is supported.
Pass? When used with the extends or super keywords in method parameters, you can obtain the maximum flexibility of the API.
Then, when should the extends keyword be used, and when should the super keyword be used. One principle is PECS, that is, producer-extends and consumer-super.
PECS means that if a Wildcard parameterized type is used to represent an E producer, <? Extends E>; use <? Super E>. In the preceding example, the add producer parameter generates an instance of E for the CarContainer, so the corresponding producer type is Driver <? Extends E>; the consumer parameter of pop consumes E instances through CarContainer, so the corresponding type of consumer parameter is Set <? Super E>. What if the parameter is both the producer and the consumer ?, Because you need strict type matching, that is, directly use Set <E>
What are the wildcard characters above? Extendsand superusers refer to 《effective.java_2 .pdf. Due to the limited level, you may not understand it yet. You are welcome to ask questions.
This practical demonstration is not used in the project for the time being. It will be added later.
Conclusion
This is the end of extensive learning and practices. There are four sections in total. Thank you for your attention. Now that we have time, I want to study the design model with you. I think this is also a required course for every Java programmer. Coming soon