泛型

为什么要有泛型

集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。Collection,List,ArrayList 这个就是类型参数,即泛型。

  1. 解决元素存储的安全性问题
  2. 解决获取数据元素时,需要类型强制转换的问题

没有泛型时:


有泛型时:

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>

使用泛型后,该接口内涉及泛型的方法的参数都会变成该类型

总结:

  1. 集合接口或集合类在jdk5.0时都修改为带泛型的结构。

  2. 实例化集合类时,可以指明具体的泛型类型

  3. 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。

  4. 比如:add(E e) —>实例化以后:add(Integer e)

  5. 注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换

  6. 如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。

  7. 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】泛型的更多相关文章

  1. Java泛型的历史

    为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...

  2. 浅析Java 泛型

    泛型是JavaSE5引入的一个新概念,但是这个概念在编程语言中却是很普遍的一个概念.下面,根据以下内容,我们总结下在Java中使用泛型. 泛型使用的意义 什么是泛型 泛型类 泛型方法 泛型接口 泛型擦 ...

  3. Java:泛型基础

    泛型 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚很多! 解决这种限制的 ...

  4. java泛型基础

    泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法.  Ja ...

  5. 使用java泛型设计通用方法

    泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 因此我们可以利用泛型和反射来设计一些通用方法. 现在有2张表, 一张user表和一张stu ...

  6. 关于Java泛型的使用

    在目前我遇到的java项目中,泛型应用的最多的就属集合了.当要从数据库取出多个对象或者说是多条记录时,往往都要使用集合,那么为什么这么使用,或者使用时有什么要注意的地方,请关注以下内容. 感谢Wind ...

  7. 初识java泛型

    1 协变数组类型(covariant array type) 数组的协变性: if A IS-A B then A[] IS-A B[] 也就是说,java中的数组兼容,一个类型的数组兼容他的子类类型 ...

  8. 【Java心得总结四】Java泛型下——万恶的擦除

    一.万恶的擦除 我在自己总结的[Java心得总结三]Java泛型上——初识泛型这篇博文中提到了Java中对泛型擦除的问题,考虑下面代码: import java.util.*; public clas ...

  9. 【Java心得总结三】Java泛型上——初识泛型

    一.函数参数与泛型比较 泛型(generics),从字面的意思理解就是泛化的类型,即参数化类型.泛型的作用是什么,这里与函数参数做一个比较: 无参数的函数: public int[] newIntAr ...

  10. 初识Java泛型以及桥接方法

    泛型的由来 在编写程序时,可能会有这样的需求:容器类,比如java中常见的list等.为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型.此时可能会有Int ...

随机推荐

  1. 修复 Edge 浏览器 1Password 插件 Ctrl+Shift+X 弹出快捷键失效

    解决方式 在 Edge 浏览器右上角 1Password插件图标上右键,选择设置: 在打开的 1Password 设置页面中,找到快捷键设置环节,默认使用快捷键打开后面为空,点击"在扩展也上 ...

  2. Windows10计算文件SHA1 SHA256 SHA384 SHA512 or MD5

    目录 Windows10计算文件SHA1 SHA256 SHA384 SHA512 or MD5? 1.计算SHA1 2.计算SHA256 3.计算SHA384 4.计算SHA512 5.计算MD5 ...

  3. AT3589 Similar Arrays 题解

    Content 给定一个长度为 \(n\) 的序列 \(a\).定义两个序列 \(x,y\) 是相似的,当且仅当 \(\forall i\in[1,n],|x_i-y_i|\leqslant 1\). ...

  4. HTTPS握手-混合加解密过程

    SSL协议通信过程 (1) 浏览器发送一个连接请求给服务器;服务器将自己的证书(包含服务器公钥S_PuKey).对称加密算法种类及其他相关信息返回客户端; (2) 客户端浏览器检查服务器传送到CA证书 ...

  5. Raft论文概述

    介绍 Raft是一种为了管理复制日志的一致性算法.为了提升可理解性,Raft 将一致性算法分解成了几个关键模块,例如领导人选举.日志复制和安全性.同时它通过实施一个更强的一致性来减少需要考虑的状态的数 ...

  6. JAVA火星坐标系、百度坐标系、84坐标系相互转换工具类

    /** * 坐标系转换工具类 */ public class PositionUtil { public static double pi = 3.1415926535897932384626; pu ...

  7. nim_duilib(3)之按钮

    introduction 更多控件用法,请参考 here 和 源码. 本文的代码基于这里 lets go xml文件添加代码 下面的xml文件内容,删除label控件的相关代码,增加了3个按钮. 其中 ...

  8. 【LeetCode】561. Array Partition I 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 排序 日期 题目地址:https://leetcod ...

  9. 【LeetCode】893. Groups of Special-Equivalent Strings 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  10. 一、golang以及vscode的安装和配置

    1.golang的下载安装 golang的官网最近好像整合了内容,统一到了一个地址:https://go.dev/ 首页直接点击download,下载自己对应的版本即可. 安装是傻瓜式的,一般默认安装 ...