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 variable
  • ArrayList<Integer>In theInteger is called the actual type parameter
  • The whole is calledArrayList<E>The generic type
  • The wholeArrayList<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

  1. Subclasses specify the type parameter variables of the generic class
  2. 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: in generics is not inherited as before, that is, Listand List

are unrelated !!!!

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