java之泛型理解(高效java之泛型)

  之前因为博客被盗 此篇文章写在博客园了 但是后面又加了写泛型的东西 故还是放到此处

  不过还是要感谢csdn的 webmaster@csdn.net 给它发邮件 不但账号找回了 被删的文章也找回 再次感谢CSDN的工作人员 谢谢


 多说无益 一切尽在代码和注释中

/**
 * 泛型学习测试代码
 * 
 * 泛型-->类或者接口的声明中拥有一个或多个类型参数时,称为泛型类/泛型接口,简称泛型 
 * 泛型在安全性和表述性上都比原生态类型更具有优势
 * 泛型是不可变的,无法向数组一样形成协变关系 
 * (Sub extends Super,同时可支持Sub[] extends Super[]) 
 * (Sub extends Super,不支持List<Sub> extends List<Super>) 
 * 泛型在编译时检查其元素类型信息,而在运行期舍弃其元素类型信息
 *  每个类都是自身的子类型和超类型
 * T 形式类型参数 
 * E 集合中的形式类型参数 
 * K Map中的键形式参数 
 * V Map中的值形式参数 
 * ? 任意匹配的配型参数 <? extends E>/<? super E>
 * 有限的通配符形式参数(PECS)
 * 
 * Class<T> 泛型 
 * Class<String> 参数化的类型 
 * Class 原生态类型(删除了所有的泛型信息) 
 * Class<?> 无限制的通配符类型
 * Class<? extends E> 有限制的通配符类型
 * Class<T extends Comparable<T>> 递归类型限制(用类型参数本身组成表达式限制类型参数)
 *  <T> 形式类型参数 
 *  <String> 实际类型参数
 * 
 * static <E> E get(E e) 泛型方法
 *  (<E> 称为类型参数列表,即在调用方法之前告诉编译器,此方法中的类型都是什么类型)
 * 编译器使用泛型方法可通过类型推导,推导出类型参数列表的类型
 * 
 * 此内容主要涉及泛型类和泛型方法,测试用例-->testGenericeClass
 * 泛型集合-->testGeneCollection
 * 有限的通配符使用-->testBoundWildType
 * 泛型编译器维护类型信息,运行时舍弃-->testEraseGenericsInfo
 * 递归类型参数调用-->testRecursionTypeRestri
 * 测试多个类型参数-->testDoubleType
 * @author Administrator
 * 
 */


测试代码

package com.undergrowth.lang;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

import org.junit.Test;

/**
 * 泛型学习测试代码
 * 
 * 泛型-->类或者接口的声明中拥有一个或多个类型参数时,称为泛型类/泛型接口,简称泛型 
 * 泛型在安全性和表述性上都比原生态类型更具有优势
 * 泛型是不可变的,无法向数组一样形成协变关系 
 * (Sub extends Super,同时可支持Sub[] extends Super[]) 
 * (Sub extends Super,不支持List<Sub> extends List<Super>) 
 * 泛型在编译时检查其元素类型信息,而在运行期舍弃其元素类型信息
 *  每个类都是自身的子类型和超类型
 * T 形式类型参数 
 * E 集合中的形式类型参数 
 * K Map中的键形式参数 
 * V Map中的值形式参数 
 * ? 任意匹配的配型参数 <? extends E>/<? super E>
 * 有限的通配符形式参数(PECS)
 * 
 * Class<T> 泛型 
 * Class<String> 参数化的类型 
 * Class 原生态类型(删除了所有的泛型信息) 
 * Class<?> 无限制的通配符类型
 * Class<? extends E> 有限制的通配符类型
 * Class<T extends Comparable<T>> 递归类型限制(用类型参数本身组成表达式限制类型参数)
 *  <T> 形式类型参数 
 *  <String> 实际类型参数
 * 
 * static <E> E get(E e) 泛型方法
 *  (<E> 称为类型参数列表,即在调用方法之前告诉编译器,此方法中的类型都是什么类型)
 * 编译器使用泛型方法可通过类型推导,推导出类型参数列表的类型
 * 
 * 此内容主要涉及泛型类和泛型方法,测试用例-->testGenericeClass
 * 泛型集合-->testGeneCollection
 * 有限的通配符使用-->testBoundWildType
 * 泛型编译器维护类型信息,运行时舍弃-->testEraseGenericsInfo
 * 递归类型参数调用-->testRecursionTypeRestri
 * 测试多个类型参数-->testDoubleType
 * @author Administrator
 * 
 */
public class GenericsLearn {

	/**
	 * 测试泛型类和方法
	 */
	@Test
	public void testGenericeClass() {
		GenericeClass<String> gClass1 = new GenericeClass<String>("测试泛型类参数");
		System.out.println(gClass1);
		System.out.println(gClass1.getAddSome("泛型方法"));
		System.out.println(gClass1.getAddSome(123));
	}

	/**
	 * 泛型测试类
	 * 
	 * @author Administrator
	 * 
	 * @param <T>
	 */
	private static class GenericeClass<T> {
		private final T t;

		public GenericeClass(T t) {
			super();
			this.t = t;
		}

		/**
		 * 获取对象后 添加附加信息
		 * 
		 * @param t
		 * @return
		 */
		public <E> E getAddSome(E t) {
			if (t instanceof String) {
				// 因为在进入此方法时 已做了类型判断 使用注解消除非受检警告
				@SuppressWarnings("unchecked")
				E t1 = (E) (String.valueOf(t) + ",附加泛型防范新消息");
				return t1;
			}
			return t;
		}

		public void iterator(Iterable<? extends T> src) {
			for (T t : src) {
				System.out.println(t);
			}
		}

		@Override
		public String toString() {
			return "GenericeClass [t=" + t + "]";
		}

	}

	/**
	 * 测试泛型集合
	 */
	@Test
	public void testGeneCollection() {
		Collection<String> collection = createCollection("123");
		/*
		 * for (Iterator<String> iterator = collection.iterator();
		 * iterator.hasNext();) { String string = (String) iterator.next();
		 * System.out.println(string); }
		 */
		iterator(collection);
	}

	/**
	 * 创建测试集合
	 * 
	 * @return
	 */
	private <E> Collection<E> createCollection(E t) {
		// TODO Auto-generated method stub
		Collection<E> collection = Collections.emptyList();
		if (t instanceof String) {
			collection = new CopyOnWriteArrayList<E>();
			// 已经进行类类型检查 所以转换时没有问题的 每个类都是自身的子类型和超类型
			@SuppressWarnings("unchecked")
			Collection<? extends E> initData = (Collection<? extends E>) Arrays
					.asList(new String[] { "测试集合1", "测试集合2", "测试集合3" });
			collection.addAll(initData);
		}
		return collection;
	}

	/**
	 * 创建Number集合
	 * 此方法不推荐使用 这里只是测试使用  
	 * @return
	 */
	@Deprecated
	private <E> Collection<E> createNumber() {
		Collection<E> collection = new CopyOnWriteArrayList<E>();
		@SuppressWarnings("unchecked")
		Collection<? extends E> initData = (Collection<? extends E>) Arrays
				.asList(new Number[] { 123.2, Integer.MAX_VALUE, 789 });
		// System.out.println(initData.getClass().getName());
		collection.addAll(initData);
		return collection;
	}

	/**
	 * 迭代实现了Iterable接口的可迭代子类
	 * 
	 * @param src
	 */
	public <E> void iterator(Iterable<E> src) {
		for (E e : src) { // 内部通过迭代器来遍历元素
			System.out.println(e);
		}
	}

	/**
	 * 测试有限的通配符类型 每个类都是自身的子类型和超类型
	 *  PECS原则-->producer-extends,consumer-super
	 */
	@Test
	public void testBoundWildType() {
		GenericeClass<Number> gClass1 = new GenericeClass<Number>(123456);
		System.out.println(gClass1);
		System.out.println(gClass1.getAddSome("123456"));
		// 创建Number数组
		Collection<Number> collection = createNumber();
		iterator(collection);
		// 使用GenericeClass的迭代方法进行迭代 每个类都是自身的子类型和超类型
		System.out
				.println("使用有限的通配符进行迭代 形式为:Iterable<? extends T>  实际为:Iterable<Number extends Number> 每个类都是自身的子类型和超类型");
		gClass1.iterator(collection);
		Collection<Integer> collection2 = createNumber();
		// 使用foreach进行迭代
		System.out.println("使用foreach进行迭代");
		iterator(collection2);
		// 使用有限的通配符进行迭代
		System.out
				.println("使用有限的通配符进行迭代 形式为:Iterable<? extends T>  实际为:Iterable<Integer extends Number>");
		gClass1.iterator(collection2);
		System.out.println("进行字符串集合的foreach迭代");
		Collection<String> collection3 = createNumber();
		iterator(collection3);
		System.out.println("如果使用collection3.add(123)方法,泛型的安全性检查就会得到体现,编译器会报错");
		// collection3.add(123);
		System.out
				.println("如果调用gClass1.iterator(collection3)方法,就会有问题,因为形式为:Iterable<? extends T> 实际为:Iterable<String extends Number>");
		// gClass1.iterator(collection3);
		System.out.println("获取Serializable集合");
		Collection<Serializable> collection4 = createNumber();
		iterator(collection4);
		System.out
				.println("之前一直有个疑惑,为什么Collection<Number>、Collection<Integer>、Collection<String>、Collection<Serializable>、Collection<List>调用的时候 能够返回相应的集合,"
						+ "因为很明显 在createNumber方法中创建的是Number的List<Number>集合 我们有知道泛型是不可协变的 为什么会成功呢 ");
		System.out
				.println("因为泛型在编译器检查其类型信息(所以当定义Collection<Serializable> collection4 = createNumber();的时候 调用createNumber,而此方法只会进行类型检查,createNumber为泛型方法,所以编译时是没有问题的),而在运行时丢弃其元素类型信息,并且强制类型转换是在运行期进行的,所以在(Collection<? extends E>)强制类型转换实际上是(Collection)List,所以运行期也没有问题,调试一下就知道了,害我想了1个多小时");
	}

	/**
	 * 测试泛型只在编译器维护其类型信息 在运行期不会维护其元素的类型信息 
	 * 下面代码会报错 java.lang.ClassCastException:
	 * java.lang.Double cannot be cast to java.util.List
	 */
	@Test
	public void testEraseGenericsInfo() {
		System.out.println("获取List集合");
		Collection<List> collection5 = createNumber();
		for (List list : collection5) {
			System.out.println(list.get(0));
			;
		}
	}
	
	/**
	 * 递归类型限制
	 * 使用类型参数本身组成表达式限制类型参数
	 */
	@Test
	public void testRecursionTypeRestri(){
		//Integer和String都实现了Comparable接口
		List<Integer> list=Arrays.asList(1,2,3,4);
		System.out.println(recurType(list));
		List<String> listString=Arrays.asList("1","2","3","4");
		System.out.println(recurType(listString));
		//自定义实现的Comparable接口
		List<CustomComparable> listCustomComparables=Arrays.asList(new CustomComparable(10),new CustomComparable(20),new CustomComparable(30));
		System.out.println(recurType(listCustomComparables));
	}
	/**
	 * 找到列表中的最大值
	 * @param list
	 * @return
	 */
	private <T  extends Comparable<T>> T recurType(List<T> list){
		T to=list.get(0);
		for (Iterator<T> iterator = list.iterator(); iterator.hasNext();) {
			T t = (T) iterator.next();
			if(to.compareTo(t)<=0) to=t;
		}
		return to;
	}
	
	/**
	 * 多个类型参数调用
	 * 多个类型参数 
	 *  其中一个参数要么与泛型类相关联 iterator(Iterable<? extends T> src)
	 *  要么与静态方法关联 GenericsLearn.<Number>doubleType
	 */
	@Test
	public void testDoubleType(){
		Collection<Integer> collection=Arrays.asList(1,2,3);
		Collection<Number> collection2=GenericsLearn.<Number>doubleType(collection);
		System.out.println("使用泛型方法传递多个类型参数");
		for (Number number : collection2) {
			System.out.println(number);
		}
	}
	
	public static <E> Set<E> doubleType(Collection<? extends E> collection){
		Set<E> set=new HashSet<>();
		for (Iterator<? extends E> iterator = collection.iterator(); iterator.hasNext();) {
			E e = (E) iterator.next();
			System.out.println(e);
			set.add(e);
		}
		return set;
	}	
	@Test
	public void testOther() {
		Integer integer = (int) 13.2;
		String aString = String.valueOf(13.2);
	}

	/**
	 * 自定义比较器
	 * @author Administrator
	 *
	 */
	class CustomComparable implements Comparable<CustomComparable>{

		private final int  num;
		public CustomComparable(int num){
			this.num=num;
		}
		
		@Override
		public int compareTo(CustomComparable o) {
			// TODO Auto-generated method stub
			if(this.num>o.num) return 1;
			else if(this.num==o.num) return 0;
			else return -1;
		}

		@Override
		public String toString() {
			return "CustomComparable [num=" + num + "]";
		}
		
		
	}
}



附加一个 泛型中最复杂的用法  时间:2015-6-13

类型限界--在尖括号中指出,它指定的参数类型必须具有某种性质

例如:

public static <anytype> anytype findMax(anytype[] arr){
int maxIndex=0;
for(int i=1;i<arr.length;i++){
  if(arr[i].compareTo(arr[maxIndex])>0) maxIndex=i;
}
return arr[maxIndex];
}

更好的做法

public static <anytype extends Comparable<anytype>> ...

但是 此种方法会因为泛型的不可协变 导致子类无法使用

           举个例子,假如Shape实现Comparable<Shape>,Square继承Shape,那么Square也是实现了Comparable<Shape>,Square is-a Comparabe<Shape>,

          但是因为泛型不可协变,导致于 Square is-not-a Comparable<Square>,为了解决此问题

更好的做法

public static <anytype extends Comparable<? super anytype>> ...




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值