generic paradigm
1. Introduction to generics:
1.1 basic concepts of generics:
1.2 benefits of generics:
Better code readability (no coercion); Program more secure
1.3 erasure type:
Type parameters written in generics during encoding will be removed by the compiler during compilation, which is called "type erasure"
2. Use of generics:
2.1 defining generics:
Generic characters can be any identifier, generally E,T,K,V,N,?
2.2 generic classes:
A generic class defines a generic type on a class. When users use the class, they define the type. The specific use method of generic class is to add one or more type parameter declarations after the class name, such as, < T, K, V >
2.2.1 grammatical structure
public class ***<Generic representation symbol>{ }
2.2.2 example
public class Generic <T>{ private T flag; public void setFlag(T flag) { this.flag = flag; } public T getFlag() { return this.flag; } } public class Test { public static void main(String[] args) { Generic<String> generic = new Generic<>(); generic.setFlag("admin"); String flag = generic.getFlag(); System.out.println(flag); } }
2.3 generic interface:
Generic interfaces and generic classes are declared in the same way. The specific types of generic interfaces need to be declared in the implementation class.
2.3.1 grammatical structure:
public interface ***<Generic representation symbol>{ }
2.3.2 example
//generic interface public interface Igeneric<T> { T getName(T name); } //Interface implementation class public class IgenericImpl implements Igeneric<String>{ @Override public String getName(String name) { // TODO Auto-generated method stub return name; } } //Test class public class Test2 { public static void main(String[] args) { IgenericImpl igeneric = new IgenericImpl(); String name = igeneric.getName("JioH"); System.out.println(name); Igeneric<String> igeneric2 = new IgenericImpl(); String name2 = igeneric2.getName("JioH"); System.out.println(name2); } }
2.4 generic methods:
2.4.1 non static method
2.4.1.1 grammatical structure
public <Generic representation symbol> void getName(Generic representation symbol name){ } public <Generic representation symbol> Generic representation symbol getName(Generic representation symbol name){ }
2.4.1.2 example:
public class MethodGeneric { //No return value public<T> void setName(T name) { System.out.println(name); } //There is a return value public<T> T getName(T name) { return name; } } public class Test3 { public static void main(String[] args) { MethodGeneric mg = new MethodGeneric(); mg.setName("JioH"); mg.setName(951933); MethodGeneric mg1 = new MethodGeneric(); String name = mg1.getName("JioH"); System.out.println(name); Integer name1 = mg1.getName(951933); System.out.println(name1); } }
2.4.2 static method:
Static methods cannot access generics on a class
Generics can only be defined on methods
2.4.2.1 grammatical structure:
public static<Generic representation symbol> void getName(Generic representation symbol name){ } public static<Generic representation symbol> Generic representation symbol getName(Generic representation symbol name){ }
2.4.2.2 example:
public class MethodGeneric { //No return value public static <T> void getFlag(T flag) { System.out.println(flag); } //There is a return value public static <T> T setFlag(T flag) { return flag; } } public class Test4{ public static void main(String[] args) { //Static methods do not need to be instantiated and can be called directly with the class name MethodGeneric.setFlag("JioH"); MethodGeneric.setFlag(123123); String flag = MethodGeneric.getFlag("jioh"); Integer flag1 = MethodGeneric.getFlag(123123); System.out.println(flag); System.out.println(flag1); } }
2.4.3 generic methods and variable parameters
In generic methods, generics can also define variable parameter types
2.4.3.1 grammatical structure
public <Generic representation symbol> void showMsg(Generic representation symbol... args){ }
2.4.3.2 example
public <T> void method(T...args) { //Traversal array for(T t:args) { System.out.println(t); } } public class Test5{ public static void main(String[] args) { //instantiation MethodGeneric mg = new MethodGeneric(); String[] arr = new String[] {"a","b","c"}; mg.method(arr); Integer[] arr2 = new Integer[] {1,2,3}; mg.method(arr2); } }
2.5 wildcards and upper and lower restrictions:
Can only be used in < >
2.5.1 unbounded wildcards
2.5.1.1 grammatical structure:
public void showFlag(Generic<?> generic){ }
2.5.1.2 example:
public class Generic <T>{ private T flag; public void setFlag(T flag) { this.flag = flag; } public T getFlag() { return this.flag; } } public class ShowMsg { public void showFlag(Generic<?> generic){ System.out.println(generic.getFlag()); } } public class Test6 { public static void main(String[] args) { ShowMsg showMsg = new ShowMsg(); Generic<Integer> generic = new Generic<>(); generic.setFlag(20); showMsg.showFlag(generic); Generic<Number> generic1 = new Generic<>(); generic1.setFlag(50); showMsg.showFlag(generic1); Generic<String> generic2 = new Generic<>(); generic2.setFlag("JioH"); showMsg.showFlag(generic2); } }
2.5.2 upper limit of wildcard
The upper limit limit indicates that the type of wildcard is t class and subclass of t class or T interface and sub interface of T interface; This method is also applicable to the upper limit of generics
2.5.2.1 grammatical structure
public void showFlag(Generic<? extends Number> generic){ }
2.5.2.2 example:
public class ShowMsg { public void showFlag(Generic<? extends Number> generic){ System.out.println(generic.getFlag()); } }
2.5.3 lower limit of wildcard
The lower limit limit indicates that the type of wildcard is t class and the parent class of t class or T interface and the parent interface of T interface; This method is not applicable to generic classes
2.5.3.1 grammatical structure
public void showFlag(Generic<? super Number> generic){ }
2.5.3.2 example:
public class ShowMsg { public void showFlag(Generic<? super Integer> generic){ System.out.println(generic.getFlag()); } }
3 generic summary
1. Basic type cannot be used for generic Test t
2. Object T elm = new T() cannot be created through type parameter;
container
1. Structure of container
1.1 structure diagram
1.1.1 single instance set
Store data one by one
1.1.2 double case set
Data storage based on key and value structure
2. Use of singleton set
2.1 introduction to collection interface
Collection is the root interface of singleton collection, and its two sub interfaces are List and Set interfaces
2.2 abstract methods in collection interface
2.3 List interface
2.3.1 List interface features
Orderly and repeatable
2.3.2 common methods of list
2.4 ArrayList container class
ArrayList is the implementation class of the List interface. It is the concrete implementation of List storage feature.
The bottom layer of ArrayList is the storage realized by array. Features: high query efficiency, low addition and deletion efficiency, and unsafe thread
2.4.1 adding elements
public class ArrayListTest { public static void main(String[] args) { //Instantiate the ArrayList container List<String> list = new ArrayList<>(); //Add element boolean flag = list.add("123"); System.out.println(flag); list.add(1, "JioH"); } }
2.4.2 get elements
get
for(int i = 0;i<list.size();i++){ System.out.println(list.get(i)); }
2.4.3 replacement elements
set
String val = list.set(0, "JioH"); System.out.println(val); for(int i=0;i<list.size();i++) { System.out.println(list.get(i)); } //Convert to object [] //Cast cannot be performed on a converted method call Object[] arr = list.toArray(); for(int i=0;i<arr.length;i++){ String str = (String)arr[i]; System.out.println(str); } //Converts a singleton collection to an array of the specified type //The type needs to refer to the type in the generic type String[] arr2 = list.toArray(new String[list.size()]); for(int i=0;i<arr2.length;i++){ System.out.println(arr2[i]); }
2.4.4 merging operation of containers
The collection cannot be empty. If it is empty, FALSE will be returned
List<String> a = new ArrayList<>(); a.add("a"); a.add("b"); a.add("c"); List<String> b = new ArrayList<>(); b.add("d"); b.add("e"); //a and b boolean flag5 = a.addAll(b); System.out.println(flag5); for(String str:a) { System.out.println(str); }
2.4.5 container intersection operation
boolean flag6 = a.retainAll(b);
2.4.6 differential operation of container
//Remove the elements of b in the set of a boolean flag6 = a.removeAll(b);
2.4.7 source code analysis
2.4.7.1 ArrayList underlying storage mode
The bottom layer of ArrayList is the storage realized by array
2.5 Vector container
The bottom layer of Vector is implemented by array, which is thread safe and inefficient
2.5.1 use of vector
The use of Vector is the same as that of ArrayList. Both implement the List interface and implement the abstract methods in the List interface
public class VectorTest { public static void main(String[] args) { //Instantiate Vector List<String> v = new Vector<>(); v.add("a"); v.add("b"); v.add("a"); for(int i=0;i<v.size();i++) { System.out.println(v.get(i)); } //iteration for(String str:v) { System.out.println(str); } } }
2.5.2 Stack container
Stack stack container is a subclass of Vector, which implements a standard last in first out stack.
2.5.2.1 method of operating stack
2.5.2.2 use of stack
public class StackTest { public static void main(String[] args) { //Instantiate stack container Stack<String> s = new Stack<>(); //Add element to stack container s.push("a"); s.push("b"); s.push("c"); System.out.println(s.empty()); //false //View stack top element System.out.println(s.peek()); //Returns the position of the element in the stack container System.out.println(s.search("c")); //Returns 1, counting from the top of the stack //Remove the element from the container String s1 = s.pop(); System.out.println(s1); String s2 = s.pop(); System.out.println(s2); String s3 = s.pop(); System.out.println(s3); System.out.println(s.empty()); //true } }
2.5.2.3 use cases of stack
//Symmetry of matching symbols public class StackTest { public static void main(String[] args) { StackTest stacktest = new StackTest(); stacktest.symmetry(); } public void symmetry() { String str = "...{...[...(...)...]...}..(...)..[..]..."; //instantiation Stack<String> stack = new Stack<>(); boolean flag = true; for(int i = 0;i<str.length();i++) { char c = str.charAt(i); if(c == '{') { stack.push("}"); } if(c == '[') { stack.push("]"); } if(c == '(') { stack.push(")"); } //Judge whether the symbols match if(c == '}' || c == ']' || c == ')') { if(stack.empty()) { flag = false; break; } String x = stack.pop(); //Single string to character if(x.charAt(0) != c) { flag = false; break; } } } if(!stack.empty()) { flag = false; } System.out.println(flag); }
2.6 LinkedList container class
The underlying LinkedList uses bidirectional linked list to store. It is characterized by low query efficiency, high addition and deletion efficiency and unsafe thread.
LinkedList implements the List interface, so LinkedList has the storage characteristics of List (ordered and repeatable elements).
2.6.1 use of LinkedList
public class LinkedListTest { public static void main(String[] args) { //instantiation List<String> list = new LinkedList<>(); //Add element list.add("a"); list.add("b"); list.add("c"); list.add("a"); //Get element for(int i = 0;i<list.size();i++) { System.out.println(list.get(i)); } } }
2.6.2 use of LinkedList (non List standard)
public class LinkedListTest { public static void main(String[] args) { //instantiation LinkedList<String> linkedlist = new LinkedList<>(); //Add an element in the first position linkedlist.addFirst("xixi"); linkedlist.addFirst("haha"); linkedlist.addFirst("xixihaha"); for(String str:linkedlist) { System.out.println(str); } //Add element at last position linkedlist.addLast("No change"); linkedlist.addLast("Gale"); linkedlist.addLast("Hee hee"); //Get the first element System.out.println(linkedlist.getFirst()); //Get the last element System.out.println(linkedlist.getLast()); //Remove first element linkedlist.removeFirst(); //Remove last element linkedlist.removeLast(); //An element pops up from the stack represented by this list, which is equivalent to removeFirst linkedlist.pop(); //Pushing an element into the stack represented by this list is equivalent to addFirst linkedlist.push("Ha ha ha ha"); boolean flag = linkedlist.isEmpty(); System.out.println(flag); } }
LinkedList 3.6 source code analysis
2.6.3.1 node type
private static class Node<E> { E item; Node<E> next; Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } } //Address of the previous node address of the element object address of the next node
2.6.3.2 member variables
transient int size = 0; /** * Pointer to first node. * Invariant: (first == null && last == null) || * (first.prev == null && first.item != null) */ transient Node<E> first; /** * Pointer to last node. * Invariant: (first == null && last == null) || * (last.next == null && last.item != null) */ transient Node<E> last;
2.6.3.3 adding elements
/** * Appends the specified element to the end of this list. * * <p>This method is equivalent to {@link #addLast}. * * @param e element to be appended to this list * @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { linkLast(e); return true; }
/** * Links e as last element. */ void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
2.6.3.4 adding elements at the beginning and end
2.6.3.4.1 addFirst
/** * Inserts the specified element at the beginning of this list. * * @param e the element to add */ public void addFirst(E e) { linkFirst(e); }
/** * Links e as first element. */ private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f); first = newNode; if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; }
2.6.3.4.2 addLast
/** * Appends the specified element to the end of this list. * * <p>This method is equivalent to {@link #add}. * * @param e the element to add */ public void addLast(E e) { linkLast(e); }
/** * Links e as last element. */ void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
2.6.3.5 add elements at specified positions
public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); }
private void checkPositionIndex(int index) { if (!isPositionIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
/** * Returns the (non-null) Node at the specified element index. */ Node<E> node(int index) { // assert isElementIndex(index); if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } }
2.6.3.6 get elements
/** * Returns the element at the specified position in this list. * * @param index index of the element to return * @return the element at the specified position in this list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { checkElementIndex(index); return node(index).item; }
private void checkElementIndex(int index) { if (!isElementIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
/** * Tells if the argument is the index of an existing element. */ private boolean isElementIndex(int index) { return index >= 0 && index < size; }
/** * Returns the (non-null) Node at the specified element index. */ Node<E> node(int index) { // assert isElementIndex(index); if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } }
2.7 Set interface
Set inherits from the Collection, and the method is consistent with the Collection.
2.7.1 features
Disordered and unrepeatable.
Common implementation classes: HashSet, TreeSet, etc; HashSet is generally used
2.7.2 HashSet
HashSet is a collection without duplicate elements, and the order of elements is not guaranteed. Moreover, HashSet allows null elements. HashSet is implemented by hash algorithm, and the bottom layer is actually implemented by HashMap (HashSet is essentially a simplified version of HashMap). Therefore, the query efficiency and addition and deletion efficiency are relatively high.
2.7.2.1 principle of hash algorithm
Hash algorithm is also called hash algorithm.
2.7.3 use of HashSet
public class HashSetTest { public static void main(String[] args) { //Instantiate HashSet Set<String> set = new HashSet<>(); //Add element set.add("a"); set.add("b"); set.add("c"); //Get element. There is no index in the Set container, so there is no get(int index) method for(String str:set) { System.out.println(str); } //Delete element set.remove("a"); //Returns the number of elements int size = set.size(); System.out.println(size); } }
2.7.4 HashSet storage feature analysis
The sequence of elements is not guaranteed, there are no duplicate elements, and the thread is unsafe. null elements are allowed.
Disorder:
In HashSet, the bottom layer uses HashMap to store elements, and the bottom layer of HashMap uses array and linked list to store elements. When the elements are stored in the array, they are not stored in order or at random. Instead, the hash value of the elements (obtained by hash algorithm) is analyzed to determine the position of the elements in the array.
Do not repeat:
When the hash values of the two elements are calculated to obtain the same position in the array, the equals() method of the element will be called to judge whether the two elements are the same. If the elements are the same, the element will not be added. If not, the element will be saved using a one-way linked list.
2.7.5 storing custom objects through HashSet
2.7.5.1 creating Users object
public class Users { private String username; private int userage; public Users(String username,int userage) { this.username = username; this.userage = userage; } public Users() { } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + userage; result = prime * result + ((username == null) ? 0 : username.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Users other = (Users) obj; if (userage != other.userage) return false; if (username == null) { if (other.username != null) return false; } else if (!username.equals(other.username)) return false; return true; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getUserage() { return userage; } public void setUserage(int userage) { this.userage = userage; } @Override public String toString() { return "Users [username=" + username + ", userage=" + userage + "]"; } }
2.7.5.2 storing Users object in HashSet
public class HashSetTest { public static void main(String[] args) { //Instantiate HashSet Set<Users> set = new HashSet<>(); Users u1 = new Users("JioH",18); Users u2 = new Users("JioH",18); set.add(u1); set.add(u2); for(Users users:set) { System.out.println(users); } } }
2.7.6 TreeSet containers
TreeSet is a container that can sort elements. The bottom layer is actually implemented using TreeMap. A simplified version of TreeMap is maintained internally, and the elements of Set are stored through key. TreeSet needs to sort the stored elements internally, so we need to give a sorting rule
Implementation method of sorting rule:
The comparison rule is implemented by the element itself.
Specify the comparison rule through the comparator.
2.7.6.1 use of TreeSet
public class TreeSetTest { public static void main(String[] args) { //instantiation Set<String> set = new TreeSet<>(); //Add element set.add("a"); set.add("d"); set.add("b"); set.add("a"); for(String str:set) { System.out.println(str); } } }
2.7.7 implement comparison rules through elements themselves
2.7.7.1 create Users class
public class Users implements Comparable<Users>{ private String username; private int userage; public Users(String username,int userage) { this.username = username; this.userage = userage; } public Users() { } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + userage; result = prime * result + ((username == null) ? 0 : username.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Users other = (Users) obj; if (userage != other.userage) return false; if (username == null) { if (other.username != null) return false; } else if (!username.equals(other.username)) return false; return true; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getUserage() { return userage; } public void setUserage(int userage) { this.userage = userage; } @Override public String toString() { return "Users [username=" + username + ", userage=" + userage + "]"; } //Define comparison rules @Override public int compareTo(Users o) { if(this.userage < o.getUserage()) { return 1; } if(this.userage == o.getUserage()) { return this.username.compareTo(o.getUsername()); //Compare names } // TODO Auto-generated method stub return -1; } }
2.7.7.2 store Users object in TreeSet
public class TreeSetTest { public static void main(String[] args) { //instantiation Set<Users> set = new TreeSet<>(); Users u = new Users("JioH",18); Users u1 = new Users("xixihaha",20); Users u2 = new Users("axixihaha",20); set.add(u); set.add(u1); set.add(u2); for(Users Users:set) { System.out.println(Users); } } }
2.7.8 comparison rules realized by comparator
When defining comparison rules through a Comparator, we need to create a Comparator separately. The Comparator needs to implement the compare method in the Comparator interface to define comparison rules. When instantiating TreeSet, the Comparator object is handed over to TreeSet to complete the sorting of elements. At this point, the element itself does not need to implement the comparison rules.
2.7.8.1 create comparator
public class StudentComparator implements Comparator<Student>{ //Define comparison rules @Override public int compare(Student o1, Student o2) { // TODO Auto-generated method stub if(o1.getAge() > o2.getAge()) { return 1; } if(o1.getAge() == o2.getAge()) { return o1.getName().compareTo(o2.getName()); } return -1; } }
2.7.8.2 create Student object
public class Student { private String name; private int age; public Student() { super(); // TODO Auto-generated constructor stub } public Student(String name, int age) { super(); this.name = name; this.age = age; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } }
2.7.8.3 storing Users object in TreeSet
public class TreeSetTest { public static void main(String[] args) { //instantiation Set<Student> set = new TreeSet<>(new StudentComparator()); Student s = new Student("JIOH",18); Student s1 = new Student("jioh",16); Student s2 = new Student("JioH",22); set.add(s); set.add(s1); set.add(s2); for(Student str:set) { System.out.println(str); } } }