preface

In the days of learning Java u-turn, many young people are out of the pit, and there are also many young people into the pit, but there may be no good guidance or learning methods when entering the pit may lose their hair out of control…

One of my younger students was in the same situation. He was so confused by generics that he couldn’t figure out what generics were. She probably doesn’t even know she uses generics. Map card! Of course, the author depth is also lack, if the error also please correct!

This article is based on the author’s understanding of a simple introduction to generics (in-depth also need their own), if the depth is not enough or there are mistakes, please forgive me.

What generics are:

Generics are a feature of programming languages. Allows programmers writing code in strongly typed programming languages to define variable parts that must be specified before use. Support for generics varies from programming language to programming language and from compiler to runtime environment. A data type parameterized for code reuse to improve software development efficiency. Generic classes are reference types and heap objects, mainly introducing the concept of type parameters.

When there are no generics

Generics, in the literal sense, are broad in meaning, types that represent or handle a broad class of transactions (Java collection classes). What do you do when there are no generics? Like when you write a linked list. It might go something like this:

public class node { public int value; // Node next; Public node(){} public node(int value) {this.value=value; }}Copy the code

The node holds an int. What about a string or a double? Do I have to repeat:

public class node { public String value; // Node next; Public node(){} public node(String value) {this.value=value; }}Copy the code

Rewrite? You can rewrite it.

Use the Object class to represent generics

After discovering this big problem in design, many people have taken into account the seriousness and complexity of this problem. With the popularity of object oriented development, we know that there is an upward transition and a downward transition in Java.

Upcast: Assigning a subclass object to a variable of the parent type is a technique called upcast. You can define a method in a parent class and then implement it in a child class, which is the basic idea behind polymorphism.

For example, dogs have a lot in common. For a group of dogs, we may use dog to denote operation of them, but specific instantiation may be based on different types such as husky, Tibetan mastiff and golden retriever. Rewrite some of the special functions to use the DOG API directly.

There are also many such polymorphic ideas in Java, such as the following:

List<Integer>list1=new ArrayList<Integer>();
List<Integer>list2=new LinkedList<Integer>();
Copy the code

The previous upward transition was from a more concrete class to a more abstract class. After the upward transformation, there is also the downward transformation, which is the transformation of a more abstract class into a more concrete class. Of course, casting down requires a cast (showing the cast tells the compiler)

If you use the code:

Public class test {public static void main(String[] args) {//animal Animal =new dog("doudou",17); // Dog =(dog)animal; // Dog =(dog)animal; animal.sayhello(); dog.sayhello(); } } class animal { public String name; public int age; public animal(String name,int age){ this.name=name; this.age=age; } public void sayHello () {system.out.println ("hello, I am aninal"+this.name+" this "+this.age+" age "); } } class dog extends animal { public dog(String name, int age) { super(name, age); } @override public void sayHello () {system.out.println ("hello "+this.name+" this "+age+" age "); }}Copy the code

We know that in Java the Object class is the parent (superclass) of all classes. It’s the type at the top, all its classes are its children, and it writes its own toString(),equalls(), and so on.

Similarly, we can take a class and turn it up into an Object class, and then turn it down into the number we need. But primitive types don’t do the trick, so there’s a wrapper class. To a certain extent, objects can be stored to meet the requirements of use.

public class test { public static void main(String[] args) { Integer a=10; node node1=new node(a); Integer va1=(Integer) node1.getValue(); System.out.println(va1); node node2=new node("hello"); String va2=(String) node2.getValue(); System.out.println(va2); } } class node { private Object value; public node(Object value) { this.value=value; } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; }}Copy the code

The results are as follows:

10
hello
12
Copy the code

This can be generic to some extent, but there is a bigger problem besides being limited and cumbersome to use. The mechanism that makes Java code less secure is that on the second downward turn shown, the compiler cannot recognize a human conversion error and must wait until the code executes to report an error.

Java generics

In the case of unsafe behavior of Object conversion, Java in JDK1.5 after the proposed generics mechanism, through generics can effectively avoid the problem of transformation, the simple understanding of generics is to define unknown type variables in classes, interfaces, methods, only when the initialization of the real type. You can operate directly with this unknown type in a defined class or interface function.

A generic class

The syntax for generic classes is as follows:

Class name <T> where T stands for a type name Class names <T1,T2> may have multiple typesCopy the code

Where T, T1, and T2 are called wildcards. Common wildcards are T,E,K, and V for type, element, key, and value, respectively.

When creating a Node class, you can write it like this:

public class node <T>{ private T value; public node(T value) { this.value = value; } public T getValue() { return value; } public void setValue(T value) { this.value = value; }}Copy the code

T is free to use in a class that we don’t know yet, but the compiler knows when we initialize it:

A generic interface

If a class can use generics, so can interfaces, but interfaces use generics in a slightly different way. If a subclass inherits a generic interface, it needs to declare the generic type on its interface, otherwise the compiler will report an error. For example, the pig class below.

If you still want to use generics in a subclass, you need to declare a generic in the subclass, and generics in the interface use the subclass’s generic type. For example, the dog class below.

interface aninal <T> { T getValue(T t); } class cat implements aninal {Override public Object getValue(Object o) {return o; }} class pig implements aninal<String>{ @override public String getValue(String s) {return s+" hum "; }} class dog <T>implements aninal<T> {// @Override public T getValue(T t) { return t; }}Copy the code

That is to say, if you want to use a generic interface if you want to inherit it, you need to define the generic class of the interface part in the inherited class for the interface to use.

Class class < A, B, C > implements aninal < C >Copy the code

Generic method

The basic use of generic functions is also easy, much like the use of generic classes and generic interfaces, except that the diamond must precede the function type:

public   <T1,T2> void fuc(T1 t1,T2 t2)
{
     System.out.println(t1);
     System.out.println(t2);
 }
Copy the code

Boundary limit

Generics are so good that we can pass in a specific type when we use them, but many times in development there are limits to how much a class or method can pass in. So in Java there are upper bounds and lower bounds that limit the types available for generics.

There are two types of qualified wildcards:

  • The upper bound of the
    , that is, the type must be of type T or a T subclass

  • The lower bound of the type in the format
    , that is, the type must be type T or a superclass of T

Here’s an example of writing these classes and methods in Java:

class animal { //dosomething } class dog extends animal { //dosomething } class pig extends animal { //dosomething } public class test { static void printlist1(List<? Extends animal>list) {for(animal :list) {system.out.println (animal); } } static void dolist2(List<? super pig>list) { //dosomething } }Copy the code

So printList1 uses the upper bound. The Dolist2 function uses a generic lower bound, so the compiler can tell you when you’re making a mistake.

The end of the

Of course, this article is not a complete solution and summary of generics, there are a lot of detailed need to compare the differences of generics will not be introduced here.

On the whole, the main function of generics is to solve the security problem of type conversion, avoid the problem of Object conversion back and forth, so that the compiler can identify the error of type conversion, at the same time, by defining the type makes the use of functions and methods more flexible and convenient. However, generics are more commonly used in framework writing, and are actually ubiquitous in Java. In particular, collection classes:

The next time you’re designing a linked list binary tree, don’t use an int to represent the value of a node. I think you know the correct way to write it!