泛型

一、为什么要引入泛型?以及泛型的本质?
(1)所谓的要引入泛型,就是创造容器类,这个容器类就是放入要使用对象的地方,而且这个容器比较灵活,可以放任意类型的对象,所以使用泛型的主要目的之一就是指定容器中持有什么类型的对象,而且编译器来保证类型的正确性。
(2)知道了为什么要引入泛型,我们就来认识一下泛型的本质:实质就是参数化类型,也就是说将数据类型作为参数,在使用的时候再指定具体数据类型。
(3)引入泛型的好处:第一可以检查检查数据类型,第二获取数据时自动进行强制类型转换。(其过程只发生在编译阶段);


重点内容介绍完为什么引入泛型,一个很重要的问题就是泛型类型的擦除?
(1)所谓的JAVA泛型擦除就是就是把所有的泛型擦除成原始的object类型;但是如果指定上界的话,就擦除到这个上界;
例如:

Class c1=new ArrayList<String>().getClass();
Class c2=new ArrayList<Integer>().getClass();
System.out.println(c1==c1);  
结果返回的是true;因为它们都是相同的类型object;根据这一信息,我们可以看到java泛型是使用擦除来实现的,这意味着当你在使用泛型时,类型信息就被擦除掉了,你唯一知道的就是你在使用一个对象。

(2)有时我们需要根据情况需要,不想擦除到原始类型,因此就需要规定上界,擦除到这个指定的边界,用extends关键词来指定。
例如:

class GenericFun<T extends Comparable<T>>{

}
这里讲上界指定到Comparable,即在编译时擦除到Comparable

二、泛型的应用
(1)泛型类
eg: Class Array{ };
注意: T中不可以是简单类型;在使用的时候需指定类型参数;

class GenericMath<T extends Number>{
    public int sumFunc(T[] array){
        int sum = 0;
        for(T val : array){
            sum += val.intValue();
        }
        return sum;
    }

(2)泛型方法
eg: public void ( T[] arrray){
}
注意:泛型方法是在参数列表中返回值前面加泛型参数列表;

泛型方法举例1public static <E extends Number> int sumFunc2(E[] array){
        int sum = 0;
        for(E val : array){
            sum += val.intValue();
        }
        return sum;
    }
泛型方法举例2
//利用Comparable接口创建自己的类进行比较,即实现compareTo方法,
    public static <E extends Comparable<E>> E min(E[] array){
        E minval=array[0];
        for(int i=0;i<array.length;i++){
            if(minval.compareTo(array[i])>0){
                minval=array[i];    
            }

        }
        return minval;
    }
泛型方法举例3:
实现一个静态方法,比较任意类型两个元素的大小,返回boolean
    //Integer/Integer     Double/Double      Short/Short
    public static <E extends Comparable<E>> boolean compare(E a, E b){
        return a.compareTo(b) > 0 ? true : false;
    }
}

(3)泛型接口

eg: Comparable<Person>;

class Person implements Comparable<Person>{
    private String name;
    private int age;
    private String sex;

    public Person(String name, int age, String sex) {
        super();
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public int age(){
        return age;
    }

    //按姓名进行比较
    @Override
    public int compareTo(Person o) {
        // TODO Auto-generated method stub
        return name.compareTo(o.name);
    }
}

//Student继承person
class Student extends Person{
    private double score;
    public Student(String name, int age, String sex, double score){
        super(name, age, sex);
        this.score = score;
    }
}
class GenericFunctional{
    //比较对象的大小                                   Comparable<Student>没有接口,但是继承了基类Comparable<Person>实现了接口
                           // compareTo(?   obj)
    public static <E extends Comparable<? super E>> boolean compareObject(E a, E b){
        return a.compareTo(b) > 0 ? true : false;
    }
    //main函数中添加代码,定义两个student对象和一个比较器对象,进行学生之间的自定义比较
    public static <E> boolean compareObject2(E a, E b, Comparator<? super E> c){   //利用比较器比较
        return c.compare(a, b) > 0 ? true : false;
    }
}
public class TestGenericDemo3 {
    //定义三个匿名对象,专门对age进行排序
    public static Comparator<Person> AGE_COMP = new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
        // TODO Auto-generated method stub
    return o1.age() > o2.age() ? 1 : (o1.age() == o2.age() ? 0 : -1);
        }
    };
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //生成两个Person对象,调用compareObject进行比较
        Person p1 = new Person("zhang", 20, "male");
        Person p2 = new Person("liu", 21, "female");
        System.out.println(GenericFunctional.compareObject(p1, p2));

        //生成两个Student对象,调用compareObject进行比较
        Student s1 = new Student("zhang", 20, "male", 98.5);
        Student s2 = new Student("zhang", 20, "male", 98.5);
        System.out.println(GenericFunctional.compareObject(p1, p2));

重点内容
三、泛型常见错误
(1)不能直接new泛型类型的对象 因为编译器不知道泛型类型T到底是什么类型? T a = new T();(即在使用时需给定类型)
(2)不能直接new泛型类型的数组,因为编译器不知道T是什么类型 ?T[] arr = new T[5]; => T[] array = (T[])new Object[5];
(3)static方法不能使用泛型类定义的泛型参数T呢?
因为static不需要对象来调用,是用类名来调用,而且类名调用不加参数类型,所以没法检测类型。
(4)不能定义泛型类的数组
GenericMath[] g3 = new GenericMath[5];
java的数组也是继承关系:
object[]是基类,因此object[]可以引用任何数组,就会出现数组中可以赋任意类型元素的错误。
所以在new数组是需类型强转:
T[] array=(T [] ) new object[[size]
(5)泛型代码需要检查需要制定上界?
public static int sumFunc3(T[] array){ }
(6)两个引用类型互相为继承关系,本来可以基类引用派生类对象的, 但是,该两个类型作为泛型类的实例化类型,互相是不能够引用的!


四、java的泛型通配符
(1)泛型通配符有上界也有界;
重点内容
通配符的上界是进行读,读取的类型是object类型;
通配符的下界是进行写,写入元素的形参类型写为通配符的下界;
不能用通配符定义对象;
(2)上界的应用:

public static int sumNumberStack(SqStack<? extends Number> stack){
        int size = stack.size();
        int sum = 0;
        for(int i=0; i<size; ++i){
            sum += stack.get(i).intValue();
        }
        return sum;
    }
}

(3)下界关键词super(意思是不能超过它,必须是它的基类
eg:

 SqStack <? super Number> s=new SqStack<object>();
可以看到<? super Number>意思是一个未知的类型,但该类型是Number的基类,也就是说Number是该类型的下限
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值