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

有关术语

  • ArrayList中的E类型称为**类型变量**或**类型参数**
  • 整个ArrayList称为**参数化的类型**
  • ArrayList中的Integer称为**类型参数的实例**或**实际类型参数**
  • ArrayList念做**“ArrayList typeof Integer”**
  • ArrayList称作原始类型

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

  • 参数化泛型可以引用一个原始类型的参数,编译报告警告,例如:
   Collection<String> c = new Vector();
  • 原始类型可以引用一个参数化类型的变量,编译报告警告,例如:
   Collection c = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去

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

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

在数组创建实例时,数组的元素不能使用参数化的类型。(不能把类型变量赋给数组) 例如:

Vector<Integer> vectorList[] = new Vector<Integer>[10];//错误

泛型的 ? 通配符

public static void printCollection(Collection<?> collection){//collection.add(1);//通配符不可以调用和类型参数有关的方法System.out.println(collection.size());for(Object obj : collection){System.out.println(obj);}
}

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

通配符的扩展

  • 限定通配符的上边界

    Vector<? extends Number> x = new Vector<Integer>();//类型参数必须是Number或Number的子类
    
  • 限定通配符的下边界
    Vector<? super Integer> x = new Vector<Number>();//类型参数必须是Integer的父类
    

不能把 ? 赋给具体的类型,只能把具体的类型赋给 ?

自定义泛型

Java中的泛型类型(或者泛型)类似于C++中的模版。但是这种相似性仅限于表面,Java语言中的泛型基本上完全是在编译器中实现,用于编译器执行类型检查和类型推断,然后生成普通的非泛型字节码,这种实现技术称为擦除(erasure)(编译器使用泛型类型信息保证类型安全,然后在生成字节码之前将其清除)。这是因为扩展虚拟机指令集来支持泛型被认为是无法接受的,这会为Java厂商升级jvm造成难以逾越的障碍。所以,java的泛型采用了可以完全在编译器中实现的擦除方法。

用于放置泛型的类型参数尖括号应出现在方法的其他所有修饰符之后和在方法的返回类型之前,也就是紧邻返回值之前。按照惯例,类型参数通常用单个大写字母表示。

 swap(new String[]{"abc","xyz","itcast"},1,2);
//swap(new int[]{1,3,5,4,5},3,4);//错误,泛型方法的实际参数必须是引用类型private static <T> void swap(T[] a,int i,int j){T tmp = a[i];a[i] = a[j];a[j] = tmp;}

只有引用类型才能作为泛型方法的实际参数,对于add方法,使用基本类型的数据进行测试没有问题,这是因为自动装箱和拆箱了。swap(new int[3], 3, 5)语句会报告编译错误,这是因为编译器不会对new int[3]中的int进行自动拆箱和装箱了。因为new int[3]本身已经是对象了,你想要的有可能就是int数组呢?它装箱岂不是弄巧成拙了。

除了在应用泛型时可以使用extends,在定义泛型的时候也可以,并且可以使用&来指定多个边界,如<V extends Serializable & Cloneable> void method(){}

对异常采用泛型

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

private static <T extends Exception> method() throws T{try{}catch(Exception e){//不能catch T throw (T)e;//catch到异常后包装成另外一个异常往外扔}
}

在泛型中可以同时有多个类型参数,在定义它们的尖括号中用逗号分,例如

public static<K,V> V getValue(K key){return map.get(key);
}

自定义泛型方法

copy1(new Vector<String>(),new String[10]);
copy2(new Date[10],new String[10]);
//copy1(new Vector<Date>(),new String[10]);//错误public static <T> void copy1(Collection<T> dest,T[] src){}public static <T> void copy2(T[] dest,T[] src){}

自定义泛型类

class ClassTest<X extends Number, Y, Z> {    private X x;    private static Y y; //编译错误,不能用在静态变量中 public X getFirst() {//正确用法 return x;    }    public void wrong() {        Z z = new Z(); //编译错误,不能创建对象 }
}

注意:类里的静态方法不能使用泛型类的类型,因为该泛型类的实例化对象里的类型方法采用了泛型的类型,而静态方法不应该有类型级别的参数。

应用:通过反射获得泛型方法接收的参数的实际类型

package com.crow.Generic;/** * Created by CrowHawk on 17/2/16. */import java.lang.reflect.*;
import java.util.*;public class GenericTest {public static void main(String[] args) throws Exception{HashMap<String, Integer> hashMap = new HashMap<>();hashMap.put("Tom", 1);hashMap.put("Jerry", 2);hashMap.put("Nick", 3);printHashmap(hashMap);//用反射的方法获取printHashmap方法的参数并打印Method printMethod = GenericTest.class.getMethod("printHashmap", HashMap.class);Type[] types = printMethod.getGenericParameterTypes();ParameterizedType parameterizedType = (ParameterizedType)types[0];Type[] actualTypes = parameterizedType.getActualTypeArguments();System.out.println("The paratype is " + parameterizedType.getRawType() + "<" + actualTypes[0] + "," + actualTypes[1] + ">");}public static void printHashmap(HashMap<String, Integer> hashMap){//遍历HashMap并打印其内容Set<Map.Entry<String, Integer>> entrySet = hashMap.entrySet();for(Map.Entry<String, Integer> entry: entrySet){System.out.println(entry.getKey() + "," + entry.getValue());}Iterator<Map.Entry<String, Integer>> iter = entrySet.iterator();while(iter.hasNext()){Map.Entry<String, Integer> entry = iter.next();System.out.print("Key is " + entry.getKey() + ",");System.out.println("Value is " + entry.getValue());}}
}

Java基础学习(3)-泛型相关推荐

  1. Java基础学习——第十章 枚举类注解

    Java基础学习--第十章 枚举类&注解 一.枚举类(enum) 1. 枚举类的概念 枚举类:类的对象只有有限个,确定的 线程状态:创建.就绪.运行.阻塞.死亡 当需要定义一组常量时,强烈建议 ...

  2. Java基础学习(12)

    Java基础学习 一.不可变集合 二.Stream流 2.1 Stream流数据添加 2.2 Stream流的中间方法 2.3 Stream终结方法 三. 方法引用 3.1 方法引用的基本概念 3.2 ...

  3. java基础学习-6

    Java基础学习-6 双列集合 Map的常见API Map的遍历方式 HashMap 小练习 LinkedHashMap TreeMap TreeMap--小练习1 TreeMap--小练习2 Tre ...

  4. JAVA基础学习精简心得笔记整理

    JAVA基础学习精简心得笔记整理 配置java环境变量 Java的运行过程  基本数据类型 引用数据类型 逻辑运算符 数组 方法重载 封装 继承 多态 多态的作用 单例设计模式 接口interface ...

  5. java基础学习整理(一)

    java基础学习整理(一) lesson1: D0s命令: 1.回到根目录,>cd \ 2.复制命令行下的内容,右击标记所要复制的内容,这样就已经复制好了,右击粘贴就可以了. 3.查看,设置环境 ...

  6. 【Java基础学习笔记】- Day11 - 第四章 引用类型用法总结

    Java基础学习笔记 - Day11 - 第四章 引用类型用法总结 Java基础学习笔记 - Day11 - 第四章 引用类型用法总结 4.1 class作为成员变量 4.2 interface作为成 ...

  7. Java中大数据数组,Java基础学习笔记之数组详解

    摘要:这篇Java开发技术栏目下的"Java基础学习笔记之数组详解",介绍的技术点是"java基础学习笔记.基础学习笔记.Java基础.数组详解.学习笔记.Java&qu ...

  8. java基础学安卓开发_Android开发学习路线之Java基础学习

    原标题:Android开发学习路线之Java基础学习 很多Android学习开发者刚入手Android开发技术时,稍微有点迫切.任何的开发技术都有其基础语言,Android应用程序开发是以Java语言 ...

  9. Java基础学习:尚硅谷项目三 开发团队调度软件

    Java基础学习:尚硅谷项目三 开发团队调度软件 一.软件功能与结构设计 1. 软件功能 该软件实现以下功能: 软件启动时,根据给定的数据创建公司部分成员列表(数组) 根据菜单提示,基于现有的公司成员 ...

  10. Java基础学习汇总

    Java基础学习汇总 java语言基础 java函数和数组 java面向对象 java异常 整理用,早就停更... 写作不易,如果您觉得写的不错,欢迎给博主点赞.收藏.评论.收藏来一波~让博主更有动力 ...

最新文章

  1. redis持久化的几种方式
  2. 全新视角:用变分推断统一理解生成模型(VAE、GAN、AAE、ALI)
  3. 20000字节的包算大吗_20000的包和200的包区别,戳中了万千女人的内心!
  4. [蓝桥杯]算法提高 vertex cover(dfs)
  5. vue 页面不置顶问题(页面内操作、页面跳转后) - 集合篇
  6. android wear 处理器,联发科推Android Wear平台可穿戴处理器
  7. RFID能否让实体零售业度过“寒冬”?
  8. 《spring-boot学习》-10-RabbitMQ
  9. nftables入门文档
  10. 事半功倍,在JCreator中查询java API
  11. vue中实现图片的懒加载
  12. hosts该文件已设置为只读的解决方法
  13. 捣鼓PlantUML
  14. ISP最简单步骤,计算得到一个sRGB色域图像
  15. pytho sockt编程
  16. Think-swoole的使用
  17. php属于哪种语言,php是哪种类型的语言
  18. php 处理png图片白色背景色改为透明色
  19. html 如何让网页变灰色
  20. linux解压zip、bz、bz2、z、gz、tar(解包)

热门文章

  1. 42. Element hasChildNodes() 方法
  2. js里用append()和appendChild有什么区别?
  3. 20172325 2018-2019-1 蓝墨云班课实验--哈夫曼树的编码
  4. 事务 锁 悲观锁 乐观锁 概念 应用场景 使用方式 小记
  5. Flume案例之采集特定目录的数据到HDFS
  6. 全文检索(LuceneSolr)
  7. zzbower入门教程
  8. android开发,assets下面的资源文件不会变化/改动
  9. WCF DataService调试时的一些问题
  10. WinXP IIS配置