Java通俗易懂讲解泛型

目录
  • 1.什么是泛型
  • 2.引出泛型
  • 3.泛型类的语法
  • 4.裸类型
  • 5.泛型如何编译的
    • 5.1 擦除机制
    • 5.2.泛型数组为什么不能实例化
  • 6.泛型的上界
  • 7.通配符
    • 7.1.通配符能用来干嘛
    • 7.2.通配符的上界(读数据)
    • 7.3.通配符的下界(写数据)

1.什么是泛型

泛型是在JDK1.5引入的新的语法,通俗讲,泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数化。

看到标红的这句话,有些兄弟可能会有疑惑,我们以前传参,传得是一个整形数据,传得是一个引用,我从来没传过类型嘛,类型难道还能作为参数传递???对,没错,接下来,我们就来看一下类型作为参数传递的实现方式

2.引出泛型

我们以前学过继承和多态,我们知道所有类的父类默认是Object类,我们现在目标是:数组中可以存放任何类型的数据,这时候我们就可以new一个Object类型的数组,,,

class MyArray {
    public Object[] array = new Object[10];
    public Object getPos(int pos) {
        return array[pos];
    }
    public void setPos(int pos, Object value) {
        array[pos] = value;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        MyArray myArray = new MyArray();
        myArray.setPos(0,1);
        myArray.setPos(1,"hello");
    }
}

当我们写出这样一个代码的时候,我们发现数组中什么元素都能放了,可以放整形数据,可以放字符串,还可以放小数,这里面能放的东西太多了,你能知道某个下标的元素是什么样的类型吗??当我们取元素的时候,会发现你的代码编译都不能通过,,,

为什么会出现这样的情况呢,我相信大部分兄弟们都知道,我们观察getPos的返回值是Object,也就意味着我们拿出来的可能是任意元素,但编译器知道吗???它只知道返回的是一个Object:这就很明显了,父类给子类,,这不纯纯的向下转型吗,向下转型就必须要强转类型,否则你的代码就不可能通过。

那么问题又来了,,我这里只是放了两个元素,肉眼还能看的过来,但是这里面的类型时刻在发生改变,就算你知道类型,你每次都需要强转吗,我是动态的啊,我代码是写死的啊,所以这个地方如果用Object去做的话,会显得格外麻烦,而且局限性非常的大

我们现在的困境有两个:

1.任何类型都可以放,不好控制,,,

2.每次取元素的时候,都得进行强制类型转换,,,

这时候我们得搞一手希望工程,我们的希望是:

1.我们能不能自己指定类型

2.我们能不能,不再进行类型转换呀,能不能把这一步省略呀,兄弟!!!

为了解决这一问题,我们java就引入了这个东西----》泛型

那到底怎么指定类型呢,来看代码:

class MyArray <T>{
    //public Object[] array = new Object[10];
    public T[] array = (T[]) new Object[10];//这样写也不好,待会说为什么??
    public T getPos(int pos) {
        return array[pos];
    }
    public void setPos(int pos, T value) {
        array[pos] = value;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        //我指定放整形
        MyArray<Integer> myArray = new MyArray<>();
        //后面的尖括号里的类型可以省略,在实例化对象的时候根据前面可以做出判断
        //MyArray<Integer> myArray = new MyArray<Integer>();
        myArray.setPos(0,1);
        myArray.setPos(1,2);
        Integer ret = myArray.getPos(1);
        System.out.println(ret);
        //我指定放字符串类型
        MyArray<String> myArray2 = new MyArray<>();
        myArray2.setPos(0,"abc");
        myArray2.setPos(1,"bit");
        String ret2 = myArray2.getPos(0);
        System.out.println(ret2);
    }
}

这个代码有几个注意事项:

1.尖括号<>里面只能放引用类型;

2.<T>是一个占位符,代表当前类是一个泛型类;

3.MyArray<Integer> array = new MyArray<>();后面的尖括号可以省略Integer不写,实例化对象的 时候编译器根据前面能做出判断。

看完上面的代码,我相信兄弟们已经明白是怎么一回事了吧

我们刚刚的希望工程也已经实现了

1.<Integer>,指定当前类中,使用的类型是Integer类型

2.泛型帮我在编译期间做了2件事情(目前为止的优点):

  • 存放元素的时候,进行类型的检查
  • 取元素的时候,帮我进行类型的转换

3.泛型类的语法

有了刚刚知识的铺垫,这一块咱就形式化一下啦,,当然,语法还是很重要滴!!

语法:

泛型类<类型实参> 变量名; // 定义一个泛型类引用 
new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象

栗子:

MyArray<Integer> list = new MyArray<Integer>();

4.裸类型

说明:

兄弟们,咱学了新东西,这旧东西,咱也得了解一下是不咯,,万一以后跟别人聊到了,自己好像从来没听过就尴尬了,,

裸类型是一个泛型类但没有带着类型实参,例如 MyArrayList 就是一个裸类型

MyArray list = new MyArray();

注意: 我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制

5.泛型如何编译的

5.1 擦除机制

我用的是Powershell窗口查看的字节码文件,当然用idea的兄弟们也可以去下载一个展示字节码的插件,,接下来我们看看泛型到底是怎么编译的,,javap -c查看字节码

我们发现在编译期间,所有的T都被擦除为了Object,那既然所有的T都变成了Object,那我们为什要指定类型呢?注意这里不是编译的时候替换,指定类型只是为了在编译的时候帮我们进行类型的检查和转换,并不是替换!!!最终字节码编译完成的时候,所有的T变成了Object,而这就是我们Java当中泛型所谓的擦除机制!!!

提问:那既然T在编译的时候被擦除为了Object,那为啥 T[] array = new T[] 会报错呢?

5.2会给你答案

(0)

相关推荐

  • java简明例举讲解泛型

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

  • 一起来学习Java的泛型

    目录 泛型: 泛型父类和子类: 泛型接口: 泛型方法: 通配符: 举例说明: 总结 泛型: 什么是泛型? 泛型是在Java SE 1.5引入的的新特性,本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法. 简而言之:<>泛型就是用来约束类.方法.属性上的数据类型,比如 List<Integer> list = new ArrayList<Integer>();List<Inte

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

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

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

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

  • 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.泛型概念 2.泛型的使用 2.1泛型类语法 2.2泛型方法语法 2.3泛型接口语法 2.4泛型在main方法中的使用 3.擦除机制 4.泛型的上界 5.通配符 5.1通配符的上界 5.2通配符的下界 6.包装类 6.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通俗易懂讲解泛型

    目录 1.什么是泛型 2.引出泛型 3.泛型类的语法 4.裸类型 5.泛型如何编译的 5.1 擦除机制 5.2.泛型数组为什么不能实例化 6.泛型的上界 7.通配符 7.1.通配符能用来干嘛 7.2.通配符的上界(读数据) 7.3.通配符的下界(写数据) 1.什么是泛型 泛型是在JDK1.5引入的新的语法,通俗讲,泛型:就是适用于许多许多类型.从代码上讲,就是对类型实现了参数化. 看到标红的这句话,有些兄弟可能会有疑惑,我们以前传参,传得是一个整形数据,传得是一个引用,我从来没传过类型嘛,类型难

  • 通俗易懂讲解C语言与Java中二叉树的三种非递归遍历方式

    详解二叉树的三种非递归遍历方式(附C.java源码) 前言 二叉树的递归遍历方式很简单,三种递归遍历方式的区别,只是printf放的位置不一样而已,这里就不多讲了.把前序遍历代码贴在这里: //结点 struct Node { int val; struct Node* left, * right; }; //前序遍历 void pre(Node* root) { if (root == null) return; printf("%d ",root->val); pre(roo

  • Java 中利用泛型和反射机制抽象DAO的实例

    Java 中利用泛型和反射机制抽象DAO的实例 一般的DAO都有CRUD操作,在每个实体DAO接口中重复定义这些方法,不如提供一个通用的DAO接口,具体的实体DAO可以扩展这个通用DAO以提供特殊的操作,从而将DAO抽象到另一层次,令代码质量有很好的提升 1.通用接口 import java.io.Serializable; import java.util.List; public interface BaseDao<T> { T get(Serializable id); List<

  • 初探Java中的泛型

    泛型是一个很有意思也很重要的概念,本篇将简单介绍Java中的泛型特性,主要从以下角度讲解: 1.什么是泛型. 2.如何使用泛型. 3.泛型的好处. 1.什么是泛型? 泛型,字面意思便是参数化类型,平时所面对的类型一般都是具体的类型,如果String,Integer,Double,而泛型则是把所操作的数据类型当作一个参数.如,ArrayList<String>(),通过传入不同的类型来指定容器中存储的类型,而不用为不同的类型创建不同的类,这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类

  • 一文带你搞懂Java中的泛型和通配符

    目录 概述 泛型介绍和使用 泛型类 泛型方法 类型变量的限定 通配符使用 无边界通配符 通配符上界 通配符下界 概述 泛型机制在项目中一直都在使用,比如在集合中ArrayList<String, String>, Map<String,String>等,不仅如此,很多源码中都用到了泛型机制,所以深入学习了解泛型相关机制对于源码阅读以及自己代码编写有很大的帮助.但是里面很多的机制和特性一直没有明白,特别是通配符这块,对于通配符上界.下界每次用每次百度,经常忘记,这次我就做一个总结,加

  • 深入分析JAVA 反射和泛型

    从 JDK5 以后,Java 的 Class 类增加了泛型功能,从而允许使用泛型来限制 Class 类,例如,String.class 的类型实际上是 Class<String>.如果 Class 对应的类暂时未知,则使用 Class<?>.通过在反射中使用泛型,可以避兔使用反射生成的对象需要强制类型转换. 泛型和 Class 类 使用 Class<T> 泛型可以避免强制类型转换.例如,下面提供一个简单的对象工厂,该对象工厂可以根据指定类来提供该类的实例. public

  • Java通俗易懂系列设计模式之模板模式

    实际开发中常常会遇到,代码骨架类似甚至相同,只是具体的实现不一样的场景.例如:流程都有开启.编辑.驳回.结束.每个流程都包含这几个步骤,不同的是不同的流程实例它们的内容不一样.共享单车都是先开锁.骑行.上锁.付款.这些大的步骤固定,不同的是每个实例的具体实现细节不一样.这些类似的业务我们都可以使用模板模式实现.为什么要使用模板模式以及如何使用呢? 介绍 定义:在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板.它的子类可以按需要重写方法实现,但调用将以

随机推荐