泛型学习

144 阅读4分钟

一、objectives(学习目标)

1.To describe the benefits of generics.

Generic type enable you to detect errors at complie rather then at runtime.

自动装箱自动拆箱(autoboxing , autounboxing)

自动装箱就是基本类型(primitive type)直接包装为包装类类型。 如:int ——> integer
ArrayList<Integer> list = new ArrayList<>(); list.add(5);//这就是自动装箱 5 是基本类型 而 泛型约束的是Integer

自动拆箱就是包装类类型赋值给基本类型变量时不需要 强制转换。 如:integer——> int Arraylist<Double> list = new ArrayList<>(); list.add(5.5); double element = list.get(0);//这就是自动拆箱。约束类型为Double 不需要强制转换就可以直接赋值给基本类型double 变量

2.To use generic classes and interfaces.

java jdk中ArrayList类就是一个泛型类、Comparable接口 是泛型接口。

3.To define generic classes and interfaces.

//泛型类
class ClassName <T>{//这个T就是一个形式化的反省代表,之后可以被实际类型代替
}
//泛型接口
interface InterfaceName <T>{//这个T就是一个形式化的反省代表,之后可以被实际类型代替
}

define GenericStack class

package javaLanguage;

import java.util.ArrayList;

/**
 * 泛型类
 * @param <T>
 */
public class GenericStack<T> {
 	public GenericStack() {
    }

    public GenericStack(ArrayList<T> list) {
        this.list = list;
    }
    
    //用ArrayList存储数据
    private ArrayList<T> list = new ArrayList<>();
    //栈的当前容量
    public int getSize(){
        return list.size();
    }
    //入栈
    public void push(T o){
        list.add(o);
    }
    //出栈
    public T pop(){
        T o = list.get(getSize() - 1);
        list.remove(getSize() -1);
        return o;
    }
    //查看栈顶元素
    public T peek(){
        return list.get(getSize() - 1);
    }
    //判断栈是否为空
    public boolean isEmpty(){
        if (getSize() == 0){
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * 在main方法中测试GenericStack class
     * @param args
     */
    public static void main(String[] args) {
        GenericStack<String> stack1 = new GenericStack<>();//stack1 can only store strings type.
        GenericStack<Integer> stack2 = new GenericStack<>();//stack2 can only store integer type.

        stack1.push("heihei");
        stack1.push("haha");
        stack1.push("上了生活的贼船,就要做个快乐的海盗!");
        System.out.println(stack1.peek());

        stack2.push(1);//自动装箱
        int pop = stack2.pop();//自动拆箱

        System.out.println(pop);


    }

}


需要注意的地方构造方法以前是怎样写还是怎样写。 下面这样是错的
public GenericStack<E>()
注意: 泛型类当有多个参数时,这样写<T1,T2,T3> 在这里插入图片描述

4.To explain why generic types can improve readability and reliability.

因为泛型能在编译时就检测出错误。 如: 在这里插入图片描述

4.To define and use generic method and bounded generic types.

generic method

package javaLanguage.generic;


import java.util.Arrays;

public class GenericMethodDemo {
    public static void main(String[] args) {
        String[] strings = {"heihei","haha"};
        Integer[] integers = {1,2};

        print(strings);
        print(integers);
    }

    /**
     * 泛型方法 ,静态方法
     * @param list
     * @param <T>
     */
    public static <T> void print(T[] list){
        System.out.println(Arrays.toString(list));
    }
}

bounded generic method //An unbounded generic type <E> is the same as <E extends Object>.
You must invoke equalArea by passing two instances of GeometricObject

package javaLanguage.generic;

public class BoundedTypeDemo {
    public static void main(String[] args) {

    }

    /**
     * 受约束的泛型方法
     * You must invoke equalArea by passing two instances of GeometricObject.
     * @param o1
     * @param o2
     * @param <E>
     * @return
     */
     //An unbounded generic type <E> is the same as <E extends Object>.
    public static <E extends GeometricObject> boolean equalArea(E o1,E o2){
        return o1.getArea() == o2.getArea();
    }

}

//这个类就是个辅助,不用细看
abstract class GeometricObject {
    private String color = "white";
    private boolean filled;
    private java.util.Date dateCreated;

    /**
     * Construct a default geometric object
     */
    protected GeometricObject() {
        dateCreated = new java.util.Date();
    }

    /**
     * Construct a geometric object with color and filled value
     */
    protected GeometricObject(String color, boolean filled) {
        dateCreated = new java.util.Date();
        this.color = color;
        this.filled = filled;
    }

    /**
     * Return color
     */
    public String getColor() {
        return color;
    }

    /**
     * Set a new color
     */
    public void setColor(String color) {
        this.color = color;
    }

    /**
     * Return filled. Since filled is boolean, * the get method is named isFilled
     */
    public boolean isFilled() {
        return filled;
    }

    /**
     * Set a new filled
     */
    public void setFilled(boolean filled) {
        this.filled = filled;
    }

    /**
     * Get dateCreated
     */
    public java.util.Date getDateCreated() {
        return dateCreated;
    }

    @Override
    public String toString() {
        return "created on " + dateCreated + "\ncolor: " + color + " and filled: " + filled;
    }

    /**
     * Abstract method getArea
     */
    public abstract double getArea();

    /**
     * Abstract method getPerimeter
     */
    public abstract double getPerimeter();
}

5.To devolop a generic method for sort an array of Comparable objects.

方法中使用的排序时选择排序

package javaLanguage.generic;

public class GenericSort {

    public static void main(String[] args) {
// Create an Integer array
        Integer[] intArray = {new Integer(2), new Integer(4), new Integer(3)};
// Create a Double array
        Double[] doubleArray = {new Double(3.4), new Double(1.3), new Double(-22.1)};
// Create a Character array
        Character[] charArray = {new Character('a'), new Character('J'), new Character('r')};
// Create a String array
        String[] stringArray = {"Tom", "Susan", "Kim"}; // Sort the arrays
        
        //下面三行不行
//        int[] arr = {new Integer(3)};
//        int[] array = {1,2,3}
//        sort(arr);
        sort(intArray);
        sort(doubleArray);
        sort(charArray);
        sort(stringArray);
// Display the sorted arrays
        System.out.print("Sorted Integer objects: ");
        printList(intArray);
        System.out.print("Sorted Double objects: ");
        printList(doubleArray);
        System.out.print("Sorted Character objects: ");
        printList(charArray);
        System.out.print("Sorted String objects: ");
        printList(stringArray);
    }

    public static <E extends Comparable<E>> void sort(E[] list) {
        E currentMin;
        int currentMinIndex;
        for (int i = 0; i < list.length - 1; i++) {
            currentMin = list[i];
            currentMinIndex = i;
// Find the minimum in the list[i+1..list.length-2] currentMin = list[i];
            for (int j = i + 1; j < list.length; j++) {
                if (currentMin.compareTo(list[j]) > 0) {
                    currentMin = list[j];
                    currentMinIndex = j;
                }
            }
// Swap list[i] with list[currentMinIndex] if necessary;
            if (currentMinIndex != i) {
                list[currentMinIndex] = list[i];
                list[i] = currentMin;
            }
        }
    }

    /**
     * Print an array of objects
     */
    public static void printList(Object[] list) {
        for (int i = 0; i < list.length; i++) System.out.print(list[i] + " ");
        System.out.println();

    }
}

6.To use raw type for backward compatibility.

用原始类型向后兼容,因为早期的java版本(jdk1.5之前)是没有泛型的,新的Java版本出来了要兼容以前的代码,所以有raw type.

何为原始类型: 比如Arraylist类是一个泛型类,然而在创建对象的时候不特别指定类型,像这样Arraylist list = new Arraylist(); 没有用尖括号指出具体的类型,这就是raw type (原始类型)。

原始类型是unsafe,请看下面的图片。 在这里插入图片描述

7.泛型通配符(wildcard)

问题: To explain why wildcard generic type is necessary? 因为它可以给泛型指定一个范围 通配符有三种类型: AND ? extends T AND ? super T
第一种就相当于 ? extends Object
第二种约束是T 或T的子类
第三种约束也是T 或T的子类

例子1: 通配符 ?(不受限通配符)

package javaLanguage.generic;

public class AnyWildcardDemo {

    public static void main(String[] args) {
        GenericStack<Integer> integerGenericStack = new GenericStack<>();//这里Integer是 Object类的子类
        integerGenericStack.push(1);
        integerGenericStack.push(2);
        integerGenericStack.push(3);
        print(integerGenericStack);
    }


    public static void print(GenericStack<?> stack){//这里通配符用的是 ? ,意味着泛型尖括号里只要是Object类的子类或本身都可以使用
        if (!stack.isEmpty()){
            System.out.println(stack.peek());
        }
    }

}

例子2:? extends T (受限通配符) 在这里插入图片描述 例子3:? super T (下限通配符)

这个的关键就是你要确定好 T 必须是父类,要不然就可能出现下面这个错误。 在这里插入图片描述

8.泛型的消除和限制

消除:

泛型只是存在于编译阶段,运行阶段就消失了,这是为了向后兼容,兼容以前的java版本。 在这里插入图片描述 限制:

1.不能创建泛型对象 如: new T(); 2.不能 new T[ ] , 这样不能 E[] elements = new E[capacity]; 但是可以规避可以这样E[] elements = (E[])new Object[capacity]; 不过或许会出现异常,如T是String 而 创建的是Object类的实例,会出现ClassCastException 3.泛型类中不能出现静态字段和静态方法等,因为泛型类可以有不同类型的对象,但是静态数据是被公用的,有多个不同类型的对象时,使用这个静态数据到底是听谁的,对吧,所以不能使用。 想要使用静态方法,就必须把方法写成静态泛型方法。在static关键字后写上 泛型