`

java泛型

阅读更多

java的泛型只在程序源码中存在,在编译成.class文件后就被替换成原生类型了,并且在相应的地方插入了强制类型转换代码,因为对于运行期的java语言来说ArraList<Integer>与ArrayList<String>就是同一个类,所以泛型技术实际上java语言的一颗语法糖,java语言中的泛型实现方法成为类型擦除,伪泛型。

 

包装类的“==”运算,再不遇到算术运算的情况下不会自动拆箱

		Integer a = 1;
		Integer b = 2;
		Integer c = 3;
		Integer d = 3;
		Integer e = 321;
		Integer f = 321;
		Long g=3L;
		System.out.println(c==d);//true
		System.out.println(e==f);//false
		System.out.println(c==(a+b));//true
		System.out.println(g.equals(a+b));//false
		System.out.println(g==(a+b));//true

 

 

在JavaSE 5 之前定义一个容器类

public class Test {
	private Object a;
	public Test(Object a){ this.a =a; }
	public void set(Object a){ this.a =a; }
	public Object get(){ return a ;}
	
	public static void main(String[] args) {
		Test test = new Test(new Date());
		Date date1 = (Date)test.get(); //需要强转
		test.set("abc"); //可以插入任何类型的类对象
 		Date date2 = (Date)test.get(); //ClassCastException
	}
}

 

        一般情况下,我们使用容器只会存储一种类型的对象,泛型的主要目的之一就是用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。

       下面是一个泛型类,在调用set方法时编译器会检查传入参数类型是否为Data,get()的时候也不需要强制类型转换,编译器就知道返值类型为Date

public class Test<T> {
	private T a;
	public Test(T a){ this.a =a; }
	public void set(T a){ this.a =a; }
	public T get(){ return a ;}
	
	public static void main(String[] args) {
		Test<Date> test = new Test<Date>(new Date());
		Date date1 = test.get();
		test.set("abc"); //编译不通过
	}
}

 

泛型方法:

       是否拥有泛型方法,与其所在的类是否是泛型没有任何关系。如果使用泛型方法能取代整个类泛型化,那么就应该只使用泛型方法,方法的类型变量放在返回值前面。

       当使用泛型类时,必须在创建对象的时候指定类型参数的值。

Test<Date> test = new Test<Date>(new Date());

 

 而使用泛型方法时通常不必指明参数类型,因为编译器会给我们找到具体的类型(类型推断)。

public class Test {
	public static <T> List<T> makeList(T... ts) {
		List<T> list = new ArrayList<T>();
		for (T t : ts) {
			list.add(t);
		}
		return list;
	}
	public static void main(String[] args) {
		List<String> list1 = makeList("a b c d".split(" "));
		List<Integer> list2 = Test.<Integer> makeList(1, 2, 3, 4);// 指定参数类型
	}
}

        上面的代码中,你无法获得任何泛型参数类型(T)的信息,你可以知道诸如类型参数标识符和泛型类型边界这样的信息,但是你无法知道用来创建某个特定实例的类型参数。你无法调用参数T的任何方法。。

 

       Java 的泛型是使用擦除来实现的,这就意味着你在使用泛型时,泛型的类型参数将被擦除到他的第一个边界(它可能会有多个边界)。在没有限定边界的情况下。默认用Object作为参数类型的第一个边界,上面的泛型将T擦除后。

	//类 擦除类型变量后
	private Object a;
	public Test(Object a){ this.a =a; }
	public void set(Object a){ this.a =a; }
	public Object get(){ return a ;}
	
	//方法 擦除类型变量后
	public static  List makeList(Object... ts) {
		List list = new ArrayList();
		for (Object t : ts) {
			list.add(t);
		}
		return list;
	}

       擦除是java实现泛型的一种折中,因为泛型不是java语言出现就有的组成部分,如果泛型在Java1.0中就已经存在了,那么这个特性不会使用擦除来实现,它将使用具体化,使类型参数保持为第一实体。因此你就能在类型参数上执行基于类型的语言操作和反射操作。例如:上面的泛型方法,你可以直接像下面这样操作,代码编译时会自动监测你的类型参数T是否有replaceAll()方法。

	public static <T> List<T> makeList(T... ts) {
		List<T> list = new ArrayList<T>();
		for (T t : ts) {
			t.replaceAll("a", "");//Java中编译无法通过
			list.add(t);
		}
		return list;
	}

        Java中要想实现上面的功能就要把 参数类型改成<T extends String> 

	public static <T extends String> List<T> makeList(T... ts) {
		List<T> list = new ArrayList<T>();
		for (T t : ts) {
			t.replaceAll("a", "");//ok
			list.add(t);
		}
		return list;
	}

       泛型类型只有在静态类型检查期间才出现,在此之后,程序中的所有泛型类型都将被擦除,替换为它们的非泛型上界。例如,诸如List<T>这样的类型注解将被擦除为List,而普通的类型变量在未指定边界的情况下将被擦除为Object。

       擦除的主要正当理由是从非泛化代码到泛化代码的转变过程,以及在不破坏现有类库的情况下,将泛型融入java语言。

       另外,擦除和迁移兼容性意味着,使用泛型并不是强制的

		List list = new ArrayList();

       当你希望将类型参数不要仅仅当作Object处理时,就要付出额外的努力来管理边界。

       上面泛型代码中,编译器负责set()的类型检查,然后转型Object插入set中,get()的时候负责将返回值进行转型。边界就是发生这些动作的地方。

        Java泛型重用了extends 关键字。格式:T extends *****  下面就可以根据自己定义的边界类型来调用方法。

public class Test {
	// T 必须是实现两个接口的子类,<T extends Date> 代表必须是Date的子类
	public static <T extends Comparable<T> & CharSequence> List<T> makeList(T to, T... ts) {
		List<T> list = new ArrayList<T>();
		for (T t : ts) {
			list.add(t);
			// T 可以使用上面两个接口中的方法
			System.err.println(t.compareTo(to) > 0 ? t.length() : t.charAt(0)); 
		}
		return list;
	}

	public static void main(String[] args) {
		makeList("c", "abcd", "efg");
		// makeList(1,2);  编译无法通过 因为Integer没有实现 CharSequence 接口
	}
}

     输出:

 

              97
              3

 

     通配符“?”
     通配符是用在泛型里的(List<? extends Number>   List必须是个泛型List<E>),通配符跟类型变量限定十分相似? extends *****,但是还有一个附加的能力,即可以指定一个超类的类型限定, ? super *****,一般带有超类型限定的通配符可以向泛型对象写入,带子类型限定的通配符可以从对象独取对象。

public class Test {
	// 不能对nums进行赋值,因为不确定是Number的什么子类型
	public static List<Double> aaa(List<? extends Number> nums) {
		List<Double> dou = new ArrayList<Double>();
		for (Number num : nums) {
			dou.add(num.doubleValue());
		}
		return dou;
	}

	public static void main(String[] args) {
		List<Integer> list1 = Arrays.asList(1, 2, 3);
		for (Double num : aaa(list1)) {
			System.err.println(num.toString());
		}
	}
}

     输出

         1.0
         2.0
         3.0

 

public class Test {
     //不能对nums 取值,因为不确定是Number的什么父类
	public static void aaa(List<? super Number> nums) {
		List<Integer> inters = Arrays.asList(1, 2);
		for (Integer inter : inters) {
			nums.add(inter);
		}
		Collections.addAll(nums, 1.1, 2.2);
	}

	public static void main(String[] args) {
		List<Number> nums = new ArrayList<Number>();
		aaa(nums);
		for (Number num : nums) {
			System.err.println(num);
		}
	}
}

 输出:

          1     
          2
          1.1
          2.2

 

无界通配符“?”

比如List<?> ,表示我可以接收任何List<String>、List<Integer>等类型的泛型参数。

  

1
0
分享到:
评论

相关推荐

    Java泛型编程指南.pdf

    Java泛型编程指南.pdf 此文章译自SUN的泛型编程指南

    Java泛型和集合

    Java Generics and Collections 英文版,详细描述java 泛型技术

    java 泛型类的类型识别示例

    java 泛型类的类型识别示例 java 泛型类的类型识别示例 java 泛型类的类型识别示例

    java 泛型接口示例

    java 泛型接口示例 java 泛型接口示例 java 泛型接口示例

    java 泛型方法使用示例

    java 泛型方法使用示例 java 泛型方法使用示例 java 泛型方法使用示例

    Java泛型的用法及T.class的获取过程解析

    主要介绍了Java泛型的用法及T.class的获取过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    JAVA泛型加减乘除

    这是一个使用JAVA实现的泛型编程,分为两部分,第一部分创建泛型类,并实例化泛型对象,得出相加结果。 第二部分用户自行输入0--4,选择要进行的加减乘除运算或退出,再输入要进行运算的两个数,并返回运算结果及...

    java泛型技术之发展

    java泛型技术之发展,学习JAVA 泛型的不错东东

    1.java泛型定义.zip

    1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1....

    很好的Java泛型的总结

    很好的Java泛型的总结,看完之后你一定会知道java泛型的底层机制,你一定会学会Java泛型!

    4.java泛型的限制.zip

    4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip...

    java泛型学习ppt

    java,学习java泛型,java培训之泛型.pptxjava培训之泛型.pptxjava培训之泛型.pptxjava培训之泛型.pptx

    java泛型总结

    深入理解java泛型,包括类名泛型的定义,方法泛型定义,泛型的返回

    SUN公司Java泛型编程文档

    Sun公司的Java泛型编程文档,英文原版和网络翻译版,想对泛型有更清楚的认识的朋友可以看看,必定会有所帮助

    java泛型详解.pdf

    java泛型详解.pdf

    JAVA泛型简单排序实例

    JAVA泛型源代码实现以下功能:返回数组元素的最大值/最小值下标;判断数组元素是否按升序排列;T对象数组排序;二分法查找key元素;

    思维导图之Java泛型详解

    思维导图之Java泛型详解

    Java泛型技术之发展

    Java泛型技术之发展

    JAVA泛型教程(帮你解决学习泛型的苦恼)

    JAVA泛型教程(帮你解决学习泛型的苦恼). Java 泛型编程可能会碰到很多问题,本教程可能会对你有帮助哦。

Global site tag (gtag.js) - Google Analytics