java---泛型总结

一、了解泛型

泛型的基础说明——主要看两点:一点是指对象类型,对象引用要看是否能够继承,比如ArrayList与Vector引用的关系,二点是指对象内部元素的类型<E>一致关系。这两点是相对独立的。

1引ArrayList<E>来说明

  • 整个ArrayList<E>称为泛型类型
  • ArrayList<E>中的E称为变量类型或类型参数
  • 整个ArrayList<Integer>称为已参数化的类型
  • ArrayList称为原始类型
  • 泛型尖括号常常写在方法前面表示它是一个泛型方法。
  • 说例,ArrayList<String> cv;ArrayList定义的是cv类型,String定义cv子元素类型。
  • 泛型语法告诉JVM,参数化类型与原始类型之间存在转化,参数类型之间不存在转化。

2参数化类型与原始类型的互兼容性:

  • 引用相当于c++中的指针,其结构声明是为了数据操作语法安全考虑的
  • 参数化类型可以引用一个原始类型对象,虽然编译报告警告:

如,Collection <String> c=new Vector();

  • 原始类型可以引用以一个参数化类型的对象,虽然编译报告警告:

如,Collection c=new Vector<String>();

3参数化类型不考虑类型参数的继承关系:

 即 Vector <Streing> v =new Vector<Object>(); //不正确

Vector<Object> v= new Vector <String>();  //错误

4下面的代码不会报错!

   Vector  v1=new  Vector<String>();//正确

Vector<Object> v=v1;  //正确,计算机是代码是一行行的执行的,不能连着一起看。

5编译器不允许创建类型变量的数组时,数组的元素不能使用参数化的类型,即:

Vector <Integer> vectorList[] =new Vector<Integer>[10];是错误的,

Vector <Integer> vectorList[] =new Vector[10];正确啦,因为new Vector[10];是指初始化一个内存大小为10个Vector数组,new Vector<String>[10];则JVM不知道是不是创建大小为10Vector数组还是大小为10个String的数组,因为没设定这样指令,所以Jvm报警。

Collection  vectorList[] =new Vector<Integer>[10];

6普通方法、构造方法和静态方法中都可以使用泛型。

7也可以用类型变量表示异常,称为参数化的异常,可以用于方法的throws中,但是不能用于catch子句中。

Private static <T extends Exception> sayHello() throws T

{   try{   }cath (Exception e){

Throw(T)e;

}

}

8在泛型中可以同时有多个类型参数,在定义它们的尖括号中用逗号分,例如: public static <K,V>V getValue(K key){   return  map.get(key)  }

 

泛型是提供给Javac编码器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入(如3),编译器编译带类型说明的集合时会去掉“类型”信息,使程序运行效率不受影响,其效果就是对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合字段,再调用其add方法即可,如下:

 

 Collection1.getClass().getMethod(“add”,Object.class).invoke(Collection1,New added data)

注意:思考到——同一数组类型,不同对象,其均存储在同一堆栈,内存的利用率若是很高,则必然要内存管理机制有挪移算法及数组相同元素只需存在一个,这个就要求,javac能够为每一个数组类型对象准备一张存储说明表,当知道理论上的下标时,能够映射到其真正的下标。

 

在泛型中,public void printCollection(Collection<?>  collection)参数中的?是类型通配符,它的作用就是匹配任何参数化类型,但是该函数中不能使用collection对象调用跟参数类型有关的方法。比如add(E e),但是可以调用size(),average( int  i)等这样与参数化类型无关的函数。

 

1在函数public void printCollection(Collection <?>  cp)  

{

  cp.add(“String”) //有错,因为?是个通配符,它不确定,所以不能存储确定的类型的元素

cp.size()// 没错,因为函数size()括号里的类型与参数化类型无关

cp=new HashSet<Date>(); //正确,这是因为HashSet实现了Collection接口,所以子类对象能够赋给父类变量引用;而且?是一种通配符,因此可以匹配赋值。JVM却规定不能调用与参数化有关的函数。

}

 

2在函数public void printCollection(Collection <Object>  cp)  

{

   cp.add(“String”) //没有错,”String”字符串是String类型,之所以没有错,这里cp对象是Collection,但对象里的子元素是Object类型,即当添加数据时,实质就是Object变量引用其他类型的变量的过程,但是反过来就不对啦,因为Object是可变结构,已知类型引用时自身的固定的类型是无法更改的。

cp=new Collection<String>()// 错误,这是由于javac会匹配语法格式不对而报错。

}

使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用对象,不是用于存储,可以调用与参数化无关的方法,不能调用与参数化有关的方法。

当要调用与参数化有关的数据时,使用自定义泛型<T>的表达方式可以达到同一样的目地。

    同时,Object也是能够引用任意类型的。Object类型的数据代表着可变结构,该类型能够引用任意类型的数据。却也保留了源类型的信息,所以被Object引用后的数据能够按着原来的类型输出,但是,不能够强制输出与源类型不相干的类型的,如:

Object  obj =”1234”;

Int  var=(int)obj ; 是错误的。字串转换需用X.toString这样的形式

 

 

泛型中的?通配符的扩展

   1限定通配符的上边界:

  • 正确:Vector <? extends Number> x=new Vector<Integer>();——指示通配符?的匹配必须是Number的子类;下面的式子就出错了。
  • 错误:Vector <? extends Number> x=new Vector<String>();

   2限定通配符的下边界:

  • 正确:Vector <? super Integer> x=new Vector<Number>();
  • 错误:Vector <? super > x=new Vector<Integer>();

    3 除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符,例如,   Class.getAnnotation()方法的定义。并且可以使用&来指定多个边界,如    <V extends Serializable & cloneable> void method () { };

泛型中?通配符的对象赋值转化

   Collection<?> y;    Collection<String> x;   

y=x;  // 正确 :未知类型y引用已知类型x,就具有类型化啦。  x=y;  //错误,原因是y的类型是未知的,(jvm规定已知类型不能引用未知类型)所以不能被引用。

 

注意:Java语法规定,接口的对象不能初始化却能够互相引用赋值,如上式。但是x,y在没有初始化之前,是不能引用或者赋值给别的变量的。

l Map 接口提供三种collection 视图,即可以通过键集、值集或键-值映射关系集的形式取出或添加映射的内容。映射顺序 定义为迭代器在映射的 collection 视图上返回其元素的顺序,因为Map类实现了Iterable接口,即具有迭代的功能,这个迭代的方法实现将会在Map类中的getValue()或者getKey()中被调用。某些映射实现可明确保证其顺序,如 TreeMap 类;另一些映射实现则不保证顺序,如 HashMap 类。其中键-值映射关系集的关系存储在Map的内部类中,即Map.Entry<K,V>,可以通过方法entrySet()取出。

自定义泛型(通过传递的实例对象或者返回对象来确定类型)

  • 交换数组中的两个元素的位置的泛型方法语法定义如下:

Static <T> void swap( T[] a, int i, int j )

{
         E t=a[i];

a[i]=a[j];   //  T[]表示任意类型的数组

a[j]=t;

}

  • 用于放置泛型的类型参数的尖括号应出现在方法的其他所有修辞符之后和在方法的返回类型之前,也就是紧邻返回值之前。按照惯例,类型参数通常用单个大写字母表示。
  • 只有引用类型才能作为泛型方法的T,基本类型不能。swap(new int[3], 3, 5 );语句会报告编译错误。但是后面的<T>add(T x, T y )中用add(2,4),就自动装修。

这是因为编译器不会对new int[3]中的int自动拆箱和装箱了(),因为new int[3]你想要的有可能就是int数组呢?所以编译器不作为。装箱就是把基础类型封装成一个类。比如把int封装成Integer,这时你就不能把他当成一个数了,而是一个类了,对他的操作就需要用它的方法了。拆箱就是把类转换成基础类型。比如你算个加法什么的是不能用类的,就得把它转换成基本类型。

  • 除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符,例如:
  • 自定义类型在进行算术运算时,针对返回类型,jvm取类型最大公约数:

1    Object  x2=add( 3, “abc” );

2    public  static <T>  add( String x, T y )// 一般都是Object类型

{

Returen null;

}

注意:Java语言中的泛型基本上完全是在编译器中实现,用于编译器执行类型检查和类型推断,然后生成普通的非泛型的字节码,这种实现技术称为擦除(编译器使用泛型类型信息保证类型安全,顺利编译,然后在生成字节码之前将其擦除)。这是因为扩展虚拟机指令集来支持泛型被认为是无法接受的。

 

根据调用泛型方法时实际传递的参数类型或返回类型的类型来推断最后的类型,具有如下规则:

  • 直觉推断

Static  <E> void swap (E[] , int i, int j );

  • 多处用T,但是实际应用类型是同一类型的

Add(3,5)——static <T> add<T a,T b>

  • 多处用T,但是实际应用类型不是同一类型的,但是T最后要统一

Int x=(2,3.7f)——static <T> T add(T a,T b);//这里优先考虑返回类型

将变量X的类型改为float,对比eclipse报告的错误提示,接着再将变量X类型改为Number,则没有了错误:

  • 多处用T,但是实际应用类型不是同一类型的,且没有返回类型

Fill(new Integer[3] , 3.4f)——static <T> void fill<T[] a, T b>

这时无法参考返回类型,就得取实际应用类型的最大交集类型,上式的T的类型将看成Number。如果实际类型是其他引用类型,则看成Object。

  • 多处用T,但是应用类型又具有参数化类型

copy(new Integer[5], new String[5])——static <T> void copy(T[] a, T[] b);

Copy(new Vector <String>() , new Integer[5])——

static <T> void copy(Collection <T> a, T[] b);

这时参数类型的类型推断具有传递性,上面第一种情况推断实际参数类型为Object, 编译没有问题,而第二种情况则根据参数化的Vector实例将类型变量直接确定为String类型,编译将出现问题。

二、 类泛型的定义:

当我们要对任意类型数据进行操作时,我们就需要把方法类型定义为泛型,对于多种操作,有不同的泛型方法,却无法使它们保持统一T,因为有的方法不带参数类型,有的方法只带固定参数类型,它们却都要有T返回类型。因此就需要把该类定义成泛型。

  • 在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。
  • 不论是方法还是引用赋值,都必须有一个<E>的泛型类型说明。

即 public  static  void  update2( E obj) 错误

Public  static <T> void  update2( T obj) 正确。 这个就是泛型方法。

 

时间: 2024-11-04 10:23:07

java---泛型总结的相关文章

Java泛型中的PECS原则

今天在写代码的时候使用到了这样一个方法签名: public void foo(Map<String, String> map); 在写这个参数的时候正好在想一些关于泛型的东西,于是: public void foo(Map<? extends String, ? extends String> map); 这两种写法有什么区别呢?记得以前和同学讨论过这个问题,但后来没有记下来,渐渐又淡忘了.今天又去翻了好多资料,总算找到一些可以参考的,赶紧记在这里方便以后温故知新啦.好了,言归正传

Java泛型的协变

在上篇<Java泛型的基本使用>这篇文章中遗留下面问题,即将子类型也能加入到父类型的泛型中.要实现这样的功能必须借助于协变. 实验准备 如今在上篇文章展示的Decorator类型的基础上,添加一些代码,如代码清单1所看到的. 代码清单1 /** * * 描 述:Exp2使用br/> * 作 者:jiaan.gja<br/> * 历 史: (版本号) 作者 时间 凝视 <br/> * @param itemList */ public void doDecorate

2017.4.5 Java 泛型

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数. 假定我们有这样一个需求:写一个排序方法,能够对整形数组.字符串数组甚至其他任何类型的数组进行排序,该如何实现? 答案是可以使用 Java 泛型. 使用 Java 泛型的概念,我们可以写一个泛型方法来对一个对象数组排序.然后,调用该泛型方法来对整型数组.浮点数数组.字符串数组等进行排

关于Java泛型的使用

在目前我遇到的java项目中,泛型应用的最多的就属集合了.当要从数据库取出多个对象或者说是多条记录时,往往都要使用集合,那么为什么这么使用,或者使用时有什么要注意的地方,请关注以下内容. 感谢Windstep. 原文链接:http://www.cnblogs.com/lwbqqyumidi/p/3837629.html 原文标题:Java总结篇系列:Java泛型 (我的第一篇水文,233)

java 泛型 窜讲

一.为什么使用泛型      复用性:泛型的本质就是参数化类型,因而使用编写的泛型代码可以被许多不同类型的对象所复用.      安全性:在对类型Object引用的参数操作时,往往需要进行显式的强制类型转换.这种强制类型转换需要在运行时才能被发现是否转换异常,通过引入泛型能将在运行时才能检查类型转换,提前到编译时期就能检查. 二.自定义泛型 java中自定义泛型分为三种:泛型类.泛型接口.泛型方法. 下面使用一个案例演示泛型类.泛型方法,泛型接口类似,所以不再演示. // 自定义泛型类publi

1月21日 - (转)Java 泛型

java泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样. 可以在集合框架(Collection framework)中看到泛型的动机.例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象. 因为 M

Java泛型_上界extends_下界super

?Java泛型_上界extends_下界super ? 通配符类型 <? extends T> 表示类型的上界,表示参数化类型的可能是T或是T的子类 <? super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型(T)的超类型(父类型),直至Object 当使用 Upper Bound 通配符时 如下代码, /**  * 代码中通配符<?> 是 <? extends Object> 的简写  *  * @param list

C++泛型 &amp;&amp; Java泛型实现机制

C++泛型 C++泛型跟虚函数的运行时多态机制不同,泛型支持的静态多态,当类型信息可得的时候,利用编译期多态能够获得最大的效率和灵活性.当具体的类型信息不可得,就必须诉诸运行期多态了,即虚函数支持的动态多态. 对于C++泛型,每个实际类型都已被指明的泛型都会有独立的编码产生,也就是说list<int>和list<string>生成的是不同的代码,编译程序会在此时确保类型安全性.由于知道对象确切的类型,所以编译器进行代码生成的时候就不用运用RTTI,这使得泛型效率跟手动编码一样高.

java 泛型详解(普通泛型、 通配符、 泛型接口,泛型数组,泛型方法,泛型嵌套)

JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能-----Java的泛型. 1.Java泛型  其实Java的泛型就是创建一个用类型作为参数的类.就象我们写类的方法一样,方法是这样的method(String str1,String str2 ),方法中参数str1.str2的值是可变的.而泛型也是一样的,这样写class Java_Generics<K,V>,这里边的K和V就象方法中的参数str1和st

java泛型的讲解

java泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样. 可以在集合框架(Collection framework)中看到泛型的动机.例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象. 因为 M