`

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泛型的用法及T.class的获取过程解析

    Java泛型的用法及T.class的获取过程解析 Java泛型是Java编程语言中的一种重要特性,它允许开发者在编写代码时指定类型参数,从而提高代码的灵活性和可读性。本文将详细介绍Java泛型的用法 及T.class的获取过程解析...

    Java泛型三篇文章,让你彻底理解泛型(super ,extend等区别)

    Java 泛型详解 Java 泛型是 Java SE 5.0 中引入的一项特征,它允许程序员在编译时检查类型安全,从而减少了 runtime 错误的可能性。泛型的主要优点是可以Reusable Code,让程序员编写更加灵活和可维护的代码。 ...

    Java泛型应用实例

    Java泛型是Java编程语言中的一个强大特性,它允许我们在定义类、接口和方法时指定类型参数,从而实现代码的重用和类型安全。在Java泛型应用实例中,我们可以看到泛型如何帮助我们提高代码的灵活性和效率,减少运行时...

    很好的Java泛型的总结

    Java泛型机制详解 Java泛型是Java语言中的一种机制,用于在编译期检查类型安全。Java泛型的出现解决了Java早期版本中类型安全检查的缺陷。Java泛型的好处是可以在编译期检查类型安全,避免了运行时的...

    java 泛型类的类型识别示例

    综上所述,虽然Java泛型在编译后会进行类型擦除,但通过上述技巧,我们仍然能够在运行时获得关于泛型类实例化类型的一些信息。在实际开发中,这些方法可以帮助我们编写更加灵活和安全的代码。在示例文件`GenericRTTI...

    java泛型技术之发展

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...

    SUN公司Java泛型编程文档

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着JDK 5.0的发布被引入。这个特性极大地提高了代码的类型安全性和可读性,减少了在运行时出现ClassCastException的可能性。SUN公司的Java泛型编程文档,包括...

    java 泛型接口示例

    下面我们将详细探讨Java泛型接口的相关知识点。 1. **泛型接口的定义** 泛型接口的定义方式与普通接口类似,只是在接口名之后添加了尖括号`&lt;T&gt;`,其中`T`是一个类型参数,代表某种未知的数据类型。例如: ```java...

    java 泛型方法使用示例

    下面我们将深入探讨Java泛型方法的概念、语法以及使用示例。 **一、泛型方法概念** 泛型方法是一种具有类型参数的方法,这些类型参数可以在方法声明时指定,并在方法体内部使用。与类的泛型类似,它们提供了编译时...

    java泛型的内部原理及更深应用

    Java泛型是Java编程语言中的一个强大特性,它允许在定义类、接口和方法时使用类型参数,从而实现参数化类型。这使得代码更加安全、可读性更强,并且能够减少类型转换的必要。在“java泛型的内部原理及更深应用”这个...

    Java 泛型擦除后的三种补救方法

    Java 泛型是一种强大的工具,它允许我们在编程时指定变量的类型,提供了编译时的类型安全。然而,Java 的泛型在运行时是被擦除的,这意味着在运行时刻,所有的泛型类型信息都会丢失,无法直接用来创建对象或进行类型...

    JAVA泛型加减乘除

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

    java泛型学习ppt

    "Java 泛型学习" Java 泛型是 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的...

    Java泛型使用详细分析.pdf

    Java 泛型使用详细分析 Java 泛型是 Java 语言中的一种类型系统特性,允许开发者在编译期检查类型安全,以避免在运行时出现类型相关的错误。在本文中,我们将详细介绍 Java 泛型的使用方法和实现原理。 一、泛型的...

    Java泛型技术之发展.pdf

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...

    面试必须资料java泛型攻略、

    #### 一、什么是Java泛型? Java泛型(Generics)是一种在编译时确保类型安全的机制,它允许程序员编写类型安全的通用类或方法,而无需进行显式的类型转换。在Java 1.5引入泛型之前,集合类(如`ArrayList`)只能...

Global site tag (gtag.js) - Google Analytics