【泛型】Generic 参数化类型 类型转换
关于泛型的一些重要知识点
- 【? extends E】接收E类型或者E的子类型对象。上限。一般存储对象的时候用。比如 添加元素 addAll。
- 【? super E】接收E类型或者E的父类型对象。下限。一般取出对象的时候用。比如比较器。
- 1、表示多个可变类型之间的相互关系:HashMap<T,S>表示类型T与S的映射,HashMap<T, S extends T>表示T的子类与T的映射关系。
- 2、细化类的能力:ArrayList<T> 可以容纳任何指定类型T的数据,当T代指人,则是人的有序列表,当T代指杯子,则是杯子的有序列表,所有对象个体可以共用相同的操作行为。
- 3、复杂类型被细分成更多类型:List<People>和List<Cup>是两种不同的类型,这意味着List<People> listP = new ArrayList<Cup>()是不可编译的。这种检查基于编译时而非运行时,所以说是不可编译并非不可运行,因为运行时ArrayList不保留Cup信息。另外要注意,即使People继承自Object,List<Object> listO = new ArrayList<People>()也是不可编译的,应理解为两种不同类型。因为listO可以容纳任意类型,而实例化的People列表只能接收People实例,这会破坏数据类型完整性。
泛型的基本概念
public interface java.lang.reflect.ParameterizedType extends Type
public interface java.lang.reflect.GenericDeclaration
所有已知实现类:Class、Constructor、Method
实例分析
public class ArrayList{
public Object get(int i){......}
public void add(Object o){......}
......
private Object[] elementData;
}
- 没有错误检查,可以向数组列表中添加任何类的对象
- 在取元素的时候,需要进行强制类型转换
/**jdk1.5之前的写法,容易出问题*/
ArrayList arrayList1=new ArrayList();
arrayList1.add(1);
arrayList1.add(1L);
arrayList1.add("asa");
int i=(Integer) arrayList1.get(1);//因为不知道取出来的值的类型,类型转换的时候容易出错
/** jdk1.5之后加入泛型*/
ArrayList<String> arrayList2=new ArrayList<String>(); //限定数组列表中的类型
//arrayList2.add(1); //因为限定了类型,所以不能添加整形
//arrayList2.add(1L);//因为限定了类型,所以不能添加整长形
arrayList2.add("asa");//只能添加字符串
String str=arrayList2.get(0);//因为知道取出来的值的类型,所以不需要进行强制类型转换
泛型的使用
泛型类:类名后面
public class HashMap<K,V> {
public V put(K key, V value) {...}
public V get(Object key) {...}
...
}
public class Pair<T> {
private T value;
public Pair(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
public static void main(String[] args) throws ClassNotFoundException {
Pair<String> pair = new Pair<String>("Hello");//注意,"="号左边和右边都要使用<>指定泛型的实际类型
String str = pair.getValue();
pair.setValue("World");
}
class Pair<T, S, P, U, E> { }
泛型接口
interface Show<T,U>{
void show(T t,U u);
}
public class ShowTest implements Show<String, Date> {
@Override
public void show(String t, Date u) {
System.out.println(t + " " + u.getTime());
}
}
Show<String, Date> show = new ShowTest();
show.show("包青天", new Date());
泛型方法:返回值之前
class Person<S> {
public <W> void show(W w) {//这里的【W】完全等价于Object
if (w != null) System.out.println(w.toString());
}
public static <Y> void staticShow(Y y) {
if (y != null) System.out.println(y.toString());
//静态方法不能访问在类声明上定义的类型变量
//S s;//错误提示:Cannot make a static reference to the non-static type S
}
}
泛型变量的类型限定
- 无限定的泛型变量等价于Object(白哥添加)
- 不管该限定是类还是接口,统一都使用关键字 extends
- 可以使用 & 符号给出多个限定
- 如果限定既有接口也有类,那么类必须只有一个,并且放在首位置
public static <T extends Comparable> T get(T t1,T t2) //继承或实现都用extends
public static <T extends Comparable & Serializable> T get(T t1,T t2) //使用 & 符号给出多个限定
public static <T extends Object & Comparable & Serializable> T get(T t1,T t2) //继承的类Object必须放在首位
通配符?的使用
- 无限定通配符 形式<?>
- 上边界限定通配符 形式< ? extends Number>
- 下边界限定通配符 形式< ? super Number>
public static void main(String[] args) throws Exception {
List<Integer> listInteger = new ArrayList<Integer>();
printCollection(listInteger);//报错 The method printCollection(Collection<Object>) in the type Test is not applicable for the arguments (List<Integer>)
}
public static void printCollection(Collection<Object> collection) {
for (Object obj : collection) {
System.out.println(obj);
}
}
public static void printCollection(Collection<?> collection) {...}
collection.add(new Object());//The method add(capture#1-of ?) in the type Collection<capture#1-of ?> is not applicable for the arguments (Object)
List<? extends Number> x = new ArrayList<Integer>();//正确
List<? extends Number> y = new ArrayList<Object>();//错误 Type mismatch: cannot convert from ArrayList<Object> to List<? extends Number>
List<? super Number> y = new ArrayList<Object>();//正确
List<? super Number> x = new ArrayList<Integer>();//错误 Type mismatch: cannot convert from ArrayList<Integer> to List<? super Number>
类型擦除
ArrayList<String> list1 = new ArrayList<String>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
System.out.println((list1.getClass() == list2.getClass()) + " " + (list1.getClass() == ArrayList.class));//true true
List<Integer> list = new ArrayList<Integer>();
list.add(10086);
Method method = list.getClass().getMethod("add", Object.class);
//运行时利用反射机制调用集合的add方法,跳过编译时的泛型检查
method.invoke(list, "虽然集合中对元素限定的泛型是Integer,但是也能通过反射把字符串添加到集合中");
Object object = list.get(1);
System.out.println(object.getClass().getSimpleName() + " " + (object.getClass() == String.class));//String true
try {
System.out.println(((Object) list.get(1)).getClass());//class java.lang.String
System.out.println(list.get(1).getClass());//如果不指定list.get(1)的类型,则会默认将其强制转换为集合上指定的泛型类型
} catch (Exception e) {
e.printStackTrace();//java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
}
类型擦除后保留的原始类型
class Pair<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
class Pair {
private Object value;
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
public class Pair<T extends Comparable& Serializable> { ... }
public class Pair<T extends Serializable & Comparable>
- 在不指定泛型的时候,泛型变量的类型为 该方法中的几种类型的同一个父类的最小级,直到Object。
- 在指定泛型的时候,该方法中的几种类型必须是该泛型实例类型或者其子类。
public class Test {
public static void main(String[] args) {
/**不指定泛型的时候,泛型变量的类型为 该方法中的几种类型的同一个父类的最小级,直到Object*/
int i = Test.add(1, 2); //这两个参数都是Integer,所以T为Integer类型
Number f = Test.add(1, 1.2);//这两个参数一个是Integer,一个是Float,所以取同一父类的最小级,为Number
Object o = Test.add(1, "asd");//这两个参数一个是Integer,一个是Float,所以取同一父类的最小级,为Object
/**指定泛型的时候,该方法中的几种类型必须是该泛型实例类型或者其子类*/
int a = Test.<Integer> add(1, 2);//指定了Integer,所以只能为Integer类型或者其子类
//int b = Test.<Integer> add(1, 2.2);//编译错误,指定了Integer,不能为Float
Number c = Test.<Number> add(1, 2.2); //指定为Number,所以可以为Integer和Float
}
public static <T> T add(T x, T y) {
return y;
}
}
附加:GenericDeclaration 接口
public interface java.lang.reflect.GenericDeclaration
- TypeVariable<?>[] getTypeParameters() 返回声明顺序的 TypeVariable 对象的数组,这些对象表示由此 GenericDeclaration 对象表示的一般声明声明的类型变量。
- 返回:表示由此一般声明声明的类型变量的 TypeVariable 对象的数组
- 如果底层的一般声明未声明任何类型变量,则返回一个 0 长度的数组。
public static <T extends Person, U> void main(String[] args) throws Exception {
Method method = Test.class.getMethod("main", String[].class);
TypeVariable<?>[] tvs = method.getTypeParameters();//返回声明顺序的 TypeVariable 对象的数组
System.out.println("声明的类型变量有:" + Arrays.toString(tvs));//[T, U]
for (int i = 0; i < tvs.length; i++) {
GenericDeclaration gd = tvs[i].getGenericDeclaration();
System.out.println("【GenericDeclaration】" + gd);//public static void com.bqt.Test.main(java.lang.String[]) throws java.lang.Exception
System.out.println(gd.getTypeParameters()[i] == tvs[i]);//true。 GenericDeclaration和TypeVariable两者相互持有对方的引用
System.out.println(tvs[i] + " " + tvs[i].getName() + " " + Arrays.toString(tvs[i].getBounds()));//T T [class com.bqt.Person] 和 U U [class java.lang.Object]
}
}
【泛型】Generic 参数化类型 类型转换的更多相关文章
- 泛型 Generic 类型擦除引起的问题及解决方法
参考:http://blog.csdn.net/lonelyroamer/article/details/7868820#comments 因为种种原因,Java不能实现真正的泛型,只能使用类型擦除来 ...
- Java之集合初探(二)Iterator(迭代器),collections,打包/解包(装箱拆箱),泛型(Generic),comparable接口
Iterator(迭代器) 所有实现了Collection接口的容器都有一个iterator方法, 用来返回一个实现了Iterator接口的对象 Iterator对象称作迭代器, 用来方便的实现对容器 ...
- C#泛型(Generic)
一.什么是泛型 泛型(Generic)是C#语言2.0.通用语言运行时(CLR)2.0..NET Framework2.0推出来的新特性. 泛型为.NET框架引入类型参数(Type Parameter ...
- Java - 泛型 ( Generic )
Java - 泛型 ( Generic ) > 泛型的特点 > 解决元素存储的安全性问题 > 解决获取数据元素时,需要类型强转的问题 ...
- 谈一谈从 Delphi 2009 之后就支援的重要功能 – 泛型 (Generic)
前言 在C++的语言基础当中,除了物件导向.事件驱动的概念之外,模版设计(Template)也是非常重要的一环.然而,C++的开发人员能够善用模版设计的并不多.模版设计这个好物,一般还有一个名称,就是 ...
- JAVA中的泛型(Generic)
Java泛型(Generic)简介 泛型是jdk1.5版本以后推出来的,表示类型参数化,让java能更具有动态性一些,让类型能变成参数传递. 要我自己感觉的话,泛型本身没啥用,跟反射在一起用,就体现出 ...
- Dephi泛型generic的应用
Dephi泛型generic的应用 泛型在C++, C#中已有广泛应用,Delphi自2009版本也引入泛型,典型的应用如TList,TDictionary.如果你熟悉C#,其用法十分类似. 比如 ...
- Java基础之Comparable接口, Collections类,Iterator接口,泛型(Generic)
一.Comparable接口, Collections类 List的常用算法: sort(List); 排序,如果需要对自定义的类进行排序, 那就必须要让其实现Comparable接口, 实现比较两个 ...
- Java自学-集合框架 泛型Generic
ArrayList上使用泛型 步骤 1 : 泛型 Generic 不指定泛型的容器,可以存放任何类型的元素 指定了泛型的容器,只能存放指定类型的元素以及其子类 package property; pu ...
随机推荐
- java实现两台电脑间TCP协议文件传输
记录下之前所做的客户端向服务端发送文件的小项目,总结下学习到的一些方法与思路. 注:本文参考自<黑马程序员>视频. 首先明确需求,在同一局域网下的机器人A想给喜欢了很久的机器人B发送情书, ...
- React Native之网页组件WebView的使用与通信
在实际开发中,我们通常会嵌入一些html页面,官方为我们提供了一个非常好用的网页组件WebView,通过这个组件我们可以通过传入一个url或者是传入一段html 一. WebView的基本属性方法介绍 ...
- C++运算符重载 模板友元 new delete ++ = +=
今天的重载是基于C++ 类模板的,如果需要非类模板的重载的朋友可以把类模板拿掉,同样可以参考,谢谢. 一.类模板中的友元重载 本人喜好类声明与类成员实现分开写的代码风格,如若您喜欢将类成员函数的实现写 ...
- 删除或修改eclipse中svn的账号密码
由于eclipse没有自带的管理svn账号的功能,我也没有找到相关的插件,要是有朋友知道的话也可以跟我说下哦!以下是关于自己手动去删除eclipse 软件的 svn账号,以便切换项目的时候去更换svn ...
- python opencv3 基于ORB的特征检测和 BF暴力匹配 knn匹配 flann匹配
git:https://github.com/linyi0604/Computer-Vision bf暴力匹配: # coding:utf-8 import cv2 """ ...
- 80X86指令总结
一.数据传送指令 指令名称 汇编语句格式 功能 影响标志位 传送move data mov opd, ops (ops) → opd:分为主存储器.通用寄存器.段寄存器,不可同时使用主存储器,类型要匹 ...
- Python环境右键定制
有时候,我们需要将py打包成exe.需要将ui转换成py.需要将py转换成pyc等等,命令行操作起来有点繁琐.所以做了这个教程: 1. py打包成exe 先安装cx_freeze,参照教程:http: ...
- .NET面试宝典-高级2
http://blog.csdn.net/shanyongxu/article/category/6023593 对于 Web 性能优化,您有哪些了解和经验吗? 1.前端优化 (1)减少 HTTP 请 ...
- Android 手机 无线 ADB
要用网络调试Android需要设备已经获取root权限 如果手机没有命令行工具,请先在手机端安装终端模拟器,然后在终端输入: $su #stop adbd #setprop service.adb.t ...
- HDU4548+筛素数
先筛出素数,再筛出美素数. 简单题. /* 筛素数 */ #include<stdio.h> #include<string.h> #include<stdlib.h&g ...