学习笔记07—泛型
来源:互联网 发布:阿里云域名解析冲突 编辑:程序博客网 时间:2024/04/28 06:31
泛型的真正内容可以说是博大精深。
据说有复杂的数学证明云云。。。
泛型说到底也是运用抽象思维模式对现实世界进行抽象的产物。
过去在农村,人们把猪、牛、羊、猫、狗、鸡、鸭都养在一起,虽然这样有利于动物们相互交流感情,但是不利于分类管理,
后来条件好了,人们便把猪放进猪圈,把羊放进羊圈,把猫放进猫......洞。。。一个场所只养一类动物,这样才更有利于它们健康成长。
这就是泛型。
可是话又说回来,要具体情况具体分析。家畜混养其实是一门学问。
把适合混养的两种家畜放在一起有时候可以降低成本,提高产量,增进动物种群间的相互交流。
举一个例子,把羊和兔子放在一起养是经过实践证明了的养殖方式。好处是兔子得病少。。。扯远了。。。。
但是从数学和逻辑上看,泛型要复杂的多。在本篇仅仅介绍基本应用。
泛型
入门
通过反射手段绕过泛型的限制
集合上的泛型仅仅在编译前起到约束作用,编译时会去掉泛型信息
ArrayList<String>的字节码和ArrayList<Integer>的字节码是完全一样的
例程:
package cn.itcast.day2; import java.lang.reflect.InvocationTargetException;import java.util.ArrayList; public classGenericTest { /** * @param args */ publicstaticvoidmain(String[] args) throws Exception { // TODO Auto-generated method stub ArrayList collec = new ArrayList(); collec.add(1); collec.add(1L); collec.add("abc"); // 不知道添加的元素类型,会发生类转换异常 // int i = (Integer) collec.get(1); // System.out.println(i); ArrayList<String> collec2 = newArrayList<String>(); collec2.add("abc"); ArrayList<Integer> collec3 = newArrayList<Integer>(); collec3.add(2); // 泛型是给编译器看的,编译时会去掉类型信息 // 泛型是Integer和String的ArrayList,其字节码是相同的 boolean flag = collec2.getClass() ==collec3.getClass(); System.out.println(flag); // 根据上面的原理,可以通过反射,绕过泛型,向集合添加其他类型元素 // 尽管collec3是个带有Integer泛型的ArrayList对象,但是可以用反射方法添加String对象 collec3.getClass().getMethod("add", Object.class).invoke(collec3, "def"); System.out.println(collec3.get(1)); // 输出def,成功添加 } }
了解泛型其他特点
了解泛型
ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:
整个称为ArrayList<E>泛型类型
ArrayList<E>中的E称为类型变量或类型参教
整个ArrayList<Integer>称为参数化的类型
ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
ArrayList<Integer>中的<>念着typeof
ArrayList称为原始类型
参数化类型与原始类型的兼容性:
参数化类型可以引用一个原始类型的对象.编译报告警告.例如
Colloctlon<String>c = new Vector(); //可不可以,不就是编译器一句话的事吗?
原始类型可以引用一个参数化类型的对象,编译报告警告,例如
Colloctlonc = new Vector<String>(); //原来的方法接受一个集合参数,新的类型也要能传进去
参数化类型不考虑类型参数的继承关系:
Vector<String>v = new Vector<Object>(); //错误!不写<Object>没错,写了就是明知故犯
Vector<Object>v = new Vector<String>(); //也错误!
在创建数组实例时.数组的元素不能使用参数化的类型,例如,下面语句有错误:
Vector<Integer> vectorList[] = new Vector<Integer>[10];
思考题:下面的代码会报错误吗?
Vectorv1 = new Vector<String>();
Vector<Object>v = v1;
解答:
不会报错。按行解释。
泛型的通配符和扩展
通配符?
extends、super用于限定?的上下边界
extends还可以用到& 表示多个接口的子类
泛型集合的综合应用
// 泛型集合的综合应用,HashMap转成Set并输出其元素HashMap<String, Integer> map =newHashMap<String, Integer>();// 添加键值对map.put("a", 24);map.put("b", 25);map.put("c", 26); // 转换为SetSet<Map.Entry<String,Integer>> entrySet = map.entrySet();// 迭代for (Map.Entry<String, Integer> entry : entrySet) { System.out.println(entry.getKey()+ " : "+ entry.getValue());}
自定义泛型的语法和类型推断
在返回值前用<T>表示定义一个泛型
例如:(仅用于演示语法)
publicstatic<T> T add (T a, T b) {
return null;
}
在使用时返回值要取a和b的并集
Object obj = add(5, "abc");
Number f = add(3, 3.56);
一个具有实际意义的例子:
// 一个具有实际意义的运用泛型的方法,交换任意类型数组中两个元素的位置 publicstatic<T> voidswap (T[] t, inta, intb) { T tmp =t[a]; t[a] = t[b]; t[b] = tmp; }
在main中调用该方法:
String[] strs = new String[] {"ab", "OK", "hello"}; swap(strs, 1, 2); for (String str : strs) { System.out.println(str); }
输出:
ab
hello
OK
但是,需要注意的是上面的例子换成int[]就不可以了。
T只能代表引用类型。
只有引用类型才能作为泛型方法的实际参数。
在用于演示语法的例子中之所以能够用int类型是因为“自动装箱”的缘故。
通过反射获得泛型的参数化类型:
Vector<Date> v = newVector<Date>();
通过v.getClass()无法获得参数化类型
将其传递给一个方法,可实现此功能。
public static void applyVector(Vector<Date>v){} Method applyMethod =GenericTest.class.getMethod("applyVector", Vector.class);Type[] types =applyMethod.getGenericParameterTypes();ParameterizedType pType = (ParameterizedType)types[0];System.out.println(pType.getRawType());//VectorSystem.out.println(pType.getActualTypeArguments()[0]);//Date
附篇:
源文档 <http://blog.csdn.net/wzg199088/article/details/6755711>
宏,堆栈,变量,数组,集合,泛型集合
数组是类型相同,长度固定的存储方式。
集合是类型不同,长度可变的存储方式。
而泛型集合则是类型相同,长度可变的存储方式。
泛型:
将类的类型作为参数,制定到其他类或者方法上从而保证类型转换的安全和稳定。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
定义:将类的类型作为参数,指定到其他类或者方法上,从而保证类型转换的安全性和稳定性
好处:是在编译的时候检查类型,并且所有的强制转换都是自动和隐式的,提高代码的重用率。保证编译正确,复用性强,安全性高。
类型参数化:所操作的数据类型被指定为一个参数
类型变量:一种非限定性标识符,用来指定类,接口和方法的类型。规范:①.使用大写较短②.E表示集合的元素类型③ K V 键-值对④T任意类型
擦除:将具有泛型信息的对象赋给一个没有泛型信息的变量,则会发生擦除的现象。
泛型接口:实现类必须是泛型类,且类型参数列表一致
注意 Driver<T> Person为实现类
①建立类型参数在实现时,不加修改。在创建时将具体形式传递给接口
②类型参数不为实际类型时,实现类必须是泛型类
public class Person<T> implements Driver<T>
③当实现特定类型的泛型接口时,实现类可以不是泛型
public class Person implements Driver<String>
优势:
①针对不同数据类型实现
②对接口数据类型进行限制
泛型类:
泛型类与非泛型类的层次关系区别在于,泛型类层次的全部子类必须将泛型父类需要的参数类型,逐级想上进行传递,这种传递方式与构造方法的向上调用很类似
注意:①定义对象需要指定数据类型 ②使用构造也需要指定类型
泛型类派生子类 允许泛型子类为
class B extends A 虽然不抱错但失去了泛型的意义,A中包含的T会转变成Object
class B<T> extends A<T>可以在使用的过程中指定T的类型
class B<T,V> extendsA<T> T是A中的类型,也可以指定B所特有的类型V这样就扩展了B
class B extends A<String>也可以直接指定A中T的类型,就不需要在B中重复指定了
注意:
1.使用非泛型类继承泛型类或实现接口是,父类和接口中不能再包含类型参数
2.在派生子类时,可使用实际类型代替父类中的参数类型。子类可不再指定类型
3.允许在使用泛型类或接口时,不传入实际参数代替,编译警告。子类重写时会转换父类参数类型为Object
泛型方法:非/泛型类,不依赖泛型类或接口
public<T> void test(Tt){} 无须显示传入实际类型参数,根据传入参数
类型通配符:
普通通配符:类<?>对象名 = new类2<指定类型>
有限制的通配符(有界通配符):
? extends A <= 当前类,父类
? super B >= 当前类,活这当前类的超类
总结:
(1)泛型 泛型的类型参数只能是类(自定义类)不能是简单类型
(2)同一种泛型,可对应多个版本,不同版本泛型实例不兼容
(3)泛型类型多个
(4)有界通配符
(5)通配符?
- 学习笔记07—泛型
- 机器学习—学习笔记
- java学习笔记——泛型Generic
- Java 学习笔记——泛型
- JAVA学习笔记——泛型
- Kotlin学习笔记——泛型
- Javascript学习笔记07——DOM
- java学习笔记07—IO流
- iOS学习笔记07—网络编程
- Duilib学习笔记《07》— 资源加载
- Duilib学习笔记《07》— 资源加载
- Duilib学习笔记《07》— 资源加载
- c#学习笔记--泛型
- C#学习笔记-泛型
- 学习笔记 --泛型
- JavaSE学习笔记--泛型
- Java学习笔记(泛型)
- C#学习笔记-泛型
- JVM内存管理和GC
- 收藏的网页--视频教程
- mysql命名锦集
- realoj 134 DP 最长上升子序列
- 第七周 项目四:复数模板类
- 学习笔记07—泛型
- python版本DDOS攻击脚本
- ie6下png图片变透明解决方案
- 100个动规方程
- java.lang.OutOfMemoryError: Java heap space修改tomcat启动时所占内存大小
- 开发团队的人员结构
- C语言INT64类型和GCC中的long long的定义,及sprintf格式字符串的定义
- 为URLConnection设置超时机制 分享
- url.openStream()和url.openConnection().getInputStream()两者区别