泛型、泛型类、泛型方法、泛型方法、泛型通配符、泛型的限定

泛型

       集合中存储了不同类型的对象,取出时,容易在运行时期发生ClassCastException类型转换异常,为了避免这个问题的发生,如果在存储的时候就明确了集合要操作的数据类型,取出就没有任何问题了。这样在定义集合时,就需要立刻明确元素的类型,可以通过<>来明确元素的类型。

 

泛型的好处:

1.将运行时期出现的ClassCastException问题,转移到了编译时期;

2.避免了强制转换的麻烦。

 

泛型其实是JDJ1.5版本以后出现的一个安全机制,是给编译器使用的。泛型的表现形式就是<>,泛型的使用其实就是 给<>传递实际参数,而这个参数就是一个具体引用数据类型。

如下代码所示,直接避免了强制转换:

class GenericDemo2 
{
    public static void main(String[] args) 
    {
        TreeSet<Person> ts = new TreeSet<Person>(new CompareByName());
        //HashSet<Person> ts = new HashSet<Person>();
        ts.add(new Person("abc1",21));
        ts.add(new Person("abc0",20));
        ts.add(new Person("abc0",20));
        ts.add(new Person("abc4",24));
        ts.add(new Person("abc3",28));

        Iterator<Person> it= ts.iterator();

        while(it.hasNext())
        {
            Person p = it.next();
            System.out.println(p.getName()+"....."+p.getAge());
        }
    }
}

class CompareByName implements Comparator<Person>
{
    public int compare(Person p1,Person p2)
    {
        int temp = p1.getName().compareTo(p2.getName());
        return temp==0?p1.getAge()-p2.getAge():temp;
    }
}

class Person implements Comparable<Person>
{
    private String name;
    private int age;
    Person(String name,int age)
    {
        this.name = name;
        this.age = age;
    }
    public int compareTo(Person p)
    {
        
        int temp = this.age-p.age;
        return temp==0?this.name.compareTo(p.name):temp;

    }

    public int hashCode()
    {
        final int NUM = 34;
        return name.hashCode()+age*NUM;
    }


    public boolean equals(Object obj)
    {
        if(this==obj)
            return true;
        if(!(obj instanceof Person))
            return false;
        Person p = (Person)obj;
        return this.name.equals(p.name) && this.age==p.age;
    }
    
    public String getName()
    {
        return name;
    }
    public int getAge()
    {
        return age;
    }
    public String toString()
    {
        return name+"::"+age;
    }
}

 

泛型类

当类要操作的引用数据类型不确定的时候,可以使用泛型来定义,也就是定义一个类型参数。具体要操作什么类型的对象,由使用该类的使用者来明确,将具体的类型作为实际参数传递给<>,将泛型定义在雷桑,该泛型在该类范围内有效。

package Test.Test;

class Student
{
}

class Worker
{
}

class Tool<Q>
{
    private Q obj;
    public void setObj(Q obj)
    {
        this.obj = obj;
    }
    public Q getObj()
    {
        return obj;
    }
}



class GenericDemo3 
{
    public static void main(String[] args) 
    {

        Tool<Student> t = new Tool<Student>();
        t.setObj(new Student());
        Student s = t.getObj();
        
    }
}

 

泛型方法

 应用场景:当方法中操作的应用数据类型不确定,而且和对应的对象执行的类型也不一定一致,这时就将泛型定义在方法上。

 

当泛型定义在类上,该泛型作用于整个类,当建立该对象时就明确了具体类型,那么凡是使用了类上定义的泛型方法,操作的类也就固定了。

希望类中的方法,可以操作任意类型而不受类中泛型限制,可以将泛型定义在方法上----泛型方法。

 

当类中定义static方法时,静态方法是不可以直接访问类上的泛型的,因为类上的泛型只有通过建立对象才可以明确具体类型。

所以静态发那个发如果操作的引用数据类型不确定,只能将泛型定义在方法上,在静态方法上定义泛型,必须定义在static关键字之后。

 

package Test.Test;

class Student
{
}

class Worker
{
}

class Tool<Q>
{
    private Q obj;
    public void setObj(Q obj)
    {
        this.obj = obj;
    }
    public Q getObj()
    {
        return obj;
    }
    public static<w> void show(w obj){
        System.out.println(obj.toString());
    }
    public <w> void print(w obj){
        System.out.println(obj.toString());
    }
}



class GenericDemo3
{
    public static void main(String[] args)
    {

        Tool<Student> t = new Tool<Student>();
        t.setObj(new Student());
        Student s = t.getObj();
        t.print(new Worker());
        Tool.show(new Worker());
    }
}

输出为:

 

 

 

泛型接口

package Test.Test;

public class GenericInterfce {
    public static void main(String[] args){
        GenericInterfaceClass<String> gIC=new GenericInterfaceClass<String>();
        gIC.show("haha");
        GenericInterfaceClass2 gIC2=new GenericInterfaceClass2();
        gIC2.show("hehe");
    }
}

interface GenericInterface<T>{
    void show(T obj);
}

class GenericInterfaceClass<T> implements GenericInterface<T>{

    @Override
    public void show(T obj) {
        System.out.println(obj.toString());
    }
}


class GenericInterfaceClass2 implements GenericInterface<String>{

    @Override
    public void show(String obj) {
        System.out.println(obj);
    }
}

泛型接口的实现有两种方式:

第一种:在类实现该接口时仍然使用泛型,只有在建立类对象时才明确操作的类型,如GenericInterfaceClass 所示;

第二种:在类实现该接口时即确定类型,如 GenericInterfaceClass2 所示

 

 

泛型通配符 ?

 

以API文档中Collection类中的containsAll(Collection<?> c)为例:

可以看到存储有String类型的集合对象mc不能判断其是否包含存储有Integer类型的集合对象,这是因为mc存储的类型是String,其containsAll方法中对应的类型也为String,那么如何实现存储有String类型的集合对象也能够判断其是否包含存储有Integer类型的集合对象呢?

package Test.Test;

import java.util.Collection;

public class GenericDemo4 {
    public static void main(String[] args){
        MyCollection<String> mc=new MyCollection<String>();
        mc.containsAll(new MyCollection<Integer>());
    }
}

class MyCollection<T>{
    boolean containsAll(MyCollection <?> coll){
        return false;
    }
}

 

 

泛型的限定

 

package Test.Test;

import java.util.*;
class Person
{
    private String name;
    Person(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return name;
    }
}

class Student extends Person
{
    Student(String name)
    {
        super(name);
    }
}

class Teacher extends Person{

    Teacher(String name) {
        super(name);
    }
}
class  GenericDemo7
{
    public static void main(String[] args) 
    {
       // ArrayList<Person> al = new ArrayList<Student>();//不允许这样定义,因为集合声明的是可以放Person及其子类对象,
       // 但是集合实体声明只能存放Student类型,这会导致向集合中添加Person类的其他子类对象时出错,所以不允许这样定义,会在编译时出错。
        ArrayList<Person> al = new ArrayList<>();
        //定义集合要保证左右两边的类型一致。
        //两边只有一边定义泛型,也是可以支持,至少新老版本兼容。但是一样会出现,安全提示信息。

        al.add(new Person("p1"));
        al.add(new Person("p2"));
        al.add(new Person("p3"));
        al.add(new Student("s1"));
        al.add(new Teacher("t1"));
        show(al);

        ArrayList<Student> al1 = new ArrayList<Student>();

        al1.add(new Student("s1"));
        al1.add(new Student("s2"));
        al1.add(new Student("s3"));
        show(al1);//al1集合中存储的是Student类型,Student是Person的子类,所以可以正常调用show方法

    }

    public static void show(Collection< ? extends Person> coll)
    {
        Iterator<? extends Person> it = coll.iterator();
        while(it.hasNext())
        {
            System.out.println(it.next().getName());
        }
    }
}

     在泛型方法中,不可以使用具体类型的方法,最多只能使用Object类中的方法,

     定义T只能固定一种类型;

     定义?可以是任意类型;

     如果泛型方法中指向操作Person或者Person的子类类型,使用泛型的限定 ? extends E:接收E类型或者E的子类型;

      ? super E:接收E类型或者E的父类型;

 

? super E 示例:

 

package Test.Test;

import java.util.*;
class Person{
    private String name;
    Person(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return name;
    }

    @Override
    public String toString() {
        return "name:" + name;
    }
}

class Student extends Person{
    Student(String name)
    {
        super(name);
    }
}

class Teacher extends Person{

    Teacher(String name) {
        super(name);
    }
}


class  GenericDemo7{
    public static void main(String[] args) 
    {
        TreeSet<Student> treeSet=new TreeSet<Student>(new MyComparator());
        treeSet.add(new Student("s1"));
        treeSet.add(new Student("s4"));
        treeSet.add(new Student("s2"));
        System.out.println(treeSet);

    }
}

class MyComparator implements Comparator<Person>{
    public int compare(Person p1,Person p2){
        return p1.getName().compareTo(p2.getName());
    }
}

MyComparator类对象可以比较Person类及其子类对象,因为treeSet集合中存储的是Student类对象,Student类是Person类的子类,所以可以这样构造并进行比较。

这样创建比较器的好处是创建Person类的比较器之后,其各个子类都都可以用这个比较器进行比较。

 

此外,例如方法containsAll()

 

可以向存储有父类元素的集合中添加存储有子类对象的集合。

posted @ 2018-03-13 15:14  Garcia11  阅读(200)  评论(0)    收藏  举报