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

目录
  • 1、什么是泛型
  • 2、泛型的语法
  • 3、泛型的上界
  • 4、通配符
    • (1)通配符的上界
    • (2)通配符的下界
  • 5、包装类

1、什么是泛型

泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。

先看以下的例子:

我们以前学过的数组,只能存放指定类型的元素。如:int[] array=new int[10];String[] array=new String[10];而Object类是所有类的父类,那么我们是否可以创建Obj数组呢?

class Myarray{
    public Object[] array=new Object[10];
    public void setVal(int pos,Object val){
        this.array[pos]=val;
    }
    public Object getPos(int pos){
        return this.array[pos];
    }
}
public class TestDemo{
    public static void main(String[] args) {
        Myarray myarray=new Myarray();
        myarray.setVal(1,0);
        myarray.setVal(2,"shduie");//字符串也可以存放
        String ret=(String)myarray.getPos(2);//虽然我们知道它是字符串类型,但是还是要强制类型转换
        System.out.println(ret);
    }
}

以上代码实现后,我们发现:

  • 任何类型的数据都能存放
  • 2号下标本来就是字符串,但是必须进行强制类型转换

以此引出泛型,泛型的目的就是:指定当前的容器要持有什么类型的对象,让编译器自己去检查。

2、泛型的语法

class 泛型类名称< 类型形参列表>{

//这里可以使用类型参数

}

泛型的使用:

泛型类<类型实参> 变量名=new 泛型类<类型实参>(构造方法实参)

MyArray  list=new MyArray<>();

【注】

  • 类型后的<>代表占位符,表示当前类是一个泛型类
  • 在实例化泛型时,<>中不能是简单的类型,需要是包装类
  • <>不参与泛型的类型组成
  • 不能new泛型类型的数组
  • 使用泛型不需要进行强制类型转换

一个简单的泛型:

//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Test<T>{
    //key这个成员变量的类型为T,T的类型由外部指定
   private T key;

    public Test(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
        this.key = key;
    }

    public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
        return key;
    }
}

擦除机制:编译时会将<>中的类型擦除掉,所以<>中的东西不参与类型的组成。会将T擦除为Object。

为什么不能实例化泛型类型的数组?

数组和泛型之间的一个重要区别是它们如何强制执行类型检查。数组在运行时存储和检查类型信息,而泛型是在编译时检查类型错误。

返回的Object数组里面,可能存放着任何类型的数据,如string,通过int类型的数组来接收,编译器认为是不安全的。

3、泛型的上界

语法:

class 泛型类名称<T extends  类型边界>{

}

例:

public class MyArray{} //E只能是Number或Number的子类

public class MyArray<E extends Comparable<E>>{}

//E一定实现了Comparable接口的类

【注】没有指定边界的E,可以看作 E extends Object

4、通配符

? 用于在泛型的使用,即为通配符。通配符用来解决反泛型无法协变的问题。

如下两段代码:

代码一:
public static<T> void printList1(ArrayList<T> list){
   for(T x:list){
      System.out.println(x);
   }
}

代码二:
public static<T> void printList2(ArrayList<?> list){
   for(Object x:list){
      System.out.println(x);
   }
}

代码2中使用了通配符,和代码1相比,此时传入代码1的具体是什么数据类型,我们是不清楚的。

(1)通配符的上界

语法:

<? extends 上界>

<? extends Number>//可以传入的实参类型为Number或Number的子类

例:对于以下关系,我们需要写一个方法来打印存储了Animal或者Animal子类的list。

Animal
Cat extends Animal
Dog extends Animal

代码一:

public static <t extends Animal> void print1(List<T> list>{
    for(T animal:list){
        System.out.println(animal);//调用了T的toString
    }
}

此时T类型是Animal的子类或自己。

代码二:通过通配符实现

public static void print2(List<? extends Animal> list){
    for(Animal animal:list){
       Syatem.out.println(animal);//调用了子类的toString方法
    }
}

两种代码的区别:

  • 对于泛型实现的方法来说,<T extends Animal>对T进行了限制,只能是Animal的子类。传入Cat,就是Cat。
  • 对于通配符实现的方法来说,相当于对Animal进行了规定,允许传入Animal的子类。具体哪个子类,此时并不清楚。如:传入Cat,实际上声明的类型是Animal,使用多态才能调用Cat的toString方法

通配符上界→父子类关系:

//需要使用通配符来确定父子类型

MyArrayList<? extends Number>是MyArrayList<Integer>或者MyArrayList<Double>的父类

MyArrayList<?>是MyArrayList<? extends Number>的父类

 ArrayList<Integer> arrayList1 = new ArrayList<>();
 ArrayList<Double> arrayList2 = new ArrayList<>();
 List<? extends Number> list = arrayList1;
 //list.add(1,1);//报错,此时list的引用的子类对象有很多,再添加的时候,任何子类型都可以,为了安全,java不让这样进行添加操作。
 Number a = list.get(0);//可以通过
 Integer i = list.get(0);//编译错误,只能确定是Number子类

【注】

  • 不能对其进行添加,list中存储的可能是Number也可能是Number的子类,无法确定类型。
  • 通配符上界适合读取,不适合写入。

(2)通配符的下界

语法:

<? super 下界>

<? super Integer>//可以传入的参数类型是Integer或者Integer的父类

通配符下界的父子类关系:

MyArrayList<? super Integer>是MyArrayList<Intrger>的父类类型

MyArrayList<?>是MyArrayList<? super Integer>的父类

通配符下界适合写入元素,不适合读取。

5、包装类

在Java中,由于基本类型不是继承自Object,为了在泛型中可以支持基本类型,每个基本类型都对应了一个包装类。除了Integer和Character,其余基本类型的包装类都是首字母大写。

拆箱和装箱:

int i=10;

//装箱操作,新建一个Integer类型对象,将i的值放入对象的某个属性中
Integer ii=i;  //自动装箱
//Integer ii=Integer.valueOf(i);
Integer ij= new Integer(i);//显示装箱

//拆箱操作,将Integer对象中的值取出,放到一个基本数据类型中
int j=ii.intValue();//显示的拆箱
int jj=ii;//隐式的拆箱

到此这篇关于Java 深入浅出讲解泛型与包装类的文章就介绍到这了,更多相关Java 泛型 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java 泛型考古 泛型擦除 包装类详细解析

    目录 一. 什么是泛型 二. 为什么要有泛型 ? 示例 三.泛型考古 四.泛型擦除 五.包装类 六.装箱拆箱 一. 什么是泛型 泛型(generic type)其本质是将类型参数化,也就是说所操作的数据类型被指定为一个参数这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法. 二. 为什么要有泛型 ? 之前写过MyArrayList顺序表,这个类当时自己在实现的时候只能用一种类型来表示,也就是用的时候自己实现的MyArrayList只能应用于一种类型,要想应用于其他类型

  • Java集合框架入门之泛型和包装类

    目录 1. 预备知识-泛型(Generic) 1.1 泛型的引入 1.2 泛型的分类 1.3 泛型类的定义 1.4 泛型编译的机制 2. 预备知识-包装类(Wrapper Class) 2.1 基本数据类型和包装类的对应关系 2.2 包装类介绍 2.3 装箱(boxing)和拆箱(unboxing) 2.4 自动装箱(autoboxing)和自动拆箱(autounboxing) 2.5 包装类面试题 前言: 本章主要是为了后面学习集合框架所做的知识补充.补充了泛型以及包装类两个知识,但是该章泛型

  • Java中关于泛型、包装类及ArrayList的详细教程

    目录 一.泛型 1.1 泛型类的定义 1.2 泛型类的使用 1.3 泛型总结 二.包装类 2.1基本数据类型和包装类直接的对应关系 2.2 包装类的使用,装箱(boxing)和拆箱(unboxing) 2.3 自动装箱(autoboxing)和自动拆箱(autounboxing) 三.List 的使用 3.1 ArrayList简介 3.3 ArrayList的遍历 3.4 ArrayList的常见操作 3.4.1 删除 index 位置元素(remove) 3.4.1尾插(add) 3.4.2

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

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

  • Java深入浅出讲解String类常见方法

    目录 1.定义字符串 2.字符串的存储 3.String中常用的方法 3.1字符串的比较 3.2查找字符串 3.3转换字符串 4.StringBuilder和StringBuffer 5.常量池 1.定义字符串 字符串常见的构造方式如下: String s1 = "with"; String s2 = new String("with"); char[] array = {'w','i','t','h'}; String s3 = new String(array)

  • Java 深入浅出讲解代理模式

    目录 1.动态代理模式 2.JDK动态代理 3.JDK动态代理代码演示 1.动态代理模式 动态代理的特点: 当代理对象的时候,不需要实现接口 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型) 动态代理的别称:JDK代理.接口代理 2.JDK动态代理 类图: Java动态代理类位于java.lang.reflect包下 一般主要涉及到以下两个类: 1.Interface InvocationHandler : 该接口中仅定义了一

  • Java深入浅出讲解多线程的概念到使用

    目录 1.线程的几个相关概念 2.线程的状态与生命周期 3.线程的优先级与调度 4.Java中多线程的创建 4.1继承Thread类创建线程 4.2实现Runnable接口创建线程 5.多线程的同步控制 6.线程之间的通信 下面开始学习Java多线程吧! 写在前面:Java系统在语言层次上对多线程直接提供支持,多线程的主要目的是将一个程序中的各个程序段并发化,在在通常情况下,Java程序各部分是按顺序一次执行的,由于某种原因,需要将这些按顺序执行的程序段转化为并发执行,每个程序段在逻辑上是相互完

  • Java通俗易懂讲解泛型

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

  • Java详细分析讲解泛型

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

  • 深入浅出讲解Java中的枚举类

    目录 一.枚举类的使用 二.如何定义枚举类 背景:类的对象只有有限个,确定的.举例如下: > 星期: Monday (星期一).-.. Sunday (星期天) > 性别: Man (男). Woman (女) > 季节: Spring (春节).--.. Winter (冬天) > 支付方式: Cash (现金). WeChatPay (微信). Alipay (支付宝) BankCard (银 行卡). CreditCard (信用卡) > 就职状态: Busy . Fr

  • 深入浅出讲解Java集合之Collection接口

    目录 一.集合框架的概述 二.集合框架(Java集合可分为Collection 和 Map 两种体系) 三.Collection接口中的方法的使用 四.集合元素的遍历操作 A. 使用(迭代器)Iterator接口 B. jdk5.0新增foreach循环,用于遍历集合.数组 五.Collection子接口之一:List接口 List接口方法 ArrayList的源码分析: JDK 7情况下: JDK 8中ArrayList的变化: LinkedList的源码分析: Vector的源码分析: 六.

随机推荐