【泛型】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> {@Overridepublic 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】完全等价于Objectif (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.StringSystem.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,所以取同一父类的最小级,为NumberObject 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.ExceptionSystem.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]}
}
转载于:https://www.cnblogs.com/baiqiantao/p/7475696.html
【泛型】Generic 参数化类型 类型转换相关推荐
- Java程序低手之关于泛型(Generic)
虽然一直以来,Java都提供了强制类型转换,但是那确实是Java的弱点,因为你是在取数据的时候才保证了类型安全(Type-safe),而不是在存储数据的时候就做好这项工作,Java5提供了Generi ...
- 泛型方法的定义和使用_泛型( Generic )
泛型(Generic) 1. 泛型概述 泛型是一个未知的, 不确定的数据类型. 比如ArrayList 中的E, 就是一个未知的不确定的数据类型, 那么他就是一个泛型 泛型虽然是一个未知的, 不确定的 ...
- 你真的了解泛型 Generic 嘛?
泛型 Generic Programming[1] 通常指允许程序员在强类型程序设计语言中,编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型,即类型参数化 首先我们不是科班讨论学术, ...
- DotNET:LINQ对泛型(Generic)操作和泛型方法及属性
ylbtech-DotNET:泛型(Generic)和LINQ操作 1,遍历泛型集合 2,根据索引位置移除项(RemoveAt()) 3,查询一个人(Single()) 3.2,查询一个人(Singl ...
- Java - 泛型 ( Generic )
Java - 泛型 ( Generic ) > 泛型的特点 > 解决元素存储的安全性问题 > 解决获取数据元素时,需要类型强转的问题 > 不能在 static 方法中使用泛型, ...
- 泛型(generic)概述和基本使用
泛型(generic)概述和基本使用 A:泛型概述 集合边上有一个尖括号,尖括号指的就是泛型. 限定集合存储的数据类型,如果加上这个引用数据类型, 就告诉你这个集合只能存储该类型对象和该类型的子类对象 ...
- java泛型(Generic)超详细
目录 1.为什么要有泛型(Generic)? 2.泛型的设计背景 2.1那么为什么要有泛型呢,直接Object不是也可以存储数据吗? 3.在集合中使用泛型 4.自定义泛型结构 4.1自定义泛型结构:泛 ...
- java参数传入泛型类型_Java 泛型(参数化类型)
Java 泛型 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所 ...
- Java泛型(1)--集合使用泛型Generic、自定义泛型、泛型在继承上的体现、通配符的使用
文章目录 泛型的概念 集合中使用泛型 自定义泛型结构 泛型在继承上的体现 通配符的使用 泛型的概念 集合容器类在设计阶段/声明阶段不能确定这个容器实际存的是什么类型的对象,所以在JDK1.5之前只能把 ...
最新文章
- Atitit.Java exe bat 作为windows系统服务程序运行
- 读取cc2530节点的设备类型、协调器、路由器、终端。
- Java程序转成exe可执行程序方法和exe4_j下载地址和破解。
- Java编写抓取用户信息代码_[代码全屏查看]-一个基于JAVA的知乎爬虫,抓取知乎用户基本信息...
- 团队作业9——第二次项目冲刺2(Beta阶段)
- [数分提高]2014-2015-2第7教学周第2次课 (2015-04-16)
- OSI 参考模型与TCP/IP 参考模型的比较
- Wi-Fi 6 「破茧成蝶」,高通全面布局端到端最佳解决方案
- 最老程序员创业札记:全文检索、数据挖掘、推荐引擎应用36
- html 画布 重置,html5清空画布的方法有哪些
- MFC使用简单总结(便于以后查阅)
- 文献管理三剑客之noteexpress endnote 资源和论文的搬迁备份
- shell sort 最后一列排序_Shell 编程 排序工具 sort 和 uniq
- JavaScript 高级程序设计笔记
- 18位身份证正则及校验码计算
- 春考计算机c语言题,2011春江苏省计算机等级考试c语言试题答案
- (全程图解)Axure RP8.0安装、破解、汉化教程
- 个人所得综合税年度汇算,个税计算公式,个税计算案例
- 百度地图自定义大头针图片和添加标注
- Android hilt 依赖注入使用详解
热门文章
- OSI分层和五层协议
- iOS混淆 -- 生成define 替换名
- 算法分类整理+模板②:字符串处理
- Google Nexus5在linux下刷原生安卓 android6.0
- SQL Server2000 “mcc 无法创建管理单元”
- ProgressBar 类
- 转:如何求出grid图像每个cell对应的x,y坐标?
- C语言 数字和字符串的转换 error
- WPF 问题 PresentationCore.dll!System.Windows.Media.Composition.DUCE.Channel.SyncFlush() 分析
- CentOS 7 防火墙开启了哪些服务和端口?