【Java】泛型
泛型
为什么要有泛型
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。Collection,List,ArrayList 这个就是类型参数,即泛型。
- 解决元素存储的安全性问题
- 解决获取数据元素时,需要类型强制转换的问题
没有泛型时:
有泛型时:
Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮。
在集合中使用泛型
ArrayList<Integer> list = new ArrayList<>();//类型推断
list.add(78);
list.add(88);
list.add(77);
list.add(66);
//遍历方式一:
//for(Integer i : list){
//不需要强转
//System.out.println(i);
//}
//遍历方式二:
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
泛型的嵌套:
Map<String,Integer> map = new HashMap<String,Integer>();
map.put("Tom1",34);
map.put("Tom2",44);
map.put("Tom3",33);
map.put("Tom4",32);
//添加失败
//map.put(33, "Tom");
Set<Entry<String,Integer>> entrySet = map.entrySet();
Iterator<Entry<String,Integer>> iterator = entrySet.iterator();
while(iterator.hasNext()){
Entry<String,Integer> entry = iterator.next();
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
泛型在接口的使用:
public class Employee implements Comparable<Employee>
使用泛型后,该接口内涉及泛型的方法的参数都会变成该类型
总结:
集合接口或集合类在jdk5.0时都修改为带泛型的结构。
在实例化集合类时,可以指明具体的泛型类型
指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。
比如:add(E e) —>实例化以后:add(Integer e)
注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。
jdk7的新特性:
Map<String,Integer> map = new HashMap();//HashMap<String,Integer>();
前面用了泛型后面可以不用。
如何自定义泛型结构
interface List 和 class GenTest<K,V> ,其中,T,K,V不代表值,而是表示类型。这里使用任意字母都可以。常用T表示,是Type的缩写。
自定义泛型类、接口
public class Order<T> {
String orderName;
int orderId;
//类的内部结构就可以使用类的泛型
T orderT;
public Order(){
}
public Order(String orderName,int orderId,T orderT){
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
//如下的三个方法都不是泛型方法
public T getOrderT(){
return orderT;
}
public void setOrderT(T orderT){
this.orderT = orderT;
}
@Override
public String toString() {
return "Order{" +
"orderName='" + orderName + '\'' +
", orderId=" + orderId +
", orderT=" + orderT +
'}';
}
}
如果定义了泛型类,实例化没有指明类的泛型,则以此泛型类型为Object类型处理,但不完全等价于Object类型,要么一直用泛型,要么都不用。
Order order = new Order();
order.setOrderT(123);
order.setOrderT("ABC");
由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型。
SubOrder sub1 = new SubOrder();
sub1.setOrderT(1122);
SubOrder1<String> sub2 = new SubOrder1<>();
sub2.setOrderT("order2...");
泛型不同的引用不能相互赋值
ArrayList<String> list1 = null;
ArrayList<Integer> list2 = new ArrayList<Integer>();
list1 = list2;
如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象,泛型的指定中不能使用基本数据类型,可以使用包装类替换。
异常类不能是泛型的,自定义的异常类也不可以。
public void show(){
//编译不通过
try{
}catch(T t){
}
}
静态方法中不能使用类的泛型,报错,因为泛型是在实例化对象才确定的,但是static方法是在类加载的时候就可以使用的。
public static void show(T orderT){
System.out.println(orderT);
}
泛型类数组的创建
//编译不通过
T[] arr = new T[10];
//编译通过
T[] arr = (T[]) new Object[10];
父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
意思就是子类可以继承父类所有的,然后自己可以额外增加。
class Father<T1, T2> {
}
子类不保留父类的泛型:按需实现
没有类型 擦除
class Son1 extends Father {// 等价于class Son extends Father<Object,Object>{
}
class Son<A, B> extends Father{//等价于class Son extends Father<Object,Object>{
}
具体类型
class Son2 extends Father<Integer, String> {
}
class Son2<A, B> extends Father<Integer, String> {
}
子类保留父类的泛型:泛型子类
全部保留
class Son3<T1, T2> extends Father<T1, T2> {
}
class Son3<T1, T2, A, B> extends Father<T1, T2> {
}
部分保留
class Son4<T2> extends Father<Integer, T2> {
}
class Son4<T2, A, B> extends Father<Integer, T2> {
}
泛型方法
泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。换句话说,泛型方法所属的类是不是泛型类都没有关系。泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。
public static <E> List<E> copyFromArrayToList(E[] arr){
ArrayList<E> list = new ArrayList<>();
for(E e : arr){
list.add(e);
}
return list;
}
@Test
public void test4(){
Integer[] arr = new Integer[]{1,2,3,4};
//泛型方法在调用时,指明泛型参数的类型。
List<Integer> list = order.copyFromArrayToList(arr);
System.out.println(list);
}
}
泛型在继承方面的体现
如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G并不是G的子类型!两者是并列关系。
比如:String是Object的子类,但是List并不是List的子类。
补充:类A是类B的父类,A
是 B
的父类
通配符的使用
通配符:?
类A是类B的父类,G和G是没有关系的,二者共同的父类是:G<?>
public void print(List<?> list){
Iterator<?> iterator = list.iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
对于List<?>就不能向其内部添加数据,例外:可以添加null
因为?就代表不知道是什么,那么不知道什么就无法添加数据。
允许读取数据,读取的数据类型为Object
Object o = list.get(0);
System.out.println(o);
有限制条件的通配符的使用
? extends A:
G<? extends A> 可以作为G<A>和G<B>的父类,其中B是A的子类 理解为G<?>小于等于A
? super A:
G<? super A> 可以作为G<A>和G<B>的父类,其中B是A的父类 理解为G<?>大于等于A
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> list3 = new ArrayList<Student>();
List<Person> list4 = new ArrayList<Person>();
List<Object> list5 = new ArrayList<Object>();
list1 = list3;
list1 = list4;
//报错 list1 = list5;
//报错 list2 = list3;
list2 = list4;
list2 = list5;
读取数据
//读取数据:
list1 = list3;
Person p = list1.get(0);
//编译不通过
//Student s = list1.get(0);
list2 = list4;
Object obj = list2.get(0);
编译不通过
// Person obj = list2.get(0);
写入数据
可以写入子类或相同类的数据
//写入数据:
//编译不通过
// list1.add(new Student());无法确定list是什么类,及extends的不能写入
//编译通过 及super的可以写入小于等于该类的
list2.add(new Person());
list2.add(new Student());
【Java】泛型的更多相关文章
- Java泛型的历史
为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...
- 浅析Java 泛型
泛型是JavaSE5引入的一个新概念,但是这个概念在编程语言中却是很普遍的一个概念.下面,根据以下内容,我们总结下在Java中使用泛型. 泛型使用的意义 什么是泛型 泛型类 泛型方法 泛型接口 泛型擦 ...
- Java:泛型基础
泛型 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚很多! 解决这种限制的 ...
- java泛型基础
泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法. Ja ...
- 使用java泛型设计通用方法
泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 因此我们可以利用泛型和反射来设计一些通用方法. 现在有2张表, 一张user表和一张stu ...
- 关于Java泛型的使用
在目前我遇到的java项目中,泛型应用的最多的就属集合了.当要从数据库取出多个对象或者说是多条记录时,往往都要使用集合,那么为什么这么使用,或者使用时有什么要注意的地方,请关注以下内容. 感谢Wind ...
- 初识java泛型
1 协变数组类型(covariant array type) 数组的协变性: if A IS-A B then A[] IS-A B[] 也就是说,java中的数组兼容,一个类型的数组兼容他的子类类型 ...
- 【Java心得总结四】Java泛型下——万恶的擦除
一.万恶的擦除 我在自己总结的[Java心得总结三]Java泛型上——初识泛型这篇博文中提到了Java中对泛型擦除的问题,考虑下面代码: import java.util.*; public clas ...
- 【Java心得总结三】Java泛型上——初识泛型
一.函数参数与泛型比较 泛型(generics),从字面的意思理解就是泛化的类型,即参数化类型.泛型的作用是什么,这里与函数参数做一个比较: 无参数的函数: public int[] newIntAr ...
- 初识Java泛型以及桥接方法
泛型的由来 在编写程序时,可能会有这样的需求:容器类,比如java中常见的list等.为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型.此时可能会有Int ...
随机推荐
- 微前端框架 qiankun 技术分析
我们在single-spa 技术分析 基本实现了一个微前端框架需要具备的各种功能,但是又实现的不够彻底,遗留了很多问题需要解决.虽然官方提供了很多样例和最佳实践,但是总显得过于单薄,总给人一种&quo ...
- msfvenom生成payload命令
msfvenom生成payload命令 windows: msfvenom -a x86 --platform Windows -p windows/meterpreter/reverse_tcp L ...
- AT4811 [ABC160D] Line++ 题解
Content 给定一个 \(n\) 个点.\(n\) 条边的无向图.对于所有的 \(1\leqslant i<n\),在点 \(i,i+1\) 之间连一条无向边.另外在给定两个点 \(x,y\ ...
- CF31A Worms Evolution 题解
Content 有一个长度为 \(n\) 的数组 \(a_1,a_2,a_3,...,a_n\),试找出一个三元组 \((i,j,k)\),使得 \(a_i=a_j+a_k\). 数据范围:\(3\l ...
- 分布式NoSQL数据库MongoDB初体验-v5.0.5
概述 定义 MongoDB官网 https://www.mongodb.com/ 社区版最新版本5.0,其中5.2版本很快也要面世了 MongoDB GitHub源码 https://github.c ...
- Linux(centos7)安装ClickHouse
Clickhouse 仅支持Linux 且必须支持SSE4.2 指令集 grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 suppo ...
- 价格BigDecimal的加减乘除、小数四舍五入、比较
num2必须改用传入String类型 //加法 BigDecimal result1 = num1.add(num2); //减法 BigDecimal result2 = num1.subtract ...
- 【LeetCode】263. Ugly Number 解题报告(Java & Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 除去2,3,5因子 日期 [LeetCode] 题目 ...
- 【LeetCode】461. Hamming Distance 解题报告(java & python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 Java解法 方法一:异或 + 字符串分割 方法二: ...
- 【转】最小生成树——Kruskal算法
[转]最小生成树--Kruskal算法 标签(空格分隔): 算法 本文是转载,原文在最小生成树-Prim算法和Kruskal算法,因为复试的时候只用到Kruskal算法即可,故这里不再涉及Prim算法 ...