`

java 泛型学习笔记

阅读更多

 

   java泛型从JDK1.5开始出来的,虽然自己平时也有用到,但是一直没有全面的学习,今天在看myibatis3.0.1源码时,看到多处用到泛型设计,所以自己把泛型学习了下。

 

什么是泛型?

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

  泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

 

泛型使用的规则和限制

  1. 泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
  2. 同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
  3. 泛型的类型参数可以有多个。
  4. 泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
  5. 泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String");

泛型的基本使用

    eg1:使用了泛型

package com.kyle.Generics.ch01;


/**
 * 定义泛型类型
 * @author kyle
 *
 * @param <T>
 */
public class SimpleDemo1<T> {
	private T ob;//定义泛型成员变量
	
    public T getOb() {
		return ob;
	}

	public void setOb(T ob) {
		this.ob = ob;
	}

	public SimpleDemo1(T ob){
    	
    	this.ob=ob;
    }
	
	public  void showType(){
		
		System.out.println("T的实际类型是:"+ob.getClass().getName());
	}
    
	public static void main(String args[]){
		//定义泛型SimpleDemo的一 个Integer版本
		SimpleDemo1<Integer> intObj=new SimpleDemo1<Integer>(88);
		//不需要转换可以得到ob的具体类型
		Integer  intValue=intObj.getOb();
		intObj.showType();
		
		
		//定义泛型SimpleDemo的一个String版本
		
		SimpleDemo1<String> strObj=new SimpleDemo1<String>("Hello world");
		//不需要转换可以得到ob的具体类型
		String strValue=strObj.getOb();
		strObj.showType();
		String str=strObj.getOb();
		System.out.println("ob is vlaue :"+str);
		
		
	}
    

}

 

eg2:没有使用泛型实现

package com.kyle.Generics.ch01;

/**
 * 没有使用泛型
 * @author kyle
 *
 */
public class SimpleDemo2{
	
	private Object ob; //定义一个通用类型成员 
	
	public SimpleDemo2(Object ob) {
		this.ob = ob; 
	} 
	
	public Object getOb() {
		return ob;
	}

	public void setOb(Object ob) {
		this.ob = ob;
	}

	
	
    public  void showType(){
		
		System.out.println("Object的实际类型是:"+ob.getClass().getName());
	}
    
    public  static void main(String args[]){
    	SimpleDemo2  intObj=new  SimpleDemo2(new Integer(88));
               int intValue=(Integer)intObj; //强制转换成Integer
    	intObj.showType();


    	SimpleDemo2  strObj=new SimpleDemo2(new String("Hello Gen2"));
               String  strValue=(String)strObj;//强制转换成String 
    	strObj.showType();
    	
    }

}

 

  通过上面两个DEMO的比较,我们可以很直接的看到泛型给我们带来的易用性。在这里DEMO1中我们可以简单的假想为T就是我们构造对象时动态传入的字符串,例如

SimpleDemo1<Integer> intObj=new SimpleDemo1<Integer>(88)传入的是Integer,那么private T ob 就变成private Integer ob,SimpleDemo1<String> strObj=new SimpleDemo1<String>("Hello world")传入的String,那么private T ob就变成private String ob。T就相当于是一个类型变量,编译器在编译时把该变量替换成我们传入的类型。

 

 

泛型的高级应用

 1.限制泛型的可用类型

     class GenericsFoo<T extends Collection>,这样的泛型T只能是Collection接口的实现类或者子接口,传入非Collection接口则会编译报错

  注意:<T extends Collection>这里的限定使用关键字extends ,实际T的类型Collection可以是实现Collection接口的类也可以是继承了Collection接口,  extends只是起一个限定作用,而非继承的意义。

 

 eg: 

package com.kyle.Generics.ch03;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;

public class CollectionGenFoo <T extends Collection>{
	
	private T x;
	
   public CollectionGenFoo( T x){
    	
    	this.x=x;
    	
    }
	
    public T getX() {
		return x;
	}

	public void setX(T x) {
		this.x = x;
	}
	
	public static void main(String args[]){
		
		/**1
   		* 定义CollectionGenFoo的泛型为ArrayList
   		* 即定义listFoo这个引用只接受泛型为
  		* ArrayList类型的实例
   		* 我们构造函数传入new ArrayList()传入的正是ArrayList类型
   		*/



   		CollectionGenFoo<ArrayList> listFoo = null;
  		 listFoo=new CollectionGenFoo<ArrayList>(new ArrayList());
                                 listFoo.getX();//该方法返回的对象为ArryList类型
 		 /**2
  		 * 定义CollectionGenFoo的泛型为Collection
  		 * 即定义listFoo这个引用只接受泛型为
   		 * Collection类型的实例
   		 *  我们构造函数传入new ArrayList()是Collection接口的实现类
   		 *  也是Collection类型的
   		*/



   		CollectionGenFoo<Collection> listFoo2 = null;
   		listFoo2=new CollectionGenFoo<Collection>(new ArrayList());
                              	listFoo2.getX();//该方法返回的对象为Collection类型		
		  /**3
    		  * 下面的报错
    		  *CollectionGenFoo<String>中的类型必须是 Collection类型的
     		  */



    		 //CollectionGenFoo<String> listFoo3=null;
   
   
    		/**4
    		* 下面的报错,因为声明的引用已经定义参数必须为Collection类型的
    		* 那么new CollectionGenFoo<ArrayList>传入的类型必须与引用一致
    		* 即T这个类型变量不能同时为两个值
    		*/



       		//CollectionGenFoo<Collection> listFoo4 = null;
   		//listFoo4=new CollectionGenFoo<ArrayList>(new ArrayList());
	}

	
}

 

 

   通过这个例子,我们应该仔细对比1,2,3,4这三种声明方式,体会泛型的含义:

   1.从1,2,3可以看出使用“有界泛型”<T extends SuperClass>这种声明方式 时,类型参数T必须是SuperClass的子类或者SuperClass类型。如果不是则会在编译时报:

       Bound mismatch: The type String is not a valid substitute for the bounded parameter <T extends Collection> of the type            CollectionGenFoo<T> 这个错误。

   2.从4可以看出<T extends SuperClass>中的T虽然可以是任意SuperClass的任意类型,但是一旦引用指定具体类型以后,实例的泛型类型必须和引用是一致,在这里 并不存在什么父子关系, 即类型T不能前后赋两个不同值。

 

   2.通配符泛型

     在上面的例子中对于当我们声明某一种特定泛型类型的引用时,那么对应的实例的泛型类型就必须和引用的泛型类型一样,这样当我们有多个泛型类型子类实例时,我们就必须声明多个不同的引用,也就是我们的引用被具体化了,换句话说,我们的泛型被具体化了,所以才导致我们的引用也被具体化了。那么如何让一个含有泛型的引用

也可以接受任意的实例类型?

 

  eg: 继续上面的DEMO,在main方法中加入如下声明方式

 

                /**5
		 * 使用通配符CollectionGenFoo<? extends Collection> 
		 * listFoo5这个引用接受所有Collection类型 的实例
		 * 
		 */

		CollectionGenFoo<? extends Collection> listFoo5 = null;
		listFoo5=new CollectionGenFoo<ArrayList>(new ArrayList());
		listFoo5=new CollectionGenFoo<LinkedList>(new LinkedList());
		listFoo5.getX();//该方法返回值的类型为Collection类型
		
		
		/**
		 * CollectionGenFoo<?>方式声明引用时
		 * listFoo5这个引用接受所有Collection类型的实例
		 * 
		 */
		CollectionGenFoo<?> listFoo6 = null;
		listFoo6=new CollectionGenFoo<ArrayList>(new ArrayList());
		listFoo6=new CollectionGenFoo<LinkedList>(new LinkedList());
		listFoo6.getX();//该方法返回值的类型为Object类型
     
		/*
		 * 下面的报错:
		 * 虽然通配符?可以是任意类型,但是也是有限制的
		 * 必须是Collection的子类
		 */
                /*报错:
                  *Bound mismatch: The type String is not a valid substitute for the bounded parameter
                  *<T extends Collection> of the type CollectionGenFoo<T>
                  */

  		//listFoo6=new CollectionGenFoo<String>(new String("test"));
               
 

总结:

1. 从5中可以看出当我们使用CollectionGenFoo<? extends SuperClass>的通配符方式声明对象引用时,虽然引用可以接受不 同泛型的对象实例,但是该实例泛型的具体类型已经丢失,全部被上溯成为SuperClass类型

 

2.从6中可以看出当我们使用CollectionGenFoo<?>的通配符方式声明对象引用时,虽然引用可以接受不 同泛型的对象实例,但是该实例的泛型的具体类型已经丢失,全部被上溯成为Object类型

 

3.5,6中的  new的实例中的泛型必须是SuperClass的子类或者SuperClass类型。

 

4.通配符泛型不单可以向下限制,还可以向上限制,如:<? Super  ArrayList>,表示类型只能接受ArrayList类型以及其上层父类类型,如:List,Collection

  

 

  3.泛型方法 

    未完。。。

 

 

泛型在设计的使用场景

 

分享到:
评论

相关推荐

    Java泛型学习笔记.pdf

    学习Java泛型能够帮助我们更好地编写和使用通用的类、接口和方法。以下是从给定文件的标题、描述、标签和部分内容中提取出的详细知识点。 1. 泛型类和泛型方法: 在Java中,泛型可以应用于类、接口和方法。泛型类和...

    Java泛型,深入学习java的不二之选.md

    java泛型详细学习,深入学习java的不二之选

    java基础学习笔记之泛型

    泛型是Java编程语言中的一个重要特性,首次在JDK 1.5版本中引入,它允许程序员在定义类、接口和方法时使用类型参数,从而实现了类型的安全性和代码的复用性。泛型的主要目标是增强类型安全,避免在运行时出现...

    Exer.java(JavaSE泛型学习笔记)

    泛型学习笔记2的源代码,泛型 : 要解决类型的安全问题, 如果使用Object类型会带来类型的损失。典型的应用就是在集合中, 集合中理论上可以保存任意对象,实际上我们应该让它泛型化,集合类&lt;元素类型&gt;, 添加元素...

    泛型笔记学习2009

    在Java泛型出现之前,集合框架中的类如`List`、`Map`等都是以`Object`作为类型处理元素的。这意味着在使用这些集合时,往往需要频繁地进行类型转换操作,如: ```java List list = new ArrayList(); list.add("hello...

    Java基础 学习笔记 Markdownr版

    本学习笔记主要涵盖了Java的基础知识,包括面向对象、集合、IO流、多线程、反射与动态代理以及Java 8的新特性等方面,旨在帮助初学者或有经验的开发者巩固和提升Java编程技能。 1. 面向对象(OOP):Java的核心是...

    java泛型.xmind

    自己总结的java泛型的笔记,绘制了详细的思维导图,每个思维导图中均有详细的博文解释,方便大家学习和理解,免费分享给大家。适合java的爱好者和学习者

    基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码.zip

    基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码.zip 基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码.zip 基于java的开发源码-java多线程反射泛型及正则表达式学习笔记和源码....

    java学习笔记markdown

    10. **泛型**:讨论Java泛型的使用,如何编写类型安全的代码,并理解其类型擦除的原理。 11. **枚举与注解**:介绍Java中的枚举类型及其用法,以及注解的定义和应用,它们在现代Java开发中有着广泛的应用。 12. **...

    Java1.5泛型指南中文版(Java1.5Gene....pdf

    本资源为 Java 1.5 泛型指南中文版的详细笔记,涵盖了泛型的基础知识、泛型类、泛型方法、通配符、擦除和翻译、类型安全、类型参数、实际类型参数、擦除、翻译、转型和 instanceof、数组、Class Literals as Run-...

    Java学习笔记——良葛格

    "Java学习笔记——良葛格"是一份专为初学者设计的教程资料,由良葛格精心编写,旨在帮助读者掌握JDK5.0版本的Java基础知识。JDK(Java Development Kit)是Java开发的核心工具集,包含了编译器、调试器和运行环境等...

    JAVA学习笔记 林信良

    此外,《JAVA学习笔记》还涵盖了集合框架,包括ArrayList、LinkedList、HashSet、HashMap等各种集合类的使用,以及泛型、迭代器和流API的应用。这些内容对于处理数据和实现复杂算法至关重要。 对于多线程编程,书中...

    Java JDK 7学习笔记 PDF

    这个PDF学习笔记是开发者深入理解JDK 7特性和功能的重要参考资料。以下是对Java JDK 7的一些核心知识点的详细阐述: 1. **泛型改进**:在JDK 7中,泛型的使用更加灵活,引入了类型推断(Type Inference)特性,通过...

    Java基础尚硅谷宋红康学习笔记

    【Java基础】 Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems(现已被Oracle公司收购)于1995年发布。Java以其“一次编写,到处运行”的特性...通过深入学习和实践,你可以不断提升自己的Java编程能力。

    Java JDK 6学习笔记——ppt简体版

    Java JDK 6学习笔记是为Java初学者量身定制的一份宝贵资料,它涵盖了Java编程的基础概念、语法以及核心特性。这份PPT简体版旨在帮助读者快速掌握Java开发的基本技能,逐步成为一名合格的Java程序员。 Java JDK...

    《Java学习笔记》

    这份《Java学习笔记》包含了丰富的知识内容,旨在帮助学习者全面掌握Java编程技术。笔记分为7个PDF部分,覆盖了从基础到高级的Java编程概念。 1. **Java基础知识**:这部分内容通常包括Java的历史背景、环境配置、...

Global site tag (gtag.js) - Google Analytics