Java详细分析讲解泛型

目录
  • 1.泛型概念
  • 2.泛型的使用
    • 2.1泛型类语法
    • 2.2泛型方法语法
    • 2.3泛型接口语法
    • 2.4泛型在main方法中的使用
  • 3.擦除机制
  • 4.泛型的上界
  • 5.通配符
    • 5.1通配符的上界
    • 5.2通配符的下界
  • 6.包装类
    • 6.1装箱和拆箱

1.泛型概念

泛型就是将类型参数化

所谓类型参数化就是将类型定义成参数的形式,然后在使用此类型的时候的时候再传入具体的类型

到这我们可以看出来:泛型在定义的时候是不知道具体类型的,需要在使用的时候传入具体的类型,泛型可以用在类、接口和方法中,这样做的好处是一个泛型可以适用多种情况

2.泛型的使用

2.1泛型类语法

public class 类名<T> {......}

<T>表示这是一个泛型类,T是type的首字母大写,除此之外的名称还有:

E:element

K:key

V:vlaue

N:number

<>中可以有多个类型参数,中间使用逗号隔开

2.2泛型方法语法

public<泛型类型> 返回值 方法名(泛型类型 参数) {......}

2.3泛型接口语法

public interface 接口名<泛型类型> {......}

2.4泛型在main方法中的使用

下面写一个泛型类来引出后面的内容

class Fc<T>{
    private T a;
    public T get (T data) {
        this.a=data;
        return a;
    }
}

前面说过泛型是在使用的时候再传入具体的类型,所以在实例化上面泛型类的时候要指定类型。具体方式如下

类名<具体类型>变量名=new 类名<具体类型>();

注意:

  • 等号右边<>中可以不写具体类型,编译器可以根据上下文推导出此处的类型
  • <>中只能写入类,所以如果是基本数据类型,就需要写入其对应的包装类,包装类除int是Integer,char包装类是Character外,其余均是首字母大写
  • Java中不能创建泛型数组,至于原因要从Java中泛型的机制说起

3.擦除机制

Java实现泛型是依靠这个擦除机制的,这个机制目前来讲过于复杂,只说结果

Java编译器在编译的时候会去掉类型参数,而对于泛型类型来说,如果指定上界会用上界类型进行替换,没有指定上界则会以Object来进行替换

所以在编译的时候泛型类型都被替换成了Object,编译后的class文件是不包含任何泛型信息的,即泛型信息不会进入到运行时阶段

但Java的数组需要进行运行期类型检查,而由于类型擦除,造成数组运行期类型检查不能正常进行,破坏了Java数组运行期类型检查的机制

4.泛型的上界

所谓泛型的上界就是对传入的类型变量进行约束,指定哪些类型可以传入,哪些不行,语法如下:

class 类名<类型参数extends类型边界> {......}

还是以上面的泛型类为例,现在改成如下情况:

class Fc<E extends Number >{
    private E a;
    public E get (E data) {
        this.a=data;
        return a;
    }
}

那么此时Fc就只能传入Number或者其子类

5.通配符

通配符就是“?”在泛型中使用,它是用来解决泛型无法协变的问题,那什么是协变?

假设有两个类A和B,A继承B,那么泛型Fc<A>应该也是Fc<B>的子类,但泛型不支持这样的父子关系

基于上面的情况,所以需要使用通配符

直接写两个类,A继承B

class B {
}
class A extends B {
}

现在把<B>改成<?>

5.1通配符的上界

通配符也可以指定界限,语法和泛型的上界类似

<? extends 类型边界>

假设<? extends Number>,那么可以传入的是Number及其子类

但需要注意的是:通配符的上界只能用来读取数据,不能用来写入数据

因为我们只知道里面可以传入什么类型的数据,但具体是什么类型我们不知道,所以也就无法对数据进行修改,但是读取则可以直接用父类对象来进行接收读取出来的数据

5.2通配符的下界

下界使用的是super

<? super 类型边界>

<? super Integer>表示可以传入Integer或者其父类

通配符下界可以进行写入数据,但不能用来读取数据

原因也很简单,里面可以传的类都是Integer或者它的父类,写进去的数据可以进行转化,但读取数据用哪一个父类对象接收则不好确定了

6.包装类

由于Java中基本数据类型不是继承Object类,所以为了泛型能够支持基本数据类型,每一个基本数据类型都有各自的包装类

基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

6.1装箱和拆箱

装箱就是把基本数据类型改为对应的包装类类型,拆箱就是和装箱相反的操作

Java中提供了自动装箱和拆箱机制,但还是先来看下手动装箱和拆箱的操作

//手动装箱
int i=10;
Integer j=Integer.valueOf(i);  //第一种操作
Integer j=new Integer(i);      //第二种操作
//手动拆箱
int a=j.intValue();

自动装箱和拆箱的话代码就要少的多

int i=10;
Integer j=i;  //自动装箱
int a=j;      //自动拆箱

关于int的包装类有一个比较有趣的地方,装箱使用了valueOf方法,其源码如下:

可以看到传给方法的参数首先是和IntegerCache进行比较,如果参数的值是在某个范围中,那么返回的是数组里面的元素,否则返回新的对象

那我们来看看这个IntegerCache

也就是说-128<=i<=127的时候返回的是类中的数组的元素,那么就会有一个情况如下:

原因和上面所讲一样

泛型结束,后面数据结构的时间复杂度和空间复杂度这两个概念就不写了,下一篇直接到顺序表

到此这篇关于Java详细分析讲解泛型的文章就介绍到这了,更多相关Java泛型内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java的泛型你真的了解吗

    目录 泛型的概述和优势 自定义泛型类 自定义泛型方法 自定义泛型接口 泛型通配符.上下限 总结 泛型的概述和优势 泛型概述 泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查. 泛型的格式:<数据类型>; 注意:泛型只能支持引用数据类型. 集合体系的全部接口和实现类都是支持泛型的使用的. 泛型的好处: 统一数据类型. 把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来. 泛型可以在很多地方进行定义: 类后面 --> 泛

  • Java 深入浅出讲解泛型与包装类

    目录 1.什么是泛型 2.泛型的语法 3.泛型的上界 4.通配符 (1)通配符的上界 (2)通配符的下界 5.包装类 1.什么是泛型 泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型). 先看以下的例子: 我们以前学过的数组,只能存放指定类型的元素.如:int[] array=new int[10];String[] array=new String[10];而Object类是所有类的父类,那么我们是否可以创建Obj数组呢? class Mya

  • java简明例举讲解泛型

    目录 什么是泛型 泛型类与接口派生子类 泛型通配符 类型擦除 什么是泛型 早期的Object类型可以接收任意的对象类型,但是在实际的使用中, 会有类型转换的问题.也就存在这隐患,所以Java提供了泛型来解决这个安全问题 泛型,即“参数化类型”.一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传 递实参.就是说 , 我们可以将类型向参数一样传递过去 //一个泛型类 //T可以为任意字符,如A,a,B等都可以 public class Demo1<T> { private T num;

  • Java超详细分析泛型与通配符

    目录 1.泛型 1.1泛型的用法 1.1.1泛型的概念 1.1.2泛型类 1.1.3类型推导 1.2裸类型 1.3擦除机制 1.3.1关于泛型数组 1.3.2泛型的编译与擦除 1.4泛型的上界 1.4.1泛型的上界 1.4.2特殊的泛型上界 1.4.3泛型方法 1.4.4类型推导 2.通配符 2.1通配符的概念 2.2通配符的上界 2.3通配符的下界 题外话: 泛型与通配符是Java语法中比较难懂的两个语法,学习泛型和通配符的主要目的是能够看懂源码,实际使用的不多. 1.泛型 1.1泛型的用法

  • 浅谈Java中的桥接方法与泛型的逆变和协变

    目录 1. 泛型的协变 1.1 泛型协变的使用 1.2 泛型协变存在的问题 1.2.1 Java当中桥接方法的来由 1.2.2 为什么泛型协变时,不允许添加元素呢 1.2.3 从Java字节码的角度去看桥接方法 2. 泛型逆变 2.1 泛型逆变的使用 2.2 泛型逆变会有什么问题 3.协变与逆变-PECS原则 泛型的协变和逆变是什么?对应于Java当中,协变对应的就是<? extends XXX>,而逆变对应的就是<? super XXX>. 1. 泛型的协变 1.1 泛型协变的使

  • Java 泛型超详细入门讲解

    目录 1.什么是泛型? 2.泛型是怎么编译的 泛型的编译机制:擦除机制 1.什么是泛型? 泛型其实就是将类型作为参数传递,泛型允许程序员在编写代码时使用一些以后才指定的类型 ,在实例化该类时将想要的类型作为参数传递,来指明这些类型. 为什么要引入泛型? 例如:自己实现一个顺序表 public class MyArrayList { public int[] elem; public int usedSize; public MyArrayList() { this.elem = new int[

  • Java基础泛型详情

    目录 一.泛型 二.泛型类 三.泛型方法 四.泛型接口 五.类型通配符<?> 六.可变参数 一.泛型 概述: 泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型 本质上是参数化类型,也就是说所操作的数据类型被指定为一个参数 参数化类型:就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的参数 这种参数类型可以用在类.方法和接口中,分别被称为泛型类.泛型方法.泛型接口 定义格式: 1.<类型>:指定一种类型的格式,这里的类型可以

  • Java十分钟精通泛型的使用与原理

    什么是泛型? 简而言之:<>泛型就是用来约束类.方法.属性上的数据类型,比如 List<Integer> list = new ArrayList<Integer>(); new ArrayList这个集合的元素只能添加Integer类型. 为什么需要泛型? Java推出泛型之前,程序员可以构建一个Object类型的集合,该集合能够存储任何的数据类型,而在使用该 集合的时候,需要程序员明确知道每个元素的具体的类型并向下转型,否则容易引发ClassCastExceptio

  • Java详细分析讲解泛型

    目录 1.泛型概念 2.泛型的使用 2.1泛型类语法 2.2泛型方法语法 2.3泛型接口语法 2.4泛型在main方法中的使用 3.擦除机制 4.泛型的上界 5.通配符 5.1通配符的上界 5.2通配符的下界 6.包装类 6.1装箱和拆箱 1.泛型概念 泛型就是将类型参数化 所谓类型参数化就是将类型定义成参数的形式,然后在使用此类型的时候的时候再传入具体的类型 到这我们可以看出来:泛型在定义的时候是不知道具体类型的,需要在使用的时候传入具体的类型,泛型可以用在类.接口和方法中,这样做的好处是一个

  • Java详细分析讲解自动装箱自动拆箱与Integer缓存的使用

    目录 1. 前言 2. 包装类 3. 自动装箱与自动拆箱 4. Interger缓存 5. 回答题目 1. 前言 自动装箱和自动拆箱是什么?Integer缓存是什么?它们之间有什么关系? 先来看一道题目. Integer a = new Integer(1); Integer b = new Integer(1); System.out.println(a==b); Integer c = 1; Integer d = 1; System.out.println(c==d); Integer e

  • Java详细分析讲解HashMap

    目录 1.HashMap数据结构 2.HashMap特点 3.HashMap中put方法流程 java集合容器类分为Collection和Map两大类,Collection类的子接口有Set.List.Queue,Map类子接口有SortedMap.如ArrayList.HashMap的继承实现关系分别如下 1.HashMap数据结构 在jdk1.8中,底层数据结构是“数组+链表+红黑树”.HashMap其实底层实现还是数组,只是数组的每一项都是一条链,如下 当链表过长时,会严重影响HashMa

  • Java 栈与队列超详细分析讲解

    目录 一.栈(Stack) 1.什么是栈? 2.栈的常见方法 3.自己实现一个栈(底层用一个数组实现) 二.队列(Queue) 1.什么是队列? 2.队列的常见方法 3.队列的实现(单链表实现) 4.循环队列 一.栈(Stack) 1.什么是栈? 栈其实就是一种数据结构 - 先进后出(先入栈的数据后出来,最先入栈的数据会被压入栈底) 什么是java虚拟机栈? java虚拟机栈只是JVM当中的一块内存,该内存一般用来存放 例如:局部变量当调用函数时,我们会为函数开辟一块内存,叫做 栈帧,在 jav

  • Java超详细分析讲解哈希表

    目录 哈希表概念 哈希函数的构造 平均数取中法 折叠法 保留余数法 哈希冲突问题以及解决方法 开放地址法 再哈希函数法 公共溢出区法 链式地址法 哈希表的填充因子 代码实现 哈希函数 添加数据 删除数据 判断哈希表是否为空 遍历哈希表 获得哈希表已存键值对个数 哈希表概念 散列表,又称为哈希表(Hash table),采用散列技术将记录存储在一块连续的存储空间中. 在散列表中,我们通过某个函数f,使得存储位置 = f(关键字),这样我们可以不需要比较关键字就可获得需要的记录的存储位置. 散列技术

  • Java超详细分析讲解final关键字的用法

    目录 基本介绍 final细节01 final细节02 基本介绍 final 可以修饰类.属性.方法和局部变量. 在某些情况下,程序员可能有以下需求,就会使用到final: Base Sub 类 1)当不希望类被继承时,可以用final修饰. 2)当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字 修饰.[案例演示:访问修饰符 final 返回类型方法名] 3)当不希望类的的某个属性的值被修改,可以用final修饰.[案例演示: public final dou

  • Java @GlobalLock注解详细分析讲解

    目录 GlobalLock的作用 全局锁 为什么要使用GlobalLock 工作原理 GlobalLock的作用 对于某条数据进行更新操作,如果全局事务正在进行,当某个本地事务需要更新该数据时,需要使用@GlobalLock确保其不会对全局事务正在操作的数据进行修改.防止的本地事务对全局事务的数据脏写.如果和select for update组合使用,还可以起到防止脏读的效果. 全局锁 首先我们知道,seata的AT模式是二段提交的,而且AT模式能够做到事务ACID四种特性中的A原子性和D持久性

  • C语言详细分析讲解内存管理malloc realloc free calloc函数的使用

    目录 C语言内存管理 一.动态空间申请 二.动态空间的扩容 三.释放内存 C语言内存管理 malloc && realloc && free && calloc c语言中为了进行动态内存管理,<stdlib.h>中提供了几个函数帮助进行内存管理. 我们知道,C语言中是没有C++中的容器或者说是python中list,set这些高级的数据结构的,我们一旦申请了一段内存空间以后这一段空间就归你了,比如我们举个例子,我们申请一个数组 int nums[

  • C语言详细分析讲解struct与union使用方法

    目录 一.struct 的小秘密 二.结构体与柔性数组 三.C语言中的 union 四.小结 一.struct 的小秘密 C语言中的 struct 可以看作变量的集合 struct 的问题:空结构体占用多大内存?下面编写程序看一下吧: #include <stdio.h> struct TS { }; int main() { struct TS t1; struct TS t2; printf("sizeof(struct TS) = %d\n", sizeof(stru

  • C++详细分析讲解函数参数的扩展

    目录 一.函数参数的默认值 二.函数占位参数 三.小结 一.函数参数的默认值 C++ 中可以在函数声明时为参数提供一个默认值 当函数调用时没有提供参数的值,则使用默认值 参数的默认值必须在函数声明中指定 下面看一段代码: #include <stdio.h> int mul(int x = 0); int main(int argc, char *argv[]) { printf("%d\n", mul()); printf("%d\n", mul(-1

随机推荐