Promise MongoDB gps wavedorm log4j 海思 json selenium debugging outlook stack Pure CSS formvalidator.js vue异步加载组件 vue router list获取最后一个元素 配置tomcat环境变量 eclipse显示左边目录 wps文件修复工具下载 python多线程编程 python库 python中index的用法 python中的range函数 python正则替换 python建站 java写文件 java的方法 java中instanceof java数组转集合 abaqus最新版本 冬青鼠 kms神龙版 din字体下载 win10画图 惠普战99 瑞兹技能 php正则匹配 ps怎么画漫画 txplatform winsxs可以删除吗
当前位置: 首页 > 学习教程  > 编程语言

第八章泛型程序设计

2020/12/28 19:06:19 文章标签:

泛型程序设计 为什么要使用泛型程序设计: 泛型程序设计(generic programming)意味着编写的代码可以对多种不同类型的对象重用。 例如ArrayList类就可以收集任何类的对象。 定义简单泛型类预定泛型方法 泛型类(generic class&am…

泛型程序设计

为什么要使用泛型程序设计:
泛型程序设计(generic programming)意味着编写的代码可以对多种不同类型的对象重用。
例如ArrayList类就可以收集任何类的对象。

定义简单泛型类预定泛型方法

泛型类(generic class)就是有一个或多个类型变量的类。

public class Pair<T>
{
	private T first;
	private T second;
	
	public Pair() { first = null; sencond = null; }
	public Pair(T first, T second) {this.first = first; this.second = second; }
	
	public T getFirst() { return first; }
	....
	public void setSecond(T newValue ) { second = newValue; }
}

泛型方法可以在普通类中定义,也可以在泛型类中定义

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

类型变量的限定

java的继承中,可以根据需要拥有多个接口超类型,但最多有一个限定可以是类。如果有一个类作为限定,它必须是限定列表中的第一个限定。限定类型用“&”隔开,逗号分割类型变量

下面把minmax重写为一个泛型方法。这个方法可以计算泛型数组的最大值和最小值,并返回一个Pair。

package com.day04.pair2;

import com.day04.Pair;

import java.time.*;

/**
 * @Author xcf
 * @date 2020-12-28
 */
public class PairTest2 {
    public static void main(String[] args) {
        LocalDate[] birthdays = {
                LocalDate.of(1906,12,9), // G. Hopper
                LocalDate.of(1815,12,10), // A. Lovelace
                LocalDate.of(1903,12,3), // J.von Neumann
                LocalDate.of(1910,6,22) // K. Zuse
        };
        Pair<LocalDate> mm = ArrayAlg.minmax(birthdays);
        System.out.println("min = " + mm.getFirst());
        System.out.println("max = " + mm.getSecond());
    }
}

class ArrayAlg{
    /**
     * 求T型对象数组的最小值和最大值
     * @param a T型对象的数组
     * @return 具有最小值和最大值的对,如果a为空,则为null
     */
    public static <T extends Comparable> Pair<T> minmax(T[] a){
        if (a == null || a.length == 0) return null;
        T min = a[0];
        T max = a[0];
        for (int i = 0; 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);
    }
}

泛型代码与虚拟机

虚拟机没有泛型类对象——所有对象都属于普通类。

类型擦除

无论何时定义一个泛型类型,都会自动提供一个相应的原始类型(raw type)。这个原始类型的名字就是去掉类型参数或的泛型类型名。类型变量会被擦除(erased),并替换为其限定类型(或者,对于无限定的变量则替换为Object)

转换泛型方法

类型擦除也会出现类型方法中。
对于泛型的转换,需要记住以下几个事实:

  • 虚拟机中没有泛型,只有普通的类和方法。
  • 所有的类型参数都会替换为它们的限定类型。
  • 会合成桥方法来保持多态。
  • 为保持类型安全性,必要时会插入强制类型转换。

限定与局限性

  1. 不能用基本类型实例化类型参数
  2. 运行时类型查询只适用于原始类型
  3. 不能创建参数化类型的数组
  4. Varargs警告( @SuperssWarinings(“unchecked”) )
  5. 不能实例化类型变量
  6. 不能构造泛型数组
  7. 泛型类的静态上下文中类型变量无效
  8. 不能抛出或铺货泛型类的实例
  9. 可以取消对检查型异常的检查
  10. 注意擦除后的冲突

泛型类型的继承规则

首先思考一个问题,现在有一个 Employee 类和一个继承了 Employee 类的 Manager 类,如下所示:

public class Employee { ... }
public class Manager extends Employee { ... }

那么对于一个普通的泛型类 Practical:

public class Practical<T> { ... }

类型 Practical< Manager > 是 Practical< Employee > 的子类吗?答案是否定的,通过下面这段代码可以对此进行验证:

	Practical<Manager> manager = new Practical<>();
	Practical<Employee> employee = manager; // error

上述代码的第二行,用一个 Practical< Employee > 类型的变量引用了一个 Practical< Manager > 类型的对象,然而编译器显示这样是不合法的。我们知道,如果 B 是 A 的子类的话,是可以用 A 类型的变量引用 B 类型的对象(向上造型)的。显然,这个例子证明了 Practical< Manager > 并不是 Practical< Employee > 的子类。

也许这看起来会很奇怪,但这样设定是出于安全性的考虑,可以避免一些风险的出现。

public class Practical<T> {
	ArrayList<T> list;
	
	public Practical() {
		list = new ArrayList<>();
	}
	
	public void add(T t) {
		list.add(t);
	}
	
	public T getFirst() {
		// return the top ranked;
	}

现在我们补全了一部分 Practical 类的内容,然后执行以下操作:

	Practical<Manager> manager = new Practical<>();
	Practical<Employee> employee = manager; // 假设可以
	manager.add(new Manager());
	employee.add(new Employee());
	Employee firstEmployee = getFirst();

观察上面的代码,就会发现很多不合理之处,首先第一行实例化了一个新的对象之后,此对象中的 list 列表的成员按道理应该是 Manager 类型的,在第三行向 list 中加入了一个 Manager 类型的对象之后,第四行又加入了一个 Employee 类型的对象(???此处 Employee 可是 Manager 的父类)。在此之后还选出了 list 中的第一名(暂且理解为绩效最好的吧),将“经理”和“普通员工”放一起比较显然是不合理的。

当然,Java泛型类型的继承规则保证了这种“离谱”的情况将不会发生!

泛型及通配符方法综合

package com.day04.pair3;

import com.day02.equals.*;
import com.day04.Pair;

/**
 * @Author xcf
 * @date 2020-12-28
 */
public class PairTest3 {

    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,15);
        Pair buddies = new Pair<Manager>(ceo, cfo);
        printBuddies(buddies);

        ceo.setBonus(1000000);
        cfo.setBonus(500000);
        Manager[] managers = { ceo, cfo};

        Pair result = new Pair<Employee>();
        minmaxBonus(managers,result);

        System.out.println("first:" + result.getFirst().getClass().getName()
                        + ", second:" + result.getSecond().getClass().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.length == 0) return;
        Manager min = a[0];
        Manager max = a[0];
        for (int i = 0; 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);// swapHelper捕获通配符类型
    }
    //不能写 public static <T super manager>. . .
}

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);
    }
}

本文链接: http://www.dtmao.cc/news_show_550154.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?