Day016--java中的泛型机制

 JDK1.5版本中提供了泛型的概念。泛型实际上就是使程序员定义安全的类型。在没有出现泛型时,java提供来了对Object的引用“任意化”操作对Object引用进行“向上/下转型操作”

案例1

现在我们创建一个集合a并将两只猫咪放入集合中,并使用向下转型,得到猫咪对象,打印输出猫咪的名字和年龄。

Day016--java中的泛型机制_第1张图片

在上面的案例中我们传入的是猫咪对象,向下转型的类型也是猫咪类。但是有些时候我们也会不小心将其他的类型加入集合中,并将其向下转型成猫咪类。这个时候编译器是不会有报错的,但是在运行时就会报ClassCastException异常错误。如下,我们创建一个Dog类,并将其加入集合a中。

Day016--java中的泛型机制_第2张图片

代码:

import java.util.ArrayList;
public class WithoutG {
public static void main(String[] args) {
	ArrayList a=new ArrayList();  
    a.add(new Cat("咪咪",3));     
    a.add(new Cat("喵喵",4));
    a.add(new Dog("哈士奇",4));     //在这里我们加入了Dog对象
    for(Object o:a) {
    	Cat c=(Cat)o;
    	System.out.println(c.name+"(>^ω^<)"+c.age+"岁了");
    }
}}
class Cat{
	 String name;
	 int age;
	 public Cat(String name,int age) {
		 this.name=name;
		 this.age=age;
	 }
	@Override
	public String toString() {   //重写Cat类的toString方法
		return "Cat [name=" + name + ", age=" + age + "]";
	}
	 
}
class Dog{
	 String name;
	 int age;
	 public Dog(String name,int age) {
		 this.name=name;
		 this.age=age;
	 }
	@Override
	public String toString() {  //重写Dog类的toString方法
		return "Dog [name=" + name + ", age=" + age + "]";
	}}
	 

案例2

我们可以看到哦上面的(Object的强制类型转换一般是“向下转型”容易出现问题存在安全隐患,所以在java中提供泛型机制。我们可以在类名后面加上-----T是type的缩写。表示我们的类是一个泛型类,同时该类返回和接收的参数使用了T这个类型。现在我们将上面的案例进行修改:

Day016--java中的泛型机制_第3张图片

进行如上修改后编译器就会在运行前进行检查类型匹配是否正确,这样子就不会一不小心传入不同的对象了如果想要猫狗放一个集合里面的话,我们可以创建一个ArrayList的泛型类,如下: 

Day016--java中的泛型机制_第4张图片

我们将集合修改成泛型类这样子可以传入两个不同类的对象,就不会出现“向下转型”异常的错误

import java.util.*;
public class Gennic{
	private T t;    //创建T类型(泛型类型)的变量。
	public T getT() {    //得到变量的值
		return t;
	}
	public void setT(T t) {   //设置变量的值
		this.t = t;
	}

	@Override
	public String toString() {
		return "Gennic [t=" + t + "]";
	}
	public static void main(String[] args) {
	Gennic arrayList=new Gennic();    //创建泛型对象
	 //-----------------这里不变-----------------
	ArrayList a=new ArrayList();  
    a.add(new Cat("咪咪",3));     
    a.add(new Cat("喵喵",4));
    a.add(new Dog("哈士奇",4));
    //-----------------这里不变-----------------
    arrayList.setT(a);           //将我们的集合作为参数传入arrayList中(a变泛型类)
    for(Object t:arrayList.getT()) {      //因为我们传入的不是一个类型,因此我们使用Object(所有子类的超类)来进行接收
    	System.out.println(t.toString());   
    }
   
//    for(Object o:a) {    //将集合a传入Object超类中
//    	Cat c=(Cat) o;   //使用向下转型,将Object类型转换成Cat类型
//    	System.out.println(c.name+"  is      "+c.age+"   years old");
//    }
	}

}
class Cat{
	 String name;
	 int age;
	 public Cat(String name,int age) {
		 this.name=name;
		 this.age=age;
	 }
	@Override
	public String toString() {   //重写Cat类的toString方法
		return "Cat [name=" + name + ", age=" + age + "]";
	}
	 
}
class Dog{
	 String name;
	 int age;
	 public Dog(String name,int age) {
		 this.name=name;
		 this.age=age;
	 }
	@Override
	public String toString() {  //重写Dog类的toString方法
		return "Dog [name=" + name + ", age=" + age + "]";
	}
	 
}

我们在定义泛型类时,也可以声明多个类型。形如:泛型类名称

  • T1,T2:都是可能被定义的类型

例如:泛型类名  对象名=new 泛型类名 ();

案例3

这种案例一般出现在map集合中,如hashMap及treeMap,下面我们来使用hashMap创建一个集合,用来存储员工类(键为员工的名字,值为员工的信息)--涉及的集合请跳转到Day012进行阅读

Day016--java中的泛型机制_第5张图片

 代码:

import java.util.*;
import java.util.Map.Entry;

public class WithG {
	//使用HashMap创建一个集合,用来存储员工类(键为员工的名字,值为员工的信息)
	//最后以“张三的信息为张三,wage=1800,age=30”输出打印集合中的键和值
	public static void main(String[] args) {
		Map map=new HashMap();  //设置两个类型
		Employee e1=new Employee("张三",18000,30);
		Employee e2=new Employee("李四",1800,30);
		Employee e3=new Employee("王五",28000,30);
		map.put(e1.name,e1 );
		map.put(e2.name,e2 );
		map.put(e3.name,e3 );
		Set set=map.entrySet();
		Iterator it=set.iterator();
		while(it.hasNext()) {
			Map.Entry entry=(Entry) it.next();
			System.out.println(entry.getKey()+"的信息为"+entry.getValue());
		}
		}
	}
class Employee{
	String name;
	int wage;
	int age;
	public Employee(String name,int wage,int age) {
		this.name=name;
		this.wage=wage;
		this.age=age;
	}
	@Override
	public String toString() {
		return  name + ", wage=" + wage + ", age=" + age ;
	}
	
}

案例4

//定义Employee类,该类包含private成员变量name,sal,birthday(为MyDate类的对象)

//为每一个属性定义getter和setter方法,重写toString方法输出三个变量信息

//MyDate类包含private成员变量,month,day,year,并为每一个属性定义getter和setter方法
//创建员工类的3个对象,并把这些对象放入ArrayList集合中(ArrayList需要使用泛型来定义)
//对集合中的元素进行排序(调用sort方法,传入Comparator对象,先按照name排序,如果name相同,则按照生日日期的先后排序),并遍历输出

Day016--java中的泛型机制_第6张图片

年月日时MyDate里面的属性,每当我们要去使用这三个属性时,就需要去调用getBirthday方法得到,太过于麻烦了,如下框起来的部分:

Day016--java中的泛型机制_第7张图片

 因此我们可以将它简化一下,将这些方法放入MyDate类中,并让MyDate类去实现Comparator接口,这样子就可以使用比较器并重写comparTo方法。

Day016--java中的泛型机制_第8张图片

Day016--java中的泛型机制_第9张图片

 代码:

import java.util.*;
import java.lang.*;
@SuppressWarnings({"all"})
public class Case2 {
	public static void main(String[] args) {

    Employee1 e1=new Employee1("Amy",3000,new MyDate(2000,12,2));
    Employee1 e2=new Employee1("Mike",20000,new MyDate(2002,2,4));
    Employee1 e3=new Employee1("Mike",35000,new MyDate(1998,3,5));
    ArrayList arrayList=new ArrayList<>();
    arrayList.add(e1);
    arrayList.add(e2);
    arrayList.add(e3);
    System.out.println(arrayList);
	arrayList.sort(new Comparator() {   //使用ArrayList集合自带的sort方法,之后我们重写比较器
		public int compare(Employee1 e1,Employee1 e2) {    //覆盖原有的compare方法,传入两个员工类对象
			int objName=e1.getName().compareTo(e2.getName());   //比较对象的名字使用compaTo方法,如果相同,返回0,不同则不是0
			if(objName!=0) {
				return objName;
		}
			return e1.getBirthday().compareTo(e2.getBirthday());     //直接调用员工类中的getBirthday方法即可
		}	
		});
	System.out.println("=============泛型类比较=======");
	System.out.println(arrayList);        //打印比较后的集合容器
	}}
class Employee1{
   private	String name;
   private  double sal;
   private MyDate birthday;
   
public String toString() {
	return "\nEmployee [name=" + name + ", sal=" + sal + ", month=" + birthday + "]";
}
public Employee1() {}    
public Employee1(String name, double sal, MyDate birthday) {
	this.name = name;
	this.sal = sal;
	this.birthday = birthday;
}
public String getName() {
	return name;
}
public void setName(String name) {
	this.name = name;
}
public double getSal() {
	return sal;
}
public void setSal(double sal) {
	this.sal = sal;
}
public MyDate getMonth() {
	return birthday;
}
public void setMonth(MyDate month) {
	this.birthday = birthday;
}
public MyDate getBirthday() {
	return birthday;
}
public void setBirthday(MyDate birthday) {
	this.birthday = birthday;
}

   
}
class MyDate  implements Comparable{     //创建MyDate类,实现Comparable接口,将该类作为参数传入
	private int year;
	private int month;
	private int day;
	public MyDate() {}
	@Override
	public int compareTo(MyDate date) {           //覆盖重写compareTo方法,传入的依旧是当前类
		int dateYear=year-date.year;   //如果name相同,我们再比较出生年份,并将结果返回
		if(dateYear!=0) {    
			return dateYear;
		}
		int dateMonth=month-date.month;   //如果年份相同,我们再比较出生月份,并将结果返回
		if(dateMonth!=0) {
			return dateMonth;
		}
		return 	day-date.day;    //如果月份相同,那么我们就直接返回两个的相减值

		
	}
	public MyDate(int year, int month, int day) {
		this.year = year;
		this.month = month;
		this.day = day;
	}
	public int getYear() {
		return year;
	}
	public void setYear(int year) {
		this.year = year;
	}
	public int getMonth() {
		return month;
	}
	public void setMonth(int month) {
		this.month = month;
	}
	public int getDay() {
		return day;
	}
	public void setDay(int day) {
		this.day = day;
	}
	@Override
	public String toString() {
		return "MyDate [year=" + year + ", month=" + month + ", day=" + day + "]";
	}	
}

泛型通配符 

泛型的通配符在我看来就是解决“泛型不具备继承性”问题的:

Day016--java中的泛型机制_第10张图片 给出的提示为:类型不匹配:无法从列表<字符串>转换为列表<对象>

在以前我们写继承时,都知道Object是所有类的超类,无论什么类型都可以传入里面,而在泛型中却不是这样,如果我们想要它正确可以将里面的参数String去除

Day016--java中的泛型机制_第11张图片

 如上的方法只是使用了同一个类来创建对象,没有继承,但是我们可以是使用通配符来使两个类之间有继承关系。让他们匹配。

Day016--java中的泛型机制_第12张图片

如上使用了通配符之后我们就可以使用String类型的泛型来创建对象了,在上面出现的"?  extends"是通配符里面的一种,总共有三种,接下来我们去认识一下它们:

  • ---表示支持任意类型泛型类型
  • ---表示我们的泛型最大只能到AnotherClass类的泛型---------------定义:支持AnotherClass类及AnotherClass类的子类,规定了泛型的上限。
  • ---表示我们的泛型最小要是AnotherClass类的泛型----------------------定义:支持AnotherClass类及AnotherClass类的父类,不限于直接父类,规定了泛型的下限。

Day016--java中的泛型机制_第13张图片

 代码:

import java.util.*;
public class TongPei {
	public static void main(String[] args) {
//		List list=new ArrayList();   //泛型不具备继承性
		List list=new ArrayList<>();   //使用泛型Object来创建对象
		List list1=new ArrayList();   //使用通配符
		System.out.println("===============测试通配符的使用===============");
		testWildcard1(new ArrayList());    //传入ClassA类型的对象没有问题
		testWildcard1(new ArrayList());    //传入ClassA类型的对象没有问题
		testWildcard2(new ArrayList());    //传入ClassB类型的对象会产生问题
		testWildcard2(new ArrayList());    //传入Object类型的对象没有问题
		
		
	}
	
	public static void testWildcard1(ArrayList a)  {    //测试 "  ?  extends" 调配符的使用
		System.out.println("? extends ClassA规定了上限为ClassA类型,只能传入ClassA类及ClassA类的子类的类型");
	}
	public static void testWildcard2(ArrayList a)  {    //测试    "?  super  "通配符的使用
		System.out.println("? extends ClassA规定下限为ClassA类型,只能传入ClassA类及ClassA类的父类的类型");
	}
}
class ClassA{}  //自定义的类
class ClassB  extends ClassA{}   //ClassB类继承ClassA类,是ClassA类的子类 
  

                            
                        
                    
                    
                    

你可能感兴趣的:(Java,SE,java,开发语言,eclipse)