1, Introduction of containers and generics
No matter what language it is, it is necessary to deal with data in the process of developing programs. In order to better accommodate these data, we introduced the concept of array in the previous study, which is indeed a good way to accommodate data, but array alone can not meet our needs, because we have far more requirements for data than just accommodation, more importantly It's about managing data. Admittedly, you can also manage the elements in the array, but you need to type your own code. If the function is limited to this, then it is not Java. As a more powerful language, Java naturally needs to help you write all kinds of code for managing data. You just need to call it foolishly. Java encapsulates these codes for containing, managing and operating data into some classes, which is what we need to learn today - containers, also called collections.
There are several precautions for the container:
- Java containers can only contain one object. However, there are packaging classes, and you don't need to worry about the basic data types that can't fit into the container.
- Container is not only like its literal meaning - to hold things, the strength of container is not only to store data, but also to help you process data and manage data. We can understand the container as a super enhanced data structure.
The following is the main framework of Java container classes:
Now let's talk about how Java people who write source code can store any type of Object in a container? This problem has been considered when wrapping classes. The Object [] array implementation (polymorphism). Well, now there is a new problem: I put all the different types of objects in one container. When I take them, I have to judge one by one whether I want to take the type of data again. Isn't that boring? Indeed, according to our life experience, when we use containers (bottles, pipes, etc.) to load things, we should also separate them according to different types, and then for our own convenience to know what is in the specified containers, we will paste a label on the outside of the containers to remind ourselves. Ha ha, Java is not stupid. It also has common sense. Since the containers are sealed, it is natural to do it perfectly. It also thinks that the Object type of a container can not be too miscellaneous. It also defines a label like thing - generics, to limit it.
In professional terms: generics can help us build a collection of type safety. In a collection that uses generics, there is no need to cast when traversing. JDK provides a compiler that supports generics, which can advance the type checking of runtime to compile time, and improve the readability and security of code. Take a look. Generics began to increase in JDK 1.5.
2, Use of generics in containers
When we open eclipse, let's take a look at some source codes of the Collection interface. These container classes are packaged in the java.util package:
OK, that's the source range we need to see now. Eh, why is there a '< E >' after the interface name? This is generics! The statement and syntax of generic definition are all reflected in the above. The definition of this generic type is like the parameter in this method. The character E in this < > is like the name of the parameter. The character here can be any identifier. But generally, the letters T, e and V are used. Let's not make any special case. So how to pass a certain object type to the past? The specific statement is as follows: Collection < String > object name = new specific implementation class name < String > (); the content in < after JDK 1.7 can be omitted. In this way, the "e" in this interface is equivalent to the "String", that is to say, this container object can only store the objects of the String class. Is this process particularly similar to formal and actual parameters in methods?!
There are several points to note here: first, since the container can only hold objects, the reference data type must be used in < > instead of the basic data type. Second, we just strongly recommend generics. In fact, the use of generics is not mandatory, and no compiler will not report errors! This point does not correspond to a parameter.
package cn.zjb.test; import java.util.ArrayList; import java.util.Collection; /** * Test collection class usage * @author Zhang Jian Bo * */ public class TestCollection { public static void main(String[] args) { Collection c= new ArrayList(); //No generic System.out.println(c.isEmpty()); //As the name implies, this method determines whether the container is empty } }
The operation results are as follows:
This program is just to emphasize that generics are not necessary and have no other significance.
3, Collection interface
Now, with the foreshadowing knowledge, we start to learn from the root node of the encapsulated container "class" inheritance tree system based on the principle of depth first.
First, let's look at the common methods of the Collection interface:
Let's test the last one
package cn.zjb.test; import java.util.ArrayList; import java.util.Collection; /** * Test collection class usage * @author Zhang Jian Bo * */ public class TestCollection { public static void main(String[] args) { Collection<String> c= new ArrayList<>(); c.add("Zhang"); c.add("Firm"); c.add("wave"); System.out.println(c);//[Zhang, Jian, Bo] System.out.println(c.size()); //3 System.out.println(c.isEmpty()); //false System.out.println(c.contains("zhang")); //false System.out.println(c.contains("Zhang")); //true c.remove("Zhang"); Object[] obj=c.toArray(); //Object's toString() method prints the hash address value for(Object temp:obj) System.out.print(temp+" "); //Hard wave System.out.println(""); //Line feed Collection<String> c2= new ArrayList<>(); c2.add("Zhang"); c2.addAll(c); System.out.println(c2); //[Zhang, Jian, Bo] System.out.println(c2.containsAll(c)); //true c2.retainAll(c); System.out.println(c2);// [Jian, Bo] c2.removeAll(c); System.out.println(c2); //[], element is empty } }
4, List interface
The java.util.List interface is an orderly and repeatable container. It inherits from the Collection interface, so it also has methods for the Collection interface. In addition to the methods in the Collection interface, there are more methods related to order (index) in the List, as shown in the figure:
Test it:
package cn.zjb.test; import java.util.List; import java.util.ArrayList; /** * Test List interface * @author Zhang Jian Bo * */ public class TestList { public static void main(String[] args) { List<String> list=new ArrayList<>(); list.add("Zhang"); list.add("Firm"); // list.add(3, "wave"); / / if it is wrong, you must add it to the original array length or add it next to it list.add(2, "wave"); System.out.println(list); //[Zhang, Jian, Bo] list.set(1, "wave"); System.out.println(list); //[Zhang, Bo, Bo] System.out.println(list.get(0)); //Zhang System.out.println(list.indexOf("wave")); //1 System.out.println(list.lastIndexOf("wave")); //2 list.remove(1); System.out.println(list); //[Zhang, Bo] } }
There are three common implementation classes of List interface: ArrayList, LinkedList and Vector. Let's study one by one.
5, ArrayList container
As the name implies, the underlying way to store data in an ArrayList is definitely an array. Characteristics of ArrayList: high query efficiency, low add and delete efficiency, unsafe thread. We usually use it.
We know that the array length is limited, and ArrayList can store any number of objects, and the length is unlimited. So how can it be realized? In essence, it is to realize the expansion by defining a new and larger array, copying the contents of the old array to the new array. The initialization length of ArrayList's Object array is 10. If we store the array full and need to store the 11th Object, we will define a new array with a larger length (capacity is the result of adding the original capacity to move one bit to the right, i.e. half), and add the original array content and new elements to the new array together. The source code is as follows:
In order to better master and use ArrayList, let's write the following code ourselves:
package cn.zjb.practice; import java.util.Arrays; /** * MyArrayList Class is a container class used to store and manage data. The structure of storing data is array. * <p>This class does not implement any interface and is a direct subclass of Object. * @author Zhang Jian Bo * */ public class MyArrayList <E> { /** * MyArrayList The structure used by the container to store data elements. */ private static Object[] container; /** * MyArrayList The default size of the container. */ private static final int DEFAULT_CAPACITY=5; /** * Variables to check whether expansion is needed */ private static int currentLength; /** * Length of the current container array */ private static int length; /** * Used to create an array with the default size as the data storage structure. */ public MyArrayList() { container=new Object[DEFAULT_CAPACITY]; currentLength=DEFAULT_CAPACITY; } /** * Used to create an array of custom size as a data storage structure. * @Parameter initialCapacity is the custom length * (At present, whether or not parameter passing will cause problems is not considered. All methods are like this. Simplify point) */ public MyArrayList(int initialCapacity) { container=new Object[initialCapacity]; currentLength=initialCapacity; } /** * This method is used to add elements * @Parameter E is the concrete object of generic e */ public void add(E e) { if(length==currentLength-1) { expend(); } container[length++]=e; } /** * This method is used to delete the elements of the specified index * @The parameter index indicates the index location */ public void remove(int index) { if(index<=length-1) { System.arraycopy(container, index+1, container, index, length-index+1); length--; }else throw new RuntimeException(); } /** *This method is used to find the index position of the corresponding generic element *@Parameter e indicates the generic object to be found *@The return value corresponds to the index position of the generic, if - 1 is not returned */ public int indexOf(E e) { for(int i=0;i<length;i++) if(container[i].equals(e)) return i; return -1; } /** * This method is used to find the size of the container * @Returns the length of the underlying array of values */ public int size() { return length; } /** * This method is used for automatic capacity expansion */ public void expend() { container=Arrays.copyOf(container, currentLength*2); currentLength=currentLength*2; } /** * * @Parameter obj is a container array * @Return value returns the specific value of generic E in a special format */ public static String toString(Object[] obj) { if(length==0) return "[]"; else { StringBuilder sb=new StringBuilder(); sb.append('['); for(int i=0;i<length;i++) sb.append(container[i]+","); sb.setCharAt(sb.length()-1, ']'); return sb.toString(); } } /** * Override toString() method of Object class to print contents of container * @Return value returns the return value of static String toString(Object[] obj) */ @Override public String toString() { return toString(container); } }
package cn.zjb.practice; /** * practice The class of the main method in the package * @author Zhang Jian Bo * */ public class MainClass { public static void main(String[] args) { MyArrayList<String> a=new MyArrayList<>(); for(int i=0;i<10;i++) //Automatic capacity expansion a.add("zhang"); System.out.println(a); //[zhang,zhang,zhang,zhang,zhang,zhang,zhang,zhang,zhang,zhang] a.remove(2); System.out.println(a); //[zhang,zhang,zhang,zhang,zhang,zhang,zhang,zhang,zhang] System.out.println(a.indexOf("zhang")); //0 System.out.println(a.size()); //9 } }
The simplified version can't be simplified any more. Haha, just to find the feeling.