深入理解java泛型详解,java泛型写法

  深入理解java泛型详解,java泛型写法

  00-10101、什么是泛型2、泛型的语法3、泛型的上界4、通配符(1)通配符的上界(2)通配符的下界5、包装器类

  

目录

泛型的本质是参数化类型(不需要创建新的类型,由形参具体限制的类型由泛型指定的不同类型控制)。

 

  先看下面这个例子:

  我们之前学过的数组只能存储指定类型的元素。如: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 get pos(int pos){ return this . array[pos];} } public class test demo { public static void main(String[]args){ Myarray Myarray=new Myarray();myarray.setVal(1,0);myarray.setVal(2, shduie );//String也可以保存String ret=(String)myarray . get pos(2);//虽然知道是字符串类型,但还是要强制类型转换system . out . println(ret);}}上面的代码实现后,我们发现:

  任何类型的数据都可以持有2号下标,2号下标本来是一个字符串,但是必须进行强制转换才能导致泛型。泛型的目的是指定当前容器应该保存什么类型的对象,并让编译器自己检查。

  00-1010类通用类名类型参数列表{

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

  }

  泛型的使用:

  泛型类类型参数变量名=新的泛型类类型参数(构造函数参数)

  MyArray list=new MyArray();

  [注意]

  类型后的代表占位符指示当前类是泛型类。在实例化泛型类时,不能是简单类型,但需要是不参与泛型类的类型合成的包装类。它不能是新泛型类型的数组。使用泛型时,不需要强制类型转换。一个简单的泛型类:

  //这里t可以写成任意标识符。常用参数如t、e、k、v等。通常用于表示泛型。//在实例化泛型类时,必须指定t的具体类型,公共类TestT{ //key。这个成员变量的类型是T,T的类型外部指定为私有T keytest(T key){//泛型构造方法的参数key的类型也是T,T的类型是外部指定的this.key=key} public T getKey(){ //泛型方法getKey的返回值类型为T,外部指定T的类型为return key}}擦除机制:编译时会擦除中的类型,所以中的东西不会参与类型的合成。擦除t到对象。

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

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

  返回的对象数组可以包含任何类型的数据,如字符串,它由int类型的数组接收,这被编译器认为是不安全的。

  00-1010语法:

  泛型类名扩展了类型边界{

  }

  示例:

  Classmyarray {}//e只能是数字或数字的子类

  公共类MyArrayE扩展了ComparableE { }

  //E必须实现可比接口的类

  【注】没有指定边界的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。

 

  

AnimalCat extends AnimalDog 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 泛型 内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: