JAVA编程思想笔记--泛型
来源:互联网 发布:高清矩阵厂家 编辑:程序博客网 时间:2024/06/06 20:50
1 . 泛型的主要目的之一就是用来指定容器要持有什么类型的对象。
2 . 简单泛型
(1)有许多原因促成了泛型的出现,而最引人注目的一个原因就是为了创造容器类。
public class Holder3<T> { private T a ; public Holder3(T a){ this.a = a ; } public void set(T a) { this.a = a ; } public T get(){ return a; } public static void main(String[] args) { Holder3<Automobile>(new Automobile()); Automobile a = h3.get() ; })}
3 .元组:
(1) 仅一次方法调用就能返回多个对象
(2) 它是将一组对象直接打包存储于其中的一个单一对象。这个容器对象允许读取其中元素,但是不允许向其中存放新的对象。
public class TwoTuple<A ,B> { //二维元组 ,public外部可以随意访问,final无法改变数据 //可以随便使用对象,但无法修改数据 //声明为final的元素便不能被再赋予其他值了 public final A first ; public final B second ; public TwoTuple(A a,B b){ first = a; second = b; } public String toString(){ return "("+first+"."+second+")"; }}
4 . 泛型方法
(1)同样可以在类中包含参数化方法,而这个方法所在的类可以是泛型类,也可以不是泛型类。是否拥有泛型方法,与其所在的类是否是泛型没有关系。泛型方法使得该方法能够独立于类而产生变化。
(2)如果使用泛型方法可以取代将整个类泛型化,那么就应该只使用泛型方法,因为它可以使事情变得更加清楚明白。
(3)对于一个static的方法而言,无法访问泛型类的类型参数,所以如果static方法需要使用泛型能力,就必须使其成为泛型方法
public class GenericMethods { //要定义泛型方法,只需将泛型参数列表置于返回值之前 public <T> void f(T x) { System.out.print(x.getClass().getName()); } public static void main(String[] args) { GenericMethods gm = new GenericMethods(); gm.f(""); gm.f(1); }}
5 .杠杆利用类型参数推断
//问题:重复自己做过的事情Map<Person,List<? extends Pet>> petPeople = new HashMap<Person,List<? extends Pet>>();
//工具类:类型参数推断避免了重复的泛型参数列表 ,但代码可读性差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.list(); LinkedList<String> lls = New.lList(); Set<String> ss = New.set(); Queue<String> qs = New.queue(); }}
(1)类型推断只对赋值操作有效,其他时候不起作用。如果你将一个泛型方法调用(例如New.map())作为参数,传递给另一个方法,这时编译器并不会执行类型推断。例如:
public class TestOne { static void f(Map<Person,List<? extends Pet>> petPeople) {}; public static void main(String[] args) { //f(New.map()); //无效 } }
6.可变参数与泛型方法
public class TestOne { public static <T> List<T> makeList(T... args){ List<T> result = new ArrayList<T>(); for(T item : args){ result.add(item); } return result; } public static void main(String[] args) { List<String> ls = makeList("A","B","C"); System.out.println(ls); } }
7.构建复杂模型
(1)泛型的一个重要好处是能够简单而安全地创建复杂的模型
8.类型擦除
(1)在泛型代码内部,无法获得任何有关泛型参数类型的信息。任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。
(2)例如:List 这样的类型注解将被擦除为List。而普通的类型变量在未指定边界的情况下将被擦除为Object。
(3)边界处的动作:正是因为有了擦除,泛型可以表示没有任何意义的
public class ArrayMaker<T> { //kind被存储为Class<T>,擦除意味着它实际将被存储为Class,没有任何参数。 //因此,当在使用它时,例如创建数组时,Array.newInstance()实际上并未拥有kind //所蕴含的类型信息,因此这不会产生具体的结果,所以必须转型 private Class<T> kind ; public ArrayMaker(Class<T> kind){ this.kind = kind ; } @SuppressWarnings("unchecked") T[] create(int size){ return (T[])Array.newInstance(kind, size); } public static void main(String[] args) { ArrayMaker<String> stringMaker = new ArrayMaker<String>(String.class); String[] stringArray = stringMaker.create(9); System.out.println(Arrays.toString(stringArray)); } }
(4)对于在泛型中创建数组,使用Array.newInstance()是推荐的方式。
9.擦除的补偿
(1)擦除丢失了在泛型代码中执行某些操作的能力。任何在运行时需要知道确切类型信息的操作都将无法工作:
public class Erased<T> {private final int SIZE = 100 ;//错误代码public static void f(Object arg){ if(arg instanceof T ){}; //Error 因为其类型信息已经被擦除了 T var = new T(); //Errot T[] array = new T[SIZE]; //Errot T[] array = (T)new Object[SIZE] ; //Unckecked warning}}
有时必须通过引入类型标签来对擦除进行补偿。这意味着你需要显式地传递你的类型的Class对象,以便你可以在类型表达式中使用它。
class Building{};class House extends Building{};public class Erased<T> { Class<T> kind; public Erased(Class<T> kind){ this.kind = kind ; } public boolean f(Object arg){ return kind.isInstance(arg); } public static void main(String[] args){ Erased<Building> ctt1 = new Erased<Building>(Building.class); System.out.println(ctt1.f(new Building())); //true System.out.println(ctt1.f(new House())); //true }}
10.不能创建泛型数组,一般的解决方案是在任何想要创建泛型数组的地方都使用ArrayList
public class ListOfGenerics<T> { private List<T> array = new ArrayList<T>(); public void add(T item){ array.add(item); } public T get(int index){ return array.get(index); }}
11.边界
(1)Java泛型重用了extends关键字,能够将这个参数限制为某个类型子集
class Colored2<T extends Hascolor> extends HoldItem<T> {}
12.通配符
13.问题
(1).任何基本类型都不能作为类型参数,因此不能创建ArrayList< int >之类的东西,解决之道是使用基本类型的包装类以及Java SE5的自动包装机制。如果创建一个ArrayList< Integer > ,并将基本类型int应用于这个容器。那么你将发现自动包装机制将自动地实现int到Interger的双向转换。
(2)一个类不能实现同一个泛型接口的两种变体,由于擦除的原因,这两个变体会成为相同的接口。
interface Payable<T> {};class Employee implements Payable<Employee> {};class Hourly extends Employee implements Payable<Hourly> {};
Hourly不能编译,因为擦除会将Payable和Payable< Hourly > 简化为相同的类Payable.
- 泛型-java编程思想笔记
- JAVA编程思想笔记--泛型
- Java编程思想 笔记
- 《java编程思想》笔记
- java编程思想笔记
- Java编程思想笔记
- java编程思想笔记
- java编程思想 笔记
- java编程思想笔记
- java 编程思想 笔记
- 《Java编程思想》笔记
- Java编程思想 笔记
- java编程思想笔记
- java编程思想笔记
- java 编程思想笔记
- java 编程思想 笔记
- Java编程思想笔记
- 看"java编程思想"笔记
- 第七章 假设检验
- 使用sklearn进行数据挖掘
- vivado 设置 多线程编译
- (转)献给迷茫中的量化工作者
- 在struts2中 使用poi出现报错
- JAVA编程思想笔记--泛型
- bzoj3560 DZY Loves Math V
- bzoj 3252: 攻略 (线段树+DFS序)
- 剑指offer-跳台阶
- 关于 link monitor exit process_flag
- (转)郭广昌:复星账上有400亿现金,未来十年一切围绕C2M战略
- Android--简单计算器
- Servlet
- Linux 修改Oracle数据库字符集