【笔记】Java核心技术卷1-第八章_泛型程序设计

8.1.1 类型参数的好处

ArrayList 类有一个类型参数用来指示元素的类型:ArrayList<String> files = new ArrayList<String>();
这使得代码具有更好的可读性。人们一看就知道这个数组列表中包含的是 String 对象。
在不用类型参数时,在调用get时不需要进行强制转换。在add时,编译器进行检查是否为String(原来Object可添加任意对象)。

8.2 定义简单泛型类

public class PairTest1 {
    
    
    public static void main(String[] args) {
    
    
        String[] words = {
    
    "Mary", "had", "a", "little", "lamb"};
        Pair<String> mn = ArrayAlg.minmax(words);
        System.out.println("min = " + mn.getFirst());
        System.out.println("max = " + mn.getSecond());
    }
}
class ArrayAlg
{
    
    
    public static Pair<String> minmax(String[] a)
    {
    
    
        if (a == null || a.length == 0) return null;
        String min = a[0];
        String max = a[0];
        for (int i =1 ;i < a.length;i++)
        {
    
    
            if (min.compareTo(a[i]) >0) min = a[i];
            if (max.compareTo(a[i]) < 0) max = a[i];
        }
        return new Pair<>(min, max);
    }
}
class Pair<T> {
    
    

    private String min;
    private String max;

    Pair(String a, String b) {
    
    
        min = a;
        max = b;
    }

    public String getFirst() {
    
    
        return min;
    }

    public String getSecond() {
    
    
        return max;
    }
}

8.3 泛型方法

class ArrayAlg 
{
    
     
	public static <T> T getMiddle(T... a) 
	{
    
     
		return a[a.length / 2]; 
	} 
} 

可以定义在普通类中,也可以定义在泛型类中。
调用泛型方法时,
String middle = ArrayAlg.<String>getMiddle("John", "Q.", "Public");
也可以省略<>中的类型参数
String middle = ArrayAlg.getHiddle("John", "Q.", "Public");

8.4 类型变量的限定

可以对类型变量设置限定,使得实现某个接口。

public static <T extends Comparable> T min(T[] a) . . . 

可以有多个限定,例如T extends Comparable & Serializable
限定类型用“ &” 分隔,而逗号用来分隔类型变量。

8.6 约束与局限性

8.6.1 不能用基本类型实例化类型参数

只有Pair<Double>,没有Pair<double>。因为类型擦除。Object和double不能互相转换。

8.6.2 运行时类型查询只适用于原始类型

由于编译的时候就把类型擦除了,所以在运行时并不存在泛型一说,只有相应的原始类型,如Pair在编译后就变成了Pair,所以在查询类型的时候只有原始类型。
Pair<String>Pair<Employee>getClass返回相同原始类型。

8.6.3 不能创建参数化类型的数组

不能实例化参数化类型的数组, 例如:
Pair<String>[] table = new Pair<String>[10]; // Error

这有什么问题呢? 擦除之后, table 的类型是 Pair[]。可以把它转换为 Object[]:
Object[] objarray = table;
数组在创建的时候就必须知道其内部元素的类型,并且会记住这个元素的类型,每次添加新的元素的时候都会检查一下,如果试图往里面添加其它类型的元素就会抛出一个ArrayStoreException异常,而类型擦除会使这种机制无效。

8.6.4 可变参数的警告

8.6.5 不能实例化类型变量

8.6.6 不能构造泛型数组

8.6.7 泛型类的静态上下文中类型变量无效

8.6.8 不能抛出或捕获泛型类的实例

8.6.9 可以消除对受查异常的检查

8.6.10 注意擦除后的冲突

8.8.1 通配符概念

通配符类型中, 允许类型参数变化。 例如, 通配符类型
Pair<? extends Employee>
表示任何泛型 Pair 类型, 它的类型参数是 Employee 的子类, 如 Pair< Manager>, 但不是 Pair< String>。

8.8.2 通配符的超类型限定

8.8.3 无限定通配符

Pair<?> 和 Pair 本质的不同在于: 可以用任意 Object 对象调用原始 Pair 类的 setObject
方法。

总结例子

import java.time.LocalDate;

public class PairTest
{
    
    
    public static void main(String[] args)
    {
    
    
        Manager ceo = new Manager("Gus Greedy", 80000, 2003, 12, 15);
        Manager cfo = new Manager("Sid Sneaky", 60000, 2003, 12, 11);
        Pair<Manager> buddies = new Pair<>(ceo, cfo);
        printBuddies(buddies);

        ceo.setBonus(100000);
        cfo.setBonus(500000);
        Manager[] managers = {
    
    ceo, cfo};
        Pair<Employee> result = new Pair<>();
        minmaxBonus(managers, result);
        System.out.println("first: " + result.getFirst().getName() + ", second: " + result.getSecond().getName());
        maxminBonus(managers, result);
        System.out.println("first: " + result.getFirst().getName() + ", second: " + result.getSecond().getName());

    }

    public static void printBuddies(Pair<? extends Employee> p)
    {
    
    
        Employee first = p.getFirst();
        Employee second = p.getSecond();
        System.out.println(first.getName() + " and " + second.getName() + " are buddies.");
    }

    public static void minmaxBonus(Manager[] a, Pair<? super Manager> result)
    {
    
    
        if (a == null || a.length == 0)
            return ;
        Manager min = a[0];
        Manager max = a[0];
        for (int i = 1; i < a.length; i++)
        {
    
    
            if (min.getBonus() > a[i].getBonus())
                min = a[i];
            if (max.getBonus() < a[i].getBonus())
                max = a[i];
        }
        result.setFirst(min);
        result.setSecond(max);
    }

    public static void maxminBonus(Manager[] a, Pair<? super Manager> result)
    {
    
    
        minmaxBonus(a, result);
        PairAlg.swapHelper(result);
    }
}

class PairAlg
{
    
    
    public static boolean hasNulls(Pair<?> p)
    {
    
    
        return p.getFirst() == null || p.getSecond() == null;
    }
    public static void swap(Pair<?> p) {
    
     swapHelper(p); }
    public static <T> void swapHelper(Pair<T> p)
    {
    
    
        T t = p.getFirst();
        p.setFirst(p.getSecond());
        p.setSecond(t);
    }
}

class Pair<T> //定义了一个泛型类,该类引入了一个类型变量T
{
    
    
    private T first;
    private T second;
    //使用类型变量,类型变量指定方法的返回类型
    public Pair() {
    
     first = null; second = null; }
    public Pair(T first, T second) {
    
     this.first = first;  this.second = second; }

    public T getFirst() {
    
     return first; }
    public T getSecond() {
    
     return second; }

    public void setFirst(T newValue) {
    
     first = newValue; }
    public void setSecond(T newValue) {
    
     second = newValue; }
}

class Employee
{
    
    
    private String name;
    private double salary;
    private LocalDate hireDay;

    public Employee(String name, double salary, int year, int month, int day)
    {
    
    
        this.name = name;
        this.salary = salary;
        hireDay = LocalDate.of(year, month, day);
    }

    public String getName()
    {
    
    
        return name;
    }

    public double getSalary()
    {
    
    
        return salary;
    }

    public LocalDate getHireDay()
    {
    
    
        return hireDay;
    }

    public void raiseSalary(double byPercent)
    {
    
    
        double raise = salary * byPercent / 100;
        salary += raise;
    }
}

class Manager extends Employee
{
    
    
    private double bonus;
    
    public Manager(String name, double salary, int year, int month, int day)
    {
    
    
        super(name, salary, year, month, day);
        bonus = 0;
    }

    public double getSalary()
    {
    
    
        double baseSalary = super.getSalary();
        return baseSalary + bonus;
    }

    public void setBonus(double b)
    {
    
    
        bonus = b;
    }

    public double getBonus()
    {
    
    
        return bonus;
    }
}

猜你喜欢

转载自blog.csdn.net/Ethan_997/article/details/108515049