Java 核心技术卷1 您所在的位置:网站首页 java第八章知识点 Java 核心技术卷1

Java 核心技术卷1

2024-03-22 21:39| 来源: 网络整理| 查看: 265

Github代码链接: https://github.com/deyou123/corejava.git

第八章 泛型程序设计 8.1 为什么要使用泛型程序设计

泛型程序设计: 意味着编写的代码可以被很多不同类型的对象所重用。

8.1.1 类型参数的好处

类型参数

Java SE7 及以后,构造函数中可以省略泛型类型: ArrayList< String > array = new ArrayLIst(); 省略的累心更可以从变量的类型中推断得出。类型参数的魅力在于: 使得程序具有更好的可读性和安全性。 8.1.2 谁想成为反省程序员 8.2 定义简单泛型类

在这里插入图片描述

在这里插入图片描述 在这里插入图片描述

8.3 泛型方法 class ArrayAlg { public static T getMiddle(T...a) { return a[a.length / 2]; } }

注意,类型变量放在修饰符(这里public static) 的后面,返回类型的前面。

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

当调用一个泛型方法时,在方法名前的尖括号中放人具体的类型: String middle =ArrayAlg.< String > getMiddle("]ohnM,“Q. n,” Public");

在这种情况(实际也是大多数情况)下,方法调用中可以省略< String > 类型参数。编译器有足够的信息能够推断出所调用的方法。可以调用: String middle =ArrayAlg.getHiddle("]ohn", “Q.”, “Public”);

8.4 类型变量的限定

可以通过对类型变量T 设置限定(bound) 实现这一点: public static Tmin(T[] a) . . .

下面的记法: < T extends BoundingType > 表示T 应该是绑定类型的子类型(subtype)

T 和绑定类型可以是类,也可以是接口。

一个类型变量或通配符可以有多个限定,例如: T extends Comparable & Serializable

8.5 泛型代码和虚拟机 8.5.1 类型擦除 无论何时定义一个泛型类型,都自动提供了一个相应的原始类型(raw type) 。原始类型的名字就是删去类型参数后的泛型类型名。擦除(erased ) 类型变量, 并替换为限定类型(无限定的变量用Object) 。例如,Pair 的原始类型如下所示: public class Pair { private Object first; private Object second; public Pair(Object first, Object second) { this,first = first; this.second = second; public Object getFirstO { return first; } public Object getSecondO { return second;} public void setFirst(Object newValue) { first = newValue; } public void setSecond(Object newValue) { second = newValue; } } 因为T 是一个无限定的变量,所以直接用Object 替换。 8.5.2 翻译泛型表达式 当程序调用泛型方法时,如果擦除返回类型,编译器插入强制类型转换。 例子。。。 8.5.3 翻译泛型方法

总之,需要记住有关Java 泛型转换的事实:

虚拟机中没有泛型,只有普通的类和方法。所有的类型参数都用它们的限定类型替换。桥方法被合成来保持多态。为保持类型安全性,必要时插人强制类型转换。 8.5.4 调用遗留代码 8.6 约束与局限性 8.6.1 不能用基本类型实例化类型参数 没有Pair< double>, 只有Pair< Double>。擦除之后,Pair 类含有Object 类型的域,而Object 不能存储double值。 8.6.2 运行时类型查询只适用于原始类型 试图查询一个对象是否属于某个泛型类型时,倘若使用instanceof 会得到一个编译器错误,如果使用强制类型转换会得到一个警告。同样的道理,getClass 方法总是返回原始类型。例如: Pair< String> stringPair = . . Pair< Employee>employeePair = . . if (stringPair.getClassO ==employeePair.getClassO) // they are equal 其比较的结果是true, 这是因为两次调用getClass 都将返回Pair.class。 8.6.3 不能创建参数化类型的数组

只是不允许创建这些数组,而声明类型为Pair< String>[] 的变量仍是合法的。不过不能用new Pair[10] 初始化这个变量。

8.6.4 Varargs警告 8.6.5 不能实例化类型变置 不能使用像new T(…) ,newT[…] 或T.class 这样的表达式中的类型变量。public Pair() { first = new T(); second= new T(); }// Error最好的解决办法是让调用者提供一个构造器表达式。 Pair < String > p = Pair.makePair(String::new);

makePair 方法接收一个Supplier ,这是一个函数式接口,表示一个无参数而且返回类型为T 的函数:

public static Pair makePair(Supplier constr) { return new Pair(constr.get(),constr.get()) ; } 比较传统的解决方法是通过反射调用Clasmewlnstance 方法来构造泛型对象。 first =T.dass.newInstanceO; // Error 它会擦除为Object.class。 public static Pair makePair(Class cl) { try { return new Pairo(d.newInstanceO. cl.newInstanceO) ;} catch (Exception ex) { return null; } } Pair p=Pair.makePair(String.class); 8.6.6 不能构造泛型数组 就像不能实例化一个泛型实例一样,也不能实例化数组。如果数组仅仅作为一个类的私有实例域,就可以将这个数组声明为Object[],并且在获取元素时进行类型转换。 public class ArrayList { private Object口elements; @SuppressWarnings("unchecked") public E get(int n) { return (E) elements[n]; } public void set (int n , E e) { elements[n]= e; } // no cast needed } public class ArrayList { private E[] elements; public ArrayList() { elements = (ED) new Object[10]; } } 8.6.7 泛型类的静态上下文中类型变量无效 不能在静态域或方法中引用类型变量。 public class Singleton { private static T singlelnstance; // Error public static T getSinglelnstance()// Error { if (singleinstance == null) construct new instance of T return singlelnstance; } } 8.6.8 不能抛出或捕获泛型类的实例 甚至泛型类扩展Throwable 都是不合法的。 8 . 6.9 可以消除对受查异常的检查 必须为所有受查异常提供一个处理器。不过可以利用泛型消除这个限制。 8.6.10 注意擦除后的冲突 8.7 泛型类型和继承规则 8.8 通配符类型 8.9 反射和泛型 8.9.2使用Class 参数进行类型匹配 public static Pai r makePair(Class c) throws InstantiationException, IllegalAccessException { return new Pairofc.newInstanceO» c.newInstanceO); } makePiar(Employee.class);


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有