java中泛型的秘密—Java中的泛型

泛型的引入

我们为什么需要泛型?

任何工具的产生都是离不开实际需求,凡是存在的必定是合理的,如果想知道泛型是什么,泛型这个概念为什么会出现,我们就让程序处于一个没有泛型的代码世界中,通过引入泛型前后程序的优劣的比较,从而明白泛型的作用和意义。 

请在不使用泛型的情况下完成下列要求:

设计一个类,类里面有一个数组,这个数组可以存储任意的类型的值,根据成员方法getvalue()  和  setvalue()  获得和设置数组对应下标的值。

思路: 

我们都知道Object类是所有类的父类,我们在多态的章节中学习过,子类可以进行向上转型到父类,那么如果父类是Object类,就可以进行所有类的存储了,换句话说,建立一个Object类的数组,用此数组进行不同类型的值的存储就可以了。废话不多说,直接上代码

class All_data_types{
    Object[] objects = new Object[10];
    public All_data_types(){}

    public void setObjects(int pose, Object value) {
        this.objects[pose] = value;
    }

    public Object getObjects(int pose) {
        return objects[pose];
    }
}

public class Main {
    public static void main(String[] args) {
        All_data_types all_data_types = new All_data_types();
        all_data_types.setObjects(0, "hello");
        all_data_types.setObjects(1,23);
        all_data_types.setObjects(2,true);
        System.out.println(all_data_types.getObjects(0));
        System.out.println(all_data_types.getObjects(1));
        System.out.println(all_data_types.getObjects(2));
        String str = all_data_types.getObjects(0);//编译报错
    }
}

 由此可以看到程序的问题,首先就是不能用具体的变量类型来接收,因为子类可以转型为父类,但是父类不能转型为子类,这样的话就必须进行强制类型转换,这样的代码在交给客户端的时候极易出现错误。

并且我们做软件开发不可能这样写的,因为这样的维护成本及其的高,因为我们要输入的数据类型的不同,所以我们需要手动的一个一个的进行输入,会大大的增加程序员的工作量,而且需要改变数据类型的时候我们也需要一个一个的改变,因此,我们迫切的需要一种统一的,能对数据类型进行整合的一个新的工具

泛型

更多情况下,我们还是希望一个容器只能够持有一种数据类型。而不是同时持有这么多类型。所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译器去做检查。此时,就需要把类型,作为参数传递。

写一个泛型类 My_Gener

class My_Gener<T>{
    public T[] my_gen =(T[]) new Object[10];//现阶段这样写,之后不要这样写
    public void setMy_gen(int pose, T value){
        this.my_gen[pose] = value;
    }
    public T getMy_gen(int pose){
        return this.my_gen[pose];
    }
}

public class Main {
    public static void main(String[] args) {
        My_Gener<Integer> my_gener = new My_Gener<>();
        my_gener.setMy_gen(0, 15);
        my_gener.setMy_gen(1, 23);
        System.out.println(my_gener.getMy_gen(0));
        System.out.println(my_gener.getMy_gen(1));
    }
}


用泛型所存在的两个优点,第一个就是在存放元素的时候,不再会进行类型的检查,第二个就是在取出的时候会自动地帮我们进行类型的转换,也就是用进行类型的强制类型转换了,而这两布都是在编译的时候进行完成的,运行的时候是没有泛型的概念的,这种概念其实就是泛型中的擦除机制。

擦除机制

这里引入一个知乎上的文章:https://zhuanlan.zhihu.com/p/51452375

擦除机制可以理解为把T都擦除成为了Object,那么如果是这样,我们下面这段代码为什么会出错?

class My_Gener<T>{
    public T[] my_gen =new T[10];
    public void setMy_gen(int pose, T value){
        this.my_gen[pose] = value;
    }
    public T getMy_gen(int pose){
        return this.my_gen[pose];
    }
    public T[] getT_(){
        return my_gen;
    }
}

public class Main {
    public static void main(String[] args) {
        My_Gener<Integer> my_gener = new My_Gener<>();
        Integer integer = my_gener.getT_();
    }
}

在汇编中,在上述的setMy_gen方法中,传入的值是T类型和int类型的,但是在get方法中return的值返回的其实是一个Object类型的,在没学过汇编的同学中,大家可以简单理解为在运行的时候,T这一概念已经消失,反而被擦除成为了Object类就可以了

所以,上面的这一行代码,之所以是错误的,是因为被擦除成Object类之后,返回值也是Object,因此就不能用具体的类,比如Integer类来接收,就必须强制类型转换,否则就会报错。

因此把第一行代码改为:

public T[] my_gen =(T[])new Object[10];

手动添加一个强制类型的转换,就会编译通过。

泛型的上界

我们现在要实现一个可以用来比较的泛型类

找出元素中的最大值:

class Person implements Comparable<Person> {
    public String name;
    public int age;
    public Person(){
        this.name = "nobody";
        this.age = 0;
    }
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Person o) {
        return this.name.compareTo(o.name);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

class Alg<T extends Comparable<T>>{
    public T find_Max(T[] arrays){
        T max = arrays[0];
        for(int i = 0; i < arrays.length; i++){
            if(max.compareTo(arrays[i]) < 0){
                max = arrays[i];
            }
        }
        return max;
    }
}

public class Main {
    public static void main(String[] args) {
        Alg<Person> alg = new Alg<>();
        Person[] peoples = {new Person("zhangsan", 13)
                , new Person("lisi", 34)
                , new Person("wangwu", 22)
                , new Person("zhouermazi", 43)};
        Person person = alg.find_Max(peoples);
        System.out.println(person);
    }
}

Alg中的上界就是泛型T继承了Comparable,因此如果Person想要用Alg中的find_Max方法就也需要继承Comparable方法进行重写。

泛型方法

静态泛型方法

静态泛型方法的定义:


class Alg{
    public static<T extends Comparable<T>> T find_Max(T[] arrays){
        T max = arrays[0];
        for(int i = 0; i < arrays.length; i++){
            if(max.compareTo(arrays[i]) < 0){
                max = arrays[i];
            }
        }
        return max;
    }
}

public class Main {
    public static void main(String[] args) {
        Person[] peoples = {new Person("zhangsan", 13)
                , new Person("lisi", 34)
                , new Person("wangwu", 22)
                , new Person("zhouermazi", 43)};
        Person person = Alg.<Person>find_Max(peoples);
        System.out.println(person);
    }
}

这个Alg类就是普通类,而静态方法就是泛型方法,泛型方法中定义的泛型占位符和泛型类定义的占位符是不冲突的,泛型方法的占位符优先级最高。

泛型方法只需要把静态泛型方法的static去掉就可以了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值