Detailed explanation of Java generics

introduction

Java's generics (generics) is a new feature introduced in JDK5, which provides a compile-time type safety detection mechanism, which allows illegal types to be detected at compile time. The essence of generics is that they are parameterized types, that is, the data type being manipulated is specified as a parameter. Below we divide it into four parts to explain

Rules for generic methods:
1): When a generic method is declared, there will be a type parameter declaration part, which is separated by angle brackets <>, before the return value type of the method.
2): Each type parameter declaration part contains one or more type parameters, which are separated by commas. A generic parameter is also called a type variable, which is an identifier used to specify a generic type name.
3): Type parameters can be used to declare the return value type and can be used as placeholders for the actual parameter types obtained by the generic method.
4): The declaration of the generic method body is the same as that of other methods. Note that the type parameter can only represent a reference type, not a primitive type.

  • generic method
public class PrintArray {
    public static void main(String[] args) {
        Integer[] integers = {1, 2, 3};
        String[] strings = {"Hello", "World"};
        printArray(integers);
        printArray(strings);
    }

    /**
     * 泛型打印数组
     *
     * @param array
     * @param <T>
     */
    public static <T> void printArray(T[] array) {
        for (T t : array) {
            System.out.print(" "+t);
        }
        System.out.println();
    }
}

write picture description here

  • Bounded type parameters
    Sometimes when we pass parameters, we limit the parameter range. For example, I only want to pass a certain class or its subclasses. Not all classes can be passed in as generic parameters. This Sometimes bounded type parameters will be used; for example, here is an adapter class I customized, in which E can only pass TemplateViewHolder or its subclasses, otherwise an error will be reported.

public abstract class TemplateListAdapter<T, E extends TemplateViewHolder> extends BaseAdapter {

    public Context mContext;
    public List<T> mData;
    public LayoutInflater mInflater;

    public TemplateListAdapter(Context context, List<T> data) {
        mInflater = LayoutInflater.from(context);
        mContext = context;
        mData = data;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Object getItem(int position) {
        return mData.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        E holder;
        if (convertView == null) {
            convertView = mInflater.inflate(getLayoutID(), null);
            holder = getViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            holder = (E) convertView.getTag();
        }
        bindData(position, holder);
        return convertView;
    }

    protected abstract void bindData(int position, E holder);

    protected abstract E getViewHolder(View convertView);

    protected abstract int getLayoutID();

}
  • Generic classes
    In actual development, generic classes are very useful. For example, if we fix the template of the data returned through the interface, then we only need to use generics to pass the real data. Examples are as follows:
class Result<T> {
    private T data;
    private int code;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public static void main(String[] args) {
        Result<String> stringResult = new Result<>();
        stringResult.setData("Hello World");
        System.out.println("String:"+stringResult.getData());

        Result<Integer> intResult = new Result<>();
        intResult.setData(123456789);
        System.out.println("Integer:"+intResult.getData());
    }
}

turn out:
write picture description here

  • Type wildcard
    1 Type wildcard is generally replaced by ?, you can pass in any type of parameter, the difference from generic E is that you do not need to add angle brackets <> before the return value type
    2 Type wildcard can also be used
public class PrintArray {
    public static void main(String[] args) {
        Integer[] integers = {1, 2, 3};
        String[] strings = {"Hello", "World"};
        printArray(integers);
        printArray(strings);

        List<String> list = new ArrayList<>();
        list.add("hello");
        printArray(list);

        List<Integer> list1 = new ArrayList<>();
        list1.add(23);
        printArray2(list1);

        List<Number> list2 = new ArrayList<>();
        list2.add(2.5);
        printArray3(list2);
    }

    /**
     * 泛型打印数组
     *
     * @param array
     * @param <T>
     */
    public static <T> void printArray(T[] array) {
        for (T t : array) {
            System.out.print(" " + t);
        }
        System.out.println();
    }

    /**
     * 泛型打印集合
     *
     * @param data
     * @param <E>
     */
    public static <E> void printArray(List<E> data) {
        System.out.println("泛型:"+data.get(0));
    }

    /**
     * 类型通配符打印数据
     * @param data
     */
    public static void printArray2(List<?> data) {
        System.out.println("类型通配符?:"+data.get(0));
    }

    public static void printArray3(List<? extends Number> data) {
        System.out.println("类型通配符extends:"+data.get(0));
    }
}

write picture description here

Alright, that's it for generics

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325641774&siteId=291194637