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;
}
}