Problems with collections in Java
The disadvantage of collections in Java is that when we put data into a collection, the collection does not remember the data type. That is, when we get the data from the collection again, the data type becomes the object type.
In other words, the collection has no restriction on the element type. This can be problematic, such as if we were to create a list collection that specifically stores strings, you could also put the integer type data into it. Even if the string data is put in, the type conversion is required (because the element type in the collection is object type) when it is removed from the list collection.
For example: Create a list collection that only holds strings, but numbers of integer types can also be saved. When you remove an element from the list collection, you need to force the type conversion.
public Class Demo {public static void main (string[] args) {//Create a The list collection that holds the string list List = new ArrayList (); List.add ( "Hello" ); List.add ( "world" ); List.add (1000 ); for (int i = 0 ; i < list.size (); i++) {String str = (string) list. get (i); System. out . println (str); } }}
If you want to solve the above case, we can customize the extension ArrayList to ensure that the custom ArrayList can only hold the string data type.
public Class Demo {private list list = new Arrayl IST (); //defines the Add method for custom ArrayList public boolean add (String ele) {return list.add (ele); } //override the Get method to change the type of the Get method's sweep to string type. public String get (int index) {return (String) list. get (index); } public int size () {return list.size (); }}
This approach, though effective, is very restrictive. In actual development, we need to customize a large number of list subclasses, increase the development workload, and not universal.
What is a generic type
After the Java 5 release, we provided generics to address the above problems. First, let's look at the following ArrayList source fragments:
public Class arraylist<e> {public int Span class= "Hljs-title" >size () {return size; } public boolean add (e e) {Ensurecapacityinte Rnal (size + 1 ); //increments modcount!! elementdata[size++] = e; return true ; } public E get (int index) {rangecheck (index); return elementdata (index); }}
By looking at the source code, we found that in the ArrayList underlying code, the ArrayList class followed the "" notation, which is actually generics. In the Add method and get method of the ArrayList class, we can also see that the Add method adds an element type of type E, and the Get method gets the type of the element returned by the E type.
So, we can take advantage of the generics provided after Java version 5 to solve the problem:
public Class Demo {public static void main (string[] args) {//Create a The list collection that holds the string list<string> list = new arraylist<string> (); List.add ( "Hello" ); List.add ( "world" ); for (int i = 0 ; i < list.size (); i++) {String str = (string) list. get (i); System. out . println (str); } }}
What exactly is a generic type? Generics actually allow you to specify a type parameter when defining a class or interface, which is arguments when declaring a variable and creating an object. To put it bluntly, if the collection is like a bottle filled with things, the generic is like a label on a bottle, specifying what kind of things the bottle can hold.
How to define a generic class
What is the specific way to define an interface or class with generics? In the above case, the ArrayList class we are looking at is a generic class, and the list implemented by the ArrayList class is a generic interface.
public Class arraylist<e> {public int Span class= "Hljs-title" >size () {return size; } public boolean add (e e) {Ensurecapacityinte Rnal (size + 1 ); //increments modcount!! elementdata[size++] = e; return true ; } public E get (int index) {rangecheck (index); return elementdata (index); }}
publicinterface List<E> { int size(); boolean add(E e); get(int index);}
What are the rules we should follow if we customize a generic interface or class through the cases provided by the above two Java-based layers?
- Writing "" After the class name means that the class is receiving generics, and T is the generic type. When you create the class object, you specify a specific type. (T does not have the actual meaning, can be arbitrarily specified here.) )
- A method in a generic class can receive a generic parameter or return a generic type.
- In a generic class, generics can only be used in non-static members.
publicclass Demo<T> { private T bean; publicgetBean() { return bean; } publicvoidsetBean(T bean) { this.bean = bean; }}
How to define a generic method
In addition to defining generic interfaces or classes, there are cases where generics are not used when defining interfaces or classes, but you want to customize the type parameters when you define a method. Support for generic methods is also available after the Java 5 release.
The so-called generic method is to define one or more type parameters when declaring the way. The generic method uses the following format:
<T, S> 返回值类型 方法名(形参列表){ 方法体}
According to this format, we are customizing a generic method:
publicclass Demo { publicstaticget(T[] ts) { return ts[0]; } publicstaticvoidmain(String[] args) { new123 }; // 调用方法时,自动识别泛型!因为arr这个参数是Integer[],所以相当于给T赋值为Integer get(arr); System.out.println(i); }}
Type wildcard character
If we are using a generic class, we should pass in a type argument for the generic class, and if the type argument is not passed, it will cause a generic security warning. Let's look at an example:
publicclass Demo { publicvoiddemo(List<String> list) { for (int0; i < list.size(); i++) { System.out.println(list.get(i)); } }}
In this case, we define a method that receives a list collection of type string and iterates through the list collection to print each element's contents. The problem is that the method can only traverse the list collection with the print generic type string, and we need to redefine a method if we want to complete the integer type of the same function.
publicclass Demo { publicvoiddemo(List<Integer> list) { for (int0; i < list.size(); i++) { System.out.println(list.get(i)); } }}
The problem is that when the two methods above appear in the same class, the Error "Method demo (list) has the same Erasure demo (list) as another method in type demo". The reason is that, in addition to the generics, the two methods are actually the same, and not many of the same methods are allowed in the same class.
The solution to this problem is that we can remove the generic content from the parameters, such as the following code:
public Class Demo {public static void print (List list) {for (int i = 0 ; i < list.size (); i++) {System. out . println (List. Get (i)); }} public static void main (string[] args) {list<string> strings = null ; list<integer> integers = null ; Print (strings); print (integers); }}
This allows you to receive either an integer type of list collection or a String type list collection in the Print method. However, the generic security Warning "List is a raw type" will be prompted. References to generic type List should is parameterized ".
To solve this problem completely, we need to use the type wildcard character. The code above through the type wildcard can be rewritten as follows:
public Class Demo6 {public static void print (list<?> List) {f or (int i = 0 ; i < list.size (); i++) { System. out . println (List. Get (i)); }} public static void main (string[] args) {list<string> strings = null ; list<integer> integers = null ; Print (strings); print (integers); }}
In the above case, the "
List<?list ①List<?list ②
Here ① represents the upper boundary of the type wildcard, meaning that the current generic can receive all subtypes of number type; ② represents the bottom boundary of the type wildcard, meaning that the current generic can receive all the parent types of the integer type.
Reprint NOTE: Please indicate the author and the original link, thank you!
[Java5 new feature] Generics