java编程思想读书笔记 第十五章 泛型 (泛型方法)
来源:互联网 发布:prim算法描述 编辑:程序博客网 时间:2024/05/18 00:47
泛型方法
首先需要知道的是,可以在类中包含参数化方法,而这个方法所在的类可以是泛型类,也可以不是泛型类。也就是说,是否拥有泛型方法,与其所在的类是否是泛型没有关系。泛型方法使得该方法能够独立于类而产生变化。一个基本原则是:无论何时,只要你能做到,你就应该尽量使用泛型方法。也就是说,如果使用泛型方法可以取代将整个类泛型化,那么就应该只使用泛型方法,因为它可以使事情更清楚明白。另外,对于一个 static 的方法而言,无法访问泛型类的类型参数,所以,如果 static 方法需要使用泛型能力,就必须使其成为泛型方法。
要定义泛型方法,只需将泛型参数列表置于返回值之前,比如:public void f(T x){};
1)杠杆利用类型参数推断
在泛型方法中,类型参数推断可以简化一部分工作。例如,编写一个工具类,它包含各种各样的static方法,专门用来创建各种常用的容器对象,例如:
public class New { public static <K,V> Map<K,V> map() { return new HashMap<K, V>(); } public static <T> List<T> list() { return new ArrayList<T>(); } public static <T> LinkedList<T> lList(){ return new LinkedList<T>(); } public static <T> Set<T> set(){ return new HashSet<T>(); } public static <T> Queue<T> queue(){ return new LinkedList<T>(); } public static void main(String[] args) { Map<String, List<String>> sls = New.map(); List<String> ls = New.lList(); Set<String> ss = New.set(); Queue<String> qs = New.queue(); }}
main()方法演示了如何使用这个工具类,类型参数推断避免了重复的泛型参数列表。类型推断只对复制操作有效,其他时候并不起作用。如果你将一个泛型方法调用的结果作为参数,传递给另一个方法,这时编译器并不会执行类型推断。
显示的类型说明,在泛型方法中,可以显示地指明类型,不过这种语法很少用。要显示地指明类型,必须在点操作符之前使用this关键字,如果是使用static的方法,必须在点操作符之前加上类名。例如New.<Person,List<Pet>> map();
2)可变参数与泛型方法
泛型方法与可变参数列表能够很好地共存,例如:
public class GenericVarargs { public static <T> List<T> makeListT(T... args){ List<T> reList = new ArrayList<T>(); for (T item : args) { reList.add(item); } return reList; } public static void main(String[] args) { List<String> ls = makeListT("A"); System.out.println(ls); ls = makeListT("A","B","C"); System.out.println(ls); ls = makeListT("ABCDEFHIJKLMNOPQRSTUVWXYZ".split("")); System.out.println(ls); }}
makeListT()方法展示了与标准类库中java.util.ArrayList()方法相同的功能。
3)用于Generator的泛型方法
利用生成器,可以很方便地填充一个Collection,而泛型化这种操作时具有实际意义的,例如:
public class Generators { public static <T> Collection<T> fill(Collection<T> coll,Generator<T> gen,int n) { for (int i = 0; i < n; i++) { coll.add(gen.next()); } return coll; } public static void main(String[] args) { Collection<Coffee> coffees = fill(new ArrayList<Coffee>(), new CoffeeGenerator(), 4); for (Coffee coffee : coffees) { System.out.println(coffee); } }}
其中Generator接口、Coffee类以及CoffeeGenerator类在上一篇博客中有,在这个例子中,fill()方法使如何透明地应用于Coffee的容器。
4)一个通用的Generator
下面的程序可以为任何类构造一个Generator,只要该类具有默认的构造器。为了减少类型声明,它提供了一个泛型方法,用以生成BasicGenerator:
public class BasicGenerator<T> implements Generator<T>{ private Class<T> type; public BasicGenerator(Class<T> type){ this.type = type; } @Override public T next() { try { return type.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } public static <T> Generator<T> create(Class<T> type) { return new BasicGenerator<T>(type); }}
这个类提供了一个基本实现,用以生成某个类的对象。这个类必须具备两个特点:(1)它必须声明为public。(因为BasicGenerator与要处理的类在不同的包中,所以该类必须声明为public,并且不只具有包内访问权限。)(2)它必须具备默认的构造器(无参的构造器)。要创建这样的BasicGenerator对象,只需调用create()方法,并传入想要生成的类型。泛型化的create()方法允许执行BasicGenerator.create(MyType.class),而不必执行麻烦的new BasicGenerator(MyType.class)。
例如,下面是一个具有默认构造器的简单的类:
public class CountObject { private static long counter = 0; private final long id = counter ++; public long id(){ return id; } public String toString(){ return "CountObject" + id; }}
CountObject类能够记录下它创建了多少个CountObject实例,并通过toString()方法告诉我们其编号。
使用BasicGenerator,你可以很容易地位CountObject创建一个Generator:
public class BasicGeneratorDemo { public static void main(String[] args) { Generator<CountObject> generator = BasicGenerator.create(CountObject.class); for (int i = 0; i < 5; i++) { System.out.println(generator.next()); } }}output:CountObject0CountObject1CountObject2CountObject3CountObject4
可以看到,使用泛型方法创建Generator对象,大大减少了我们要编写的代码。java泛型要求传入Class对象,以便也可以在create()方法中用它进行类型推断。
5)一个Set的实用工具
作为泛型方法的另一个示例,通过使用泛型方法,可以很方便地做到使用Set来表达数学中的关系式,而且可以应用于多种类型:
public class Sets { public static <T> Set<T> union(Set<T> a,Set<T> b){ Set<T> result = new HashSet<T>(a); result.addAll(b); return result; } public static <T> Set<T> intert(Set<T> a,Set<T> b){ Set<T> result = new HashSet<T>(a); result.retainAll(b); return result; } public static <T> Set<T> difference(Set<T> superset,Set<T> subset){ Set<T> result = new HashSet<T>(subset); result.removeAll(subset); return result; } public static <T> Set<T> complement(Set<T> a,Set<T> b){ return difference(union(a, b), intert(a, b)); }}
在前三个方法中,都将第一个参数Set复制了一份,将Set中的所有引用都存入一个新的HashSet对象中,因此,我们并未直接修改参数中的Set。返回值是一个全新的Set对象。这四个方法表达了一个数学集合的操作,union()返回一个Set,它将两个参数合并在一起,intert()返回的Set只包含两个参数共有的部分;difference()方法从superset中移除subset包含的元素;complement()返回的Set包含除了交集之外的所有元素。
- java编程思想读书笔记 第十五章 泛型 (泛型方法)
- java编程思想读书笔记----第十五章 泛型
- java编程思想读书笔记 第十五章 泛型(上)
- java编程思想读书笔记 第十五章 泛型(中)
- java编程思想读书笔记 第十五章 泛型(下)
- java编程思想读书笔记 第十五章 泛型 (匿名内部类和擦除)
- java编程思想读书笔记 第十五章 泛型(自限定的类型)
- java编程思想读书笔记-第十五章 分布式计算
- 《Java 编程思想》--第十五章:泛型
- 《JAVA编程思想》学习笔记---第十五章:泛型
- Java编程思想读书笔记
- java编程思想读书笔记
- java 编程思想 读书笔记
- <<java编程思想>>读书笔记
- java编程思想读书笔记
- java编程思想读书笔记
- 《Java编程思想》读书笔记
- Java 编程思想 - 读书笔记
- 进制转换
- hdu1671 Phone List 字典树(小组赛E)
- ubuntu 下 ssldump 编译问题解决,及安装使用
- Hibernate之自定义ID生成器
- java: Exception Handle Mechanism
- java编程思想读书笔记 第十五章 泛型 (泛型方法)
- 记录一下python的数据结构 - dict
- Codeforces 732B-Cormen—The Best Friend Of a Man
- Hibernate:一对一双向主键关联
- Android APP--两个Activity传递数据
- JAVA实现单例设计模式
- 安装genymotion安卓模拟器过程中遇到的一些坑
- 质因数分解算法
- c:forEach varStatus属性