Java泛型

package com.Generics.test;
//定义Apple类时使用了泛型声明
public class Apple<T >
{
	//使用T类型形参定义实例变量
	private T info;
	public Apple(){}
	//使用T类型形参来定义构造器
	public Apple(T info)
	{
		this.info=info;
	}
	public void setInfo(T info)
	{
		this.info=info;
	}
	public T getInfo()
	{
		return this.info;
	}
}

package com.Generics.test;

public class AnApple <T extends Number>{
	T size;
	public AnApple()
	{
		
	}
	public AnApple(T size)
	{
		this.size=size;
	}
	public void setSize(T size)
	{
		this.size=size;
	}
	public T getSize()
	{
		return this.size;
	}
}

package com.Generics.test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
class GenericMethodTest
{
	//声明一个泛型方法,该泛型方法中带一个T类型形参
	static <T> void fromArraytoCollection(T[] a,Collection<T> c)
	{
		for(T o:a)
		{
			c.add(o);
		}
	}
	
}
class RightTest{
	//声明一个泛型方法,该泛型方法中带一个T类型形参
	//static <T> void test(Collection<T> from,Collection<T> to)  ①处将产生
	//错误,由于两个形参类型都是Collection<T>,如此就要求①处调用该方法的两个集合中的泛型参数
	//类型应该相同,否则编译器无法准确推断出泛型方法中类型形参的类型
	static <T> void test(Collection<? extends T>from ,Collection<T> to)
	{
		for(T ele:from)
		{
			to.add(ele);
		}
	}
}
//泛型构造器
class Foo{
	public <T> Foo(T t)
	{
		System.out.println(t);
	}
}
//Java8改进的类型判断
class MyUtil<E>
{
	public static<Z> MyUtil<Z> nil()
	{
		return null;
	}
	public static <Z> MyUtil<Z> cons(Z head,MyUtil<Z> tail)
	{
		return null;
	}
	E head()
	{
		return null;
	}
}
//Java7的菱形语法允许调用构造器时在构造器后面使用一对尖括号来代表
//泛型信息,但如果程序显示指定了泛型构造器中声明的类型形参的实际类型,则不可以使用菱形语法
class Myclass<E>{
	public <T> Myclass(T t)
	{
		System.out.println("t参数的值为:"+t);
	}
}
public class Generics {

	public static void main(String[] args) {
		//创建一个只保存字符串的List
		List strList=new ArrayList();
		strList.add("语文");
		strList.add("计算机");
		//不小心把Integer丢尽了List集合将会导致ClassCastException异常
		//strList.add(5);
		strList.forEach(str->System.out.println(((String)str).length()));
		
		System.out.println("\n---------使用泛型---------");
		//创建一个只想保存字符串的List集合
		List<String> sList=new ArrayList<String>();
		sList.add("语文");
		sList.add("计算机");
		//下面代码将引起编译错误: Unresolved compilation problem
		//sList.add(2);
		sList.forEach(str->System.out.println(((String)str).length()));
		
/*
 * 从Java7开始,java允许在构造器后面不需要带上完整的泛型信息,
 * 只要给出一对尖括号:<>即可,java可以自动推断尖括号里应该是
 * 什么泛型信息。
 */
		System.out.println("\n--------Java7泛型的菱形语法--------");
		//Java自动推断ArrayList的<>里面应该是String
		List<String> books=new ArrayList<>();
		books.add("计算机导论");
		books.add("高级操作系统");
		books.add("模式识别");
		//遍历books集合,集合元素类型是String
		books.forEach(ele->System.out.println(ele.length()));
		//Java自动推断出HashMap的<>应该是String,List<String>
		Map<String,List<String>> schoolsInfo=new HashMap<>();
		//Java自动推断出ArrayList的<>应该是String
		List<String> schools=new ArrayList<>();
		schools.add("图书馆");
		schools.add("实验室");
		schoolsInfo.put("自习室", schools);
		//遍历Map时,Map的key是String类型,value是List<String>类型
		schoolsInfo.forEach((key,value)->System.out.println(key+"-->"+value));
		
/*
 * 定义泛型接口、类
 * 泛型就是允许在定义类,接口,方法时使用类型形参,这个类型形参将在声明变量
 * 创建对象,调用方法时动态地指定(即传入实际的类型参数)
 */
		System.out.println("\n--------定义泛型接口、类--------");
		//定义接口时指定了一个类型形参,该形参名为E
//		public interface List<E>
//		{
//			//在该接口里,E可以作为类型使用
//			//如下方法可以使用E作为参数类型
//			void add(E x);
//			Iterator<E> iterator();
//		}
//		//定义接口时指定了一个类型形参,该形参名为E
//		public interface List<E>
//		{
//			//在该接口里完全可以使用E作为类型使用
//			E next();
//			boolean hasNext();
//		}
//		//定义该接口时指定了两个类型形参,其形参名为K,V
//		public interface Map<K,V>
//		{
//			//在该接口里K,V完全可以作为类型使用
//			Set<K> keySet()
//			V put(K key,V value)
//		}
		//List<String>等同于如下接口
		/*
		 * 如下使用List类型时,如果为E形参传入String类型形参,则产生了一个
		 * 新的类型:List<String>类型,可以把List<String>想象成E被全部
		 * 替换成String的特殊List子接口
		 */
//		public interface ListString extends List
//		{
//			//原来的E形参全部变成String类型形参
//			void add(String x);
//			Iterator<String> iterator();
//			....
//		}
		
		Apple<String> a1=new Apple<>("苹果");
		System.out.println(a1.getInfo());
		Apple<Double> a2=new Apple<>(5.67);
		System.out.println(a2.getInfo());
		
		System.out.println("\n--------并不存在泛型类--------");
		List<String> l1=new ArrayList<>();
		List<String> l2=new ArrayList<>();
		//调动getclass()方法来比较l1和l2的类是否相等
		System.out.println(l1.getClass()==l2.getClass());
		
		System.out.println("\n--------类型通配符--------");
		//定义一个Integer数组
		Integer[] ia=new Integer[6];
		//可以把一个Integer[]数组赋给number[]变量
		Number[] na=ia;
		na[0]=9;
		System.out.println(na[0]);
		//下面代码会引发ArrayStoreException异常,因为7.8不是一个Integer
		//na[1]=7.8;
		List<Integer> iLlist=new ArrayList<>();
		//Java不允许把List<Integer>对象赋值给List<Number>变量,
		//下面将会引发异常
		//List<Number> nList=iList;
		
		System.out.println("\n--------使用泛型方法--------");
		Object[] oa=new Object[100];
		Collection<Object> co=new ArrayList<>();
		//下面代码中T代表Object类型
		fromArrayToCollection(oa,co);
		String[] sa=new String[100];
		Collection<String> cs=new ArrayList<>();
		//下面代码中T代表Object类型
		fromArrayToCollection(sa,co);
		Integer[] ia1=new Integer[100];
		Float[] fa=new Float[100];
		Number[] na1=new Number[100];
		Collection<Number> cn=new ArrayList<>();
		下面代码中T代表Number类型
		fromArrayToCollection(ia1,cn);
		fromArrayToCollection(fa,cn);
		fromArrayToCollection(na1,cn);
		//下面代码中T代表Object类型
		fromArrayToCollection(na1,co);
		//下面代码中T代表String类型,但na1是一个Number数组
		//因为Number既不是String类型,也不是它的子类,所以出现编译错误
		//fromArrayToCollection(na1,cs);
		System.out.println(na1);
		
		List<Object> ao=new ArrayList<>();
		List<String> as=new ArrayList<>();
		RightTest.test(as, ao);//①
		
		System.out.println("\n----Java7的菱形语法和泛型构造器----");
		//泛型构造器中的T参数为String
		new Foo("Java编程思想");
		//泛型构造器中的T参数为Integer
		new Foo("200");
		//显式指定泛型构造器中的T参数为String
		//传给Foo构造器的实参也是String对象,完全正确
		new <String> Foo("Java程序设计");
		//显式指定泛型构造器中的T参数为String
		//但传给Foo构造器的实参也是Double对象,下面代码出错
		//new <String> Foo(12.3);
		
		//Myclass 声明中的E形参是String类型,而泛型构造器中声明的T类型是Integer类型
		Myclass<String> mc1=new Myclass<>(5);
		//显式指定泛型构造器中声明的T形参是Integer类型
		Myclass<String> mc2=new<Integer> Myclass<String>(5);
		//Myclass 声明中的E形参是String类型
		//如果显式指定泛型构造器中声明的T形参是Integer类型
		//此时就不能使用“菱形”语法,下面代码错误
		//Myclass<String> mc3=new<Integer> Myclass<>(5);
		
		//❶和❷方法的两个参数都是Collection对象,前一个集合里的集合元素是后一个集合里集合元素
		//类型的父类
		System.out.println("\n----设定通配符下限----");
		List<Number> ln=new ArrayList<>();
		List<Integer> li=new ArrayList<>();
		li.add(5);
		//此处可准确知道最后一个被复制的元素时Integer类型
		//与src集合元素类型相同
		Integer last=(Integer) copy(ln,li);
		System.out.println(ln);
		
		System.out.println("\n----TreesSet<E>中的构造器设定通配符下限----");
		//Comparator的实际类型是TreeSet的元素类型的父类,满足要求
		TreeSet<String> ts1=new TreeSet<>(new Comparator<Object>(){
			public int compare(Object fst,Object snd)
			{
				return hashCode()>snd.hashCode()?1
						:hashCode()<snd.hashCode()?-1:0;
			}
		});
		ts1.add("Hello");
		ts1.add("Welcome");
		//Comparator的实际类型是TreeSet元素的类型,满足要求
		TreeSet<String> ts2=new TreeSet<>(new Comparator<String>(){
			public int compare(String first,String second)
			{
				return first.length()>second.length()?-1
						:first.length()<second.length()?1:0;
			}
		});
		ts2.add("Hello");
		ts2.add("Welcome");
		System.out.println(ts1);
		System.out.println(ts2);
		
		System.out.println("\n----Java8改进的类型判断----");
		/*
		 * 可通过调用方法的上下文来推断类型参数的目标类型
		 * 可在方法调用链中,将推断得到的类型参数传递到最后一个方法
		 */
		//可通过方法赋值的目标参数来推断类型参数为String
		MyUtil<String> ls=MyUtil.nil();
		//无须使用下面语句在调用nil()方法时指定类型参数的类型
		MyUtil<String> mu=MyUtil.<String>nil();
		//可调用cons()方法所需的参数类型来推断类型参数为Integer
		MyUtil.cons(42,MyUtil.nil());
		//无须使用下面语句在调用nil()方法时指定类型参数的类型
		MyUtil.cons(42, MyUtil.<Integer>nil());
		
		System.out.println("\n----擦除和转换----");
		AnApple<Integer> a=new AnApple<>(6);
		//a的getSize()方法返回Integer对象
		Integer as1=a.getSize();
		//把a对象赋给AnApple变量,丢失尖括号的类型信息
		AnApple b=a;
		//只知道size的类型是Number
		Number size1=b.getSize();
		System.out.println(size1);
		
		System.out.println("\n----泛型与数组----");
		List<Integer> liii=new ArrayList<Integer>();
		liii.add(new Integer(3));
		
		
	}
	static<T> void fromArrayToCollection(T[] a,Collection<T> c)
	{
		for(T o:a)
		{
			c.add(o);
		}
	}
	//❶设定通配符下限,src集合必须与dest集合元素类型相同,或者是其子类
//	public static <T> T copy(Collection <T> dest,Collection<? extends T> src)
//	{
//		T last = null;
//		for(T ele:src)
//		{
//			last=ele;
//			dest.add(ele);
//		}
//		return last;
//	}
	//❷设定通配符上限,dest集合必须与src集合元素类型相同,或者是其父类
	public static <T> T copy(Collection <? super T> dest,Collection<T> src)
	{
		T last = null;
		for(T ele:src)
		{
			last=ele;
			dest.add(ele);
		}
		return last;
	}
}














©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页