zoukankan      html  css  js  c++  java
  • Java 泛型

    1、泛型的由来

      我们先看下面这段代码:

                    List list = new ArrayList();
    		list.add(24);  //向集合中添加一个 Integer 类型的数据
    		list.add("Tom");	//向集合中添加一个 String 类型的数据
    		
    		for(int i = 0 ; i < list.size() ; i++){
    			Object obj = list.get(i);  //注意这里每个类型都是 Object
    			System.out.println(obj);
    		}
    		
    		//如果我们遍历的时候就想得到自己想要的数据类型
    		for(int i = 0 ; i < list.size() ; i++){
    			String obj = (String) list.get(i);  //在取 Integer 的时候会报类型转换错误
    			System.out.println(obj);
    		}
    

      报错信息如下:

      也就是 集合中第二个数据是 Integer,但是我们取出来的时候将其转换为 String 了,所以报错。

      那么这个如何解决呢?

      ①、我们在遍历的时候,根据每个数据的类型判断,然后进行强转。

    那么我们说这个集合只有两条数据,我们可以进行判断强转,如果数据有成千上万条呢,我们都通过这样判断强转肯定不可取

      ②、在往集合中加入数据的时候,我们就做好限制,比如这个集合只能添加 String 类型的;下一个集合只能添加 Integer 类型的,那么我们在取数据的时候,由于前面已经限制了该集合的数据类型,那么就很好强转了。

      这第二种解决办法,也就是我们这篇文章讲的 泛型

    2、什么是泛型?

      泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

      在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。

    3、泛型的基本用法

      3.1 对于上面的问题我们只需要将上述代码的 List list = new ArrayList()  改为   List<String> list = new ArrayList<String>();

                    List<String> list = new ArrayList<String>();
    		//list.add(22);  //向集合中添加一个 Integer 类型的数据时,编译器会报错
    		list.add("Bob");  //向集合中添加一个 String 类型的数据
    		list.add("Tom");	//向集合中添加一个 String 类型的数据
    		
    		//如果我们遍历的时候就想得到自己想要的数据类型
    		for(int i = 0 ; i < list.size() ; i++){
    			String obj = list.get(i);  //这里就不需要强转了,前面添加的是什么类型,这里获取的就是什么类型
    			System.out.println(obj);
    		}            
    

      

      

      3.2 泛型是在编译阶段有效

            List<String> list1 = new ArrayList<String>();
    	List list2 = new ArrayList();
    	Class c1 = list1.getClass();
    	Class c2 = list2.getClass();
    	System.out.println(c1==c2); //true    
    

      上述代码,由于我们知道反射是在运行时阶段,c1==c2为 true,说明了编译之后的 class 文件中是不包含任意的泛型信息的。如果不信,我们可以看 class 文件的反编译信息

            java.util.List list1 = new ArrayList();
            java.util.List list2 = new ArrayList();
            Class c1 = list1.getClass();
            Class c2 = list2.getClass();
            System.out.println(c1.equals(c2));
    

      我们可以看到 反编译之后的 list1和 list2完全一样。

      结论:Java 泛型只在编译阶段有效,即在编译过程中,程序会正确的检验泛型结果。而编译成功后,class 文件是不包含任何泛型信息的

      3.3 泛型类和泛型方法

    public class Box<T> {
    	private T box;
    	public T getBox(T t){
    		this.box = t;
    		return t;
    	}
    	public void getType(){
    		System.out.println("T的实际类型为:"+box.getClass().getName());
    	}
    	
    	public static void main(String[] args) {
    		Box box = new Box();
    		System.out.println(box.getBox(1));
    		box.getType();
    		
    		System.out.println(box.getBox("Tom"));
    		box.getType();
    	}
    
    }
    

      输出结果为:

    1
    T的实际类型为:java.lang.Integer
    Tom T的实际类型为:java.lang.String

      

      3.4 泛型通配符

      在泛型中,我们可以用 ? 来代替任意类型

         public List wildCard(List<?> list){
    		
    		return list;
    	}
    
    	public static void main(String[] args) {
    		GenericTest gt = new GenericTest();
    		//构造一个 Interger 类型的集合
    		List<Integer> integer = new ArrayList<Integer>();
    		integer.add(1);
    		System.out.println(gt.wildCard(integer));
    		//构造一个 String 类型的集合
    		List<String> str = new ArrayList<String>();
    		gt.wildCard(str);
    		//构造一个 Object 类型的集合
    		List<Object> obj = new ArrayList<Object>();
    		obj.add(1);
    		obj.add("a");
    		System.out.println(gt.wildCard(obj));
    		//构造一个 任意类型的 集合,这和 List<Object> 存放数据没啥区别
    		List list = new ArrayList();
    		gt.wildCard(list);
    		
    	}
    

      

      3.5 泛型的上限和下限

      ①、上限: 语法(? extends className),即只能为 className 或 className 的子类

    //通配符的下限,只能是 Number 或 Number的子类
    	public List wildCard(List<? extends Number> list){
    		
    		return list;
    	}
    
    	public static void main(String[] args) {
    		GenericTest gt = new GenericTest();
    		//构造一个 Interger 类型的集合
    		List<Integer> integer = new ArrayList<Integer>();
    		integer.add(1);
    		System.out.println(gt.wildCard(integer));
    		//构造一个 String 类型的集合
    		List<String> str = new ArrayList<String>();
    		//gt.wildCard(str);   //编译报错
    		//构造一个 Object 类型的集合
    		List<Object> obj = new ArrayList<Object>();
    		obj.add(1);
    		obj.add("a");
    		//System.out.println(gt.wildCard(obj)); //编译报错
    		
    	}
    

      ①、下限: 语法(? super className),即只能为 className 或 className 的父类

    //通配符的上限,只能是 Number 或 Number的父类
    	public List wildCard(List<? super Number> list){
    		
    		return list;
    	}
    
    	public static void main(String[] args) {
    		GenericTest gt = new GenericTest();
    		//构造一个 Interger 类型的集合
    		List<Integer> integer = new ArrayList<Integer>();
    		integer.add(1);
    		//System.out.println(gt.wildCard(integer));  //编译报错
    		//构造一个 String 类型的集合
    		List<String> str = new ArrayList<String>();
    		//gt.wildCard(str);   //编译报错
    		//构造一个 Object 类型的集合
    		List<Object> obj = new ArrayList<Object>();
    		obj.add(1);
    		obj.add("a");
    		System.out.println(gt.wildCard(obj)); 
    	}
    

      

    4、泛型的注意事项

      4.1、不能用基本类型来定义泛型,如 int、float

    List<int> list = new ArrayList<int>(); //不能用 int 这样的基本类型定义泛型
    

      关于这一点很好想明白,因为 集合中只能存放引用类型的数据,即使你存入基本类型的,Java还是会通过自动拆箱和自动装箱机制将其转换为引用类型

      

      4.2、如果使用 ? 接收泛型对象时,则不能设置被泛型指定的内容

    List<?> list = new ArrayList<>();
    		list.add("aa");  //错误,无法设置
    

      

      4.3、泛型方法的定义与其所在的类是否是泛型类是没有任何关系的,所在的类可以是泛型类,也可以不是泛型类

      4.4、泛型类没有继承关系,即String 为 Object 类型的子类,则 List<String> 是 List<Object> 的子类这句话是错误的

      原因:假设上面那句话是正确的,那么由于泛型的产生机制就是放什么类型的数据进去,取出来的就是什么类型,而不用进行类型转换,这里把 String 类型的数据放入Object 类型的泛型集合中,那么取出来的应该就是 String      类型的数据,而实际上取出来的是 Object 类型的数据,这与泛型的产生机制相违背,故不成立!

  • 相关阅读:
    PyQt作品 – PingTester – 多点Ping测试工具
    关于和技术人员交流的一二三
    Pyjamas Python Javascript Compiler, Desktop Widget Set and RIA Web Framework
    Hybrid Qt applications with PySide and Django
    pyjamas build AJAX apps in Python (like Google did for Java)
    PyQt 维基百科,自由的百科全书
    InfoQ:请问为什么仍要选择Java来处理后端的工作?
    Eric+PyQt打造完美的Python集成开发环境
    python select module select method introduce
    GUI Programming with Python: QT Edition
  • 原文地址:https://www.cnblogs.com/ysocean/p/6826525.html
Copyright © 2011-2022 走看看