java tutorial: Java Generic

Java generic, namely “parameterized type”, is to parameterize the type from the original concrete type, similar to the variable parameter in the method, the type is also defined as a parameter form, and then the specific type (type argument) is passed in when using/calling.

Code that uses generics has many benefits over non-generic code:

  • Stronger type checks at compile time.
  • Elimination of casts.
  • Enabling programmers to implement generic algorithms.

Type Parameter Naming Conventions

The most commonly used type parameter names are:

  • E – Element (used extensively by the Java Collections Framework)
  • K – Key
  • N – Number
  • T – Type
  • V – Value
  • S,U,V etc. – 2nd, 3rd, 4th types

Generics make types as parameters when defining classes, interfaces and methods.

Generic class

Syntax

public class ClassName<T> {}

Example

package com.example.generic;

public class GenericClass<T> {

    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    public static void main(String[] args) {
        GenericClass<String> stringGenericClass = new GenericClass<>();
        stringGenericClass.setT("Hello");
        System.out.println(stringGenericClass.getT());
    }
}

Generic interface

Syntax

public interface InterfaceName<T> {}

Example 1

package com.example.generic;

public class GenericInterfaceImpl implements GenericInterface<String> {

    @Override
    public String service(String s) {
        return s.toUpperCase();
    }

    public static void main(String[] args) {
        GenericInterfaceImpl genericInterface = new GenericInterfaceImpl();
        String abc = genericInterface.service("abc");
        System.out.println(abc);
    }
}

Example 2

package com.example.generic;

public class GenericInterfaceImpl2<T> implements GenericInterface<T> {

    @Override
    public T service(T t) {
        return t;
    }

    public static void main(String[] args) {
        GenericInterfaceImpl2<String> stringGenericInterfaceImpl2 = new GenericInterfaceImpl2<>();
        String str = stringGenericInterfaceImpl2.service("Hello");
        System.out.println(str);

        System.out.println("----------------------------");

        GenericInterfaceImpl2<Integer> integerGenericInterfaceImpl2 = new GenericInterfaceImpl2<>();
        Integer integer = integerGenericInterfaceImpl2.service(1000);
        System.out.println(integer);
    }
}

Generic method

Syntax

public <T, R> T methodName(T t, R r) {}

Example

package com.example.generic;

public class GenericMethod {
    public <T> void show(T t) {
        System.out.println(t);
    }

    public <T> T services(T t) {
        return t;
    }

    public static void main(String[] args) {
        GenericMethod genericMethod = new GenericMethod();
        genericMethod.show(1);

        String string = genericMethod.services("Hello");
        Double aDouble = genericMethod.services(122.1);
    }
}

Upper Bounded Wildcards

Generic Wildcards

In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type. 

Generic wildcards including:

  • upper bounded wildcards
    List<? extends Foo> list
  • lower bounded wildcards
    List<? super Foo> list
  • wildcard capture
    List<?> list

Example

package com.example.generic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class testGenericBoundedWildcards {

    public static void main(String[] args) {
        List<GrandeFather> grandeFatherList = new ArrayList<>();
        List<Father> fatherList = new ArrayList<>();
        List<Son> sonList = new ArrayList<>();

        /**
         * Upper bounded wildcard <? Expanded Father>, can only match any subtype of Father and Father.
         * UpperBound(grandeFatherList); // error
         */
        UpperBound(fatherList);
        UpperBound(sonList);

        /**
         * In a similar way, a lower bounded wildcard restricts the unknown type to be a specific type or a super type of that type.
         * LowerBound(sonList); // error
         */
        LowerBound(fatherList);
        LowerBound(grandeFatherList);
        
        /**
         * wildcard capture
         */
        List<String> stringList = Arrays.asList("a", "b", "c");
        List<Integer> integerList = Arrays.asList(1, 2, 3, 4);
        foo(stringList);
        foo(integerList);

    }

    public static void UpperBound(List<? extends Father> list) {
        list.forEach(System.out::println);
    }

    public static void LowerBound(List<? super Father> list) {
        list.forEach(System.out::println);
    }

    public static void foo(List<?> list) {
        System.out.println(list.size());
    }
}

Reference

https://docs.oracle.com/javase/tutorial/java/generics/why.html

Add a Comment

Your email address will not be published.