Catalogue
- Overview
- Introduction and use of generics
- Generic classes
- Generic methods
- Qualification of type variables
- Use of wildcards
- Unbounded wildcard
- Upper wildcard bound
- Lower wildcard bound
Overview
The generic mechanism has always been used in projects, such as ArrayList, Map, etc. in collections. Not only that, the generic mechanism is used in many source codes, so learn more about it. Generic related mechanisms are very helpful for reading source code and writing your own code. However, I have never understood many of the mechanisms and features in it, especially the wildcards. I often forget about the upper and lower bounds of wildcards every time I use Baidu. This time I will make a summary to deepen my understanding.
Introduction and use of generics
Generics do not set the specific types of attributes or method parameters in the class when the class is defined. Instead, the type is defined when the class is used (creating the object). Type errors will be checked during compilation to ensure the readability and safety of the program.
Generic definitions can be divided into generic classes and generic methods according to the actual situation:
Generic class
public class Point { private T pointX; private U pintY; public Point(T pointX, U pintY) { this.pointX = pointX; this.pintY = pintY; } public void showPoint() { System.out.println(pointX); System.out.println(pintY); } }
- Introduce type variables into the class. Type variables refer to T and U. They are enclosed in angle brackets and follow the class name.
- Multiple type variables can be separated by commas.
- Type variables can be used in methods and return values in classes.
- Type variables are in uppercase and must be brief. Generally, E represents the element type of the set, and K and V represent key and value.
- Use generic classes: Point
Generic methods
public class FxMethod { public static T getMiddleNumber(T ... numbers) { return null; } public void showNumber(T t, U u) { System.out.println("t = " + t); System.out.println("u = " + u);; } }
- Introduce type variables into the method, add before the return type, place the type variable in the middle, and separate multiple type variables with commas.
- Type variables can be used in method parameters and return values.
- Use generic methods:
Integer result = FxMethod.getMiddleNumber(2, 3)
orInteger result = FxMethod.getMiddleNumber(2, 3)
code>.
Limitations of type variables
We have explained two ways of generally defining generics. There are no restrictions on the type variables. This means that on the one hand, some APIs cannot be used when defining generics and need to be forced. On the other hand, when using It is also error-prone, so how to add qualifications to type variables?
- It can only be qualified by the extends keyword, not the super keyword.
- After adding the limit, you can directly use the API related to the limit class.
- Use the ampersand between multiple qualifications, such as
T extends Number & Comparable
. - When using generics, only corresponding qualified classes can be passed in. For example, if Point is passed in, a compilation error will be reported.
Using wildcards
The introduction of generics has indeed solved a lot of problems, but is it perfect?
class AnimalWrapper { private T animal; AnimalWrapper(T animal) { this.animal = animal; } public void eat() { animal.eat(); } } class Animal { private String name; public void eat() { System.out.println("animal eat -----"); } } class Cat extends Animal { @Override public void eat() { System.out.println("cat eat -----"); } }
Define an AnimalWrapper and limit the generic variable to Animal. What will happen if it is the following test class?
A compilation error will be reported because AnimalWrapper is not a subclass of AnimalWrapper and cannot be passed in directly. In order to solve this problem, we introduced wildcards. Wildcards are generally used in methods or when using generic classes.
AnimalWrapper can be used as AnimalWrapper subtype, this is the benefit of using wildcards.
- Uniform characters are used in parameter return values of collections or methods.
- Wildcards can be divided into unbounded wildcards, upper-bounded wildcards and lower-bounded wildcards.
Boundless��Wildcard
The wildcard has no boundaries and can be passed in any type without restrictions, which is equivalent to Object.
Basic syntax:
Example:
public static void printList1(List list) { for (Object x:list) { System.out.println(x); } } public static void main(String[] args) { List list = new ArrayList(); list.add(1); printList1(list); // ok List list2 = new ArrayList(); list2.add("1"); printList1(list2); // ok List list3 = list; //get can only be accepted with Object, Object o = list3.get(0); list3.add(5); // compile error list3.add(new Object()); // compile error }
Summary:
- Unbounded wildcard is equivalent to Object, any type can be passed in, such as
List list, List list2
. - Because? It is impossible to determine which type it is, so you can only use Object type variables to receive it, such as in the example:
Object o = list3.get(0);
- If it is unbounded The collection type corresponding to the wildcard character cannot add any elements. Because it is impossible to determine the type of data stored in the collection, who knows what type we should put in it.
Wildcard upper bound
The wildcard upper bound can limit the type passed in to the upper bound class or a subclass of this class.
Basic syntax:
//The actual parameter type that can be passed in is Number or a subclass of Number
Example:
public static void printList1(List list) { for (Object x:list) { System.out.println(x); } } public static void main(String[] args) { List list = new ArrayList(); list.add(1); printList1(list); // ok List list1 = new ArrayList(); list1.add(1.0D); printList1(list1); // ok List list2 = new ArrayList(); list2.add("1"); printList1(list2); // compile error List list3 = list; // Get can use the upper bound Number o = list3.get(0); //cannot add list3.add(5); // compile error list3.add(new Object()); // compile error }
Summary:
- The upper bound of wildcard? extends A, indicating that all classes or subtypes of A can be passed in. For example, Integer and Double in this example are both subclasses of Number, but String is not.
- Wildcard upper bound? extends A, it is determined that the type is A or a subclass of A, then getting the data from the collection container must be its upper bound class A, because the other classes are Subclasses of A, such as
Number o = list3.get(0);
- If you add elements to the wildcard upper bound set, it will fail. List, indicating that the container can hold A or a subclass of A, but there are many subclasses of A, and you are not sure which one to put. For the sake of safety, you are not allowed to add directly, such as
list3.add(5);
, although 5 is a subclass of Number, it still cannot be added.
Wildcard lower bound
The wildcard lower bound can limit the type passed in to this class or the parent class of this class.
Basic syntax:
//Represents that the type of the actual parameter that can be passed in is Integer or the parent type of Integer
Example:
public static void printList1(List list) { for (Object x:list) { System.out.println(x); } } public static void main(String[] args) { List list = new ArrayList(); list.add(1); printList1(list); // ok List list1 = new ArrayList(); list1.add(1.0D); printList1(list1); // compile error List list2 = new ArrayList(); list2.add("1"); printList1(list2); // compile error List list3 = list; //Cannot use lower bound to receive Integer o = list3.get(0); // compile error //can add list3.add(5); // ok list3.add(new Number(5)); // compile error }
- The upper bound of wildcard? super A, indicating that all classes of A or the parent class of A can be passed in.
- Upper bound of wildcard? super A. If it is determined that the type is A or the parent class of A, then the data is obtained from the collection container get. It cannot be determined whether it is A or a parent class of A, so it cannot be get.
Integer o = list3.get(0); // compile error
, for example, Integer is used to receive in the example. If list3 is of Object type, it will be a problem. - If you add an element to the wildcard lower bound collection, you can only add subclasses of the next class. For example, in the example:
list3.add(5)
, the wildcard character of list3 is, which means that the collection stores Integer or the parent class of Integer. I This is true as long as Integer and its subclasses are placed in the container.
This concludes this article about generics and wildcards in Java. For more information about Java generics and wildcards, please search for previous articles in Programming Notes or continue to browse the following related articles. I hope you will support Programming Notes more in the future!
per Integer>, indicating that the collection stores Integer or the parent class of Integer. As long as I put Integer and its subclasses into the container, it will be established.
This concludes this article about generics and wildcards in Java. For more information about Java generics and wildcards, please search for previous articles in Programming Notes or continue to browse the following related articles. I hope you will support Programming Notes more in the future!