Tags: Java foundation
What are generics?
Java generics design principle: As long as there are no warnings at compile time, there should be no ClassCastException at run time
Generics: Postpone specifying specific types until object creation or method invocation time
Parameterized types:
- Pass the type as if it were an argument
- < data type > can only be a reference type
Related terms:
ArrayList<E>
In theE is called the type parameter variableArrayList<Integer>
In theInteger is called the actual type parameter- The whole is called
ArrayList<E>
The generic type - The whole
ArrayList<Integer>
Called a ParameterizedType
Why generics
In the early days of Java, Object was used to represent arbitrary types, but the downward transition had the problem of strong conversions, which made the program unsafe
First, consider: what would collections look like without generics
- There are no restrictions on the types of elements in collections and maps. My Collection originally loaded all Dog objects, but there is no syntax error in storing Cat objects outside the Collection.
- You throw an Object into a collection that doesn’t know what type the element is, just that it’s Object. So when WE get(), we return Object. To obtain the object externally, a cast is required
With generics:
- Cleaner code [no cast]
- More robust applications (as long as there are no warnings at compile time, there are no ClasscastExceptions at run time)
- Readability and stability [when writing collections, the type is qualified]
Iterate through the collection using the enhanced for
When we created the collection, we identified the collection type, so we can use enhanced for to iterate over the collection!
// Create a collection object
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
// traversal, because the type is clear. We can enhance for
for (String s : list) {
System.out.println(s);
}
Copy the code
basis
A generic class
A generic class defines a generic type on a class. When the user uses the class, the type is specified…. In this case, the class represents whatever type the user has identified… Users do not have to worry about strong conversion problems when using, runtime conversion exceptions.
- Generics defined on a class can also be used in a class’s methods!
2. Type variables are defined on the class. You can also use */ in methods
public class ObjectTool<T> {
private T obj;
public T getObj(a) {
return obj;
}
public void setObj(T obj) {
this.obj = obj; }}Copy the code
- Test code:
Which type the user wants to use is specified at creation time. When used, the class is automatically converted to the type the user wants to use.
public static void main(String[] args) {
// Create the object and specify the element type
ObjectTool<String> tool = new ObjectTool<>();
tool.setObj(new String("Zhong Fucheng"));
String s = tool.getObj();
System.out.println(s);
// Create the object and specify the element type
ObjectTool<Integer> objectTool = new ObjectTool<>();
/** * if I pass a String into this object, it will not pass at compile time
objectTool.setObj(10);
int i = objectTool.getObj();
System.out.println(i);
}
Copy the code
Generic method
Generic classes have already been introduced, and you can also use….. in methods for generics defined on classes
For now, we may need to use generics…. for only one method The outside world only cares about the method, not the other properties of the class… So it’s a bit of a stretch to define generics on an entire class.
- Define generic methods…. Generics are defined before they are used
// Define generic methods..
public <T> void show(T t) {
System.out.println(t);
}
Copy the code
- Test code:
What type is passed in by the user, and what type is returned
public static void main(String[] args) {
// Create an object
ObjectTool tool = new ObjectTool();
// Call the method. What type of argument is passed in and what type is returned
tool.show("hello");
tool.show(12);
tool.show(12.5);
}
Copy the code
A subclass derived from a generic class
We have already defined a generic class. A generic class is a class that has the property of generics and is essentially a Java class, so it can be inherited
So how is it inherited? There are two cases here
- Subclasses specify the type parameter variables of the generic class
- A subclass does not specify the type parameter variable of a generic class
Subclasses specify the type parameter variables of the generic class
- A generic interface
/* Define generics on interfaces */
public interface Inter<T> {
public abstract void show(T t);
}
Copy the code
- Classes that implement generic interfaces…..
/** * Subclasses specify the type parameter variable of the generic class: */
public class InterImpl implements Inter<String> {
@Override
public void show(String s) { System.out.println(s); }}Copy the code
A subclass does not specify the type parameter variable of a generic class
- When a subclass does not specify the type parameter variable of the generic class, it is also required to pass in the type parameter variable when using the subclass, and to define the type parameter variable on the implementation class
/** * subclasses do not specify the type parameter variables of generic classes: * The implementation class also defines the ** / of type
public class InterImpl<T> implements Inter<T> {
@Override
public void show(T t) { System.out.println(t); }}Copy the code
Test code;
public static void main(String[] args) {
// Test the first case
//Inter<String> i = new InterImpl();
//i.show("hello");
// Test the second case
Inter<String> ii = new InterImpl<>();
ii.show("100");
}
Copy the code
It is worth noting:
- If an implementation overrides a method of the parent class, the return value must be of the same type as the parent class.
- Generics declared on a class are valid only for non-static members
Type wildcard
Why is the type wildcard ???? needed Let’s look at a requirement…….
Now we have a requirement: the method takes a collection parameter, iterates through the collection, and prints the collection elements.
- Before we learned generics, we might have done something like this:
public void test(List list){
for(int i=0; i<list.size(); i++){ System.out.println(list.get(i)); }}Copy the code
The above code is correct, except for a warning at compile time that the type of the collection element is not determined…. It’s not elegant…
- So we learned about generics, now what do we do? Some people might do this:
public void test(List<Object> list){
for(int i=0; i<list.size(); i++){ System.out.println(list.get(i)); }}Copy the code
The syntax is fine, but it’s worth noting that the test() method can only iterate over collections containing objects!!
Note:
So what now?? List
:…….. So Java generics provide type wildcards?
So the code should look like this:
public void test(List
list){
for(int i=0; i<list.size(); i++){ System.out.println(list.get(i)); }}Copy the code
? The wildcard character indicates that it can match any type, and any Java class can match…..
Now it’s very noteworthy that when we use? When a wildcard character is used, only methods that are independent of the object type can be called, not methods that are dependent on the object type.
Remember that you can only call methods that are independent of an object, not methods that are related to an object’s type. Because you don’t know what the exact type is until you use it externally. In other words, I can’t use add() on the List above. Because the add() method drops the object into the collection, and now I don’t know what type the object is.
Set the upper limit for wildcards
First, let’s take a look at where we use wildcard caps….
Now I want to receive a List that can only operate on numeric elements (Float, Integer, Double, Byte, etc).
We learned about wildcards, but if we use wildcards directly, the set doesn’t just manipulate numbers. So we need to set the upper limit of wildcards
List<? extends Number>
Copy the code
The List collection can only load elements that are subclasses of Number or themselves
public static void main(String[] args) {
// The List collection is loaded with Integer and can be called
List<Integer> integer = new ArrayList<>();
test(integer);
// The List collection is loaded with strings, which was reported at compile time
List<String> strings = new ArrayList<>();
test(strings);
}
public static void test(List<? extends Number> list) {}Copy the code
Set the lower limit for wildcards
Now that we’ve talked about how to set upper limits on wildcards, setting lower limits on wildcards is not new. Let’s get straight to the grammar
// Only Type or its parent can be passed in
<? super Type>
Copy the code
It is not uncommon to set a lower limit for wildcards, such as…. in the TreeSet collection Let’s see
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
Copy the code
So what does it do? Let’s think about when we want to create a variable of type TreeSet
and pass in a Comparator that compares the String size.
It can be a Comparator
or a parent of String. For example, when Comparator
….
When you do that, you’re very flexible. That is, as long as it can compare string sizes, it’s fine
It is important to note that you cannot operate on methods related to objects, either by setting the upper or lower limits of wildcards. Whenever wildcards are involved, their types are undefined!
Wildcards and generic methods ##
Most of the time, we can use generic methods instead of the wildcard…..
// Use wildcards
public static void test(List
list) {}// Use generic methods
public <T> void test2(List<T> t) {}Copy the code
Both of the above methods are ok….. So the question is, do we use wildcards or do we use generic methods?
Principle:
- If there is a type dependency between the parameters, or if the return value is dependent on the parameters. Then use the generic method
- If there are no dependencies, use wildcards, which are more flexible.
erase
Generics are provided for use by the JavAC compiler to restrict the input type of a collection, allowing the compiler to prevent illegal data from being inserted into the collection at the source level. However, after the compiler compiles a Java program with generics, the generated class file will no longer contain the generics information, so that the efficiency of the program is not affected. This process is called “erasing”.
compatibility
The concept of generics was introduced in JDK5, but there were no generics in JDK5 before. Generics need to be compatible with collections up to JDK5.
When assigning a generic property to an older version of the collection, the generics are erased.
It is worth noting that it retains an upper limit on type parameters.
List<String> list = new ArrayList<>();
// The type is erased to preserve the upper limit of the type. The upper limit of String is Object
List list1 = list;
Copy the code
What if I assign a set with no type parameters to a set with type parameters?
List list = new ArrayList();
List<String> list2 = list;
Copy the code
It also doesn’t report an error, just an “unchecked conversion.”
If you find this article helpful, give the author a little encouragement
![](http://cloud.mo4tech.com/images/wZuBnLRVGcnNjR38SbvNmLyV3ZtlmLp9yL6MHc0RHa/5bcf3b5a9e3757b6d418e155622db436.png)