美文网首页
(三)什么是泛型

(三)什么是泛型

作者: 50e383299c68 | 来源:发表于2018-01-02 23:31 被阅读0次
    1. 第一部分:泛型说明

    泛型是Java SE1.5的新特性。
    泛型的本质是类型参数化。也就是操作的数据类型是个参数,不是确定的类型,在使用时指定。
    这种类型的参数可以用在类、接口、方法中,分别称为泛型类、泛型接口、泛型方法。
    Java引入泛型的好处是安全简单。在Java SE1.5之前,没有泛型的情况下,通过类型Object的使用,实现参数类型的任意化。“任意化”带来的缺点就是要做显示的强制类型转换。如果强制类型转换错误,编译器不会提示。在运行的时候才会出现异常,这是一个安全隐患。
    泛型的好处是编译的时候检查类型安全,并且所有的强制转换都是自动和隐藏的,提高代码的重用率。


    1. 泛型的代码示例:

    • 原始代码
    public class DoubleTest {
        public DoubleTest(Double var) {
            this.var = var;
        }
    
        public Double getVar() {
            return var;
        }
    
        public void setVar(Double var) {
            this.var = var;
        }
    
        private Double var;
    }
    
    public class StringTest {
        public StringTest(String var) {
            this.var = var;
        }
    
        public String getVar() {
            return var;
        }
    
        public void setVar(String var) {
            this.var = var;
        }
    
        private String var;
    }
    

    上面的类中,成员和方法的逻辑都一样,就是类型不一样,因此考虑重构。Object是所有类的父类,因此可以考虑用Object做为成员类型,这样就可以实现通用了,实际上就是“Object泛型”,暂时这么称呼。

    • 没有使用泛型
    public class WithoutGenerics {
        public WithoutGenerics(Object var) {
            this.var = var;
        }
    
        public Object getVar() {
            return var;
        }
    
        public void setVar(Object var) {
            this.var = var;
        }
    
        public void showTypeName() {
            System.out.println(String.format("参数实际类型是:%s", var.getClass().getSimpleName()));
        }
    
        private Object var;
    
        public static void main(String[] args) {
            WithoutGenerics w1 = new WithoutGenerics(1);
            w1.showTypeName();
            // 使用变量时,要显示进行强制类型转换。
            Integer var1 = (Integer)w1.getVar();
            System.out.println(String.format("参数值是:%s", var1));
    
            WithoutGenerics w2 = new WithoutGenerics("123");
            w2.showTypeName();
            // 使用变量时,要显示进行强制类型转换。
            String var2 = (String)w2.getVar();
            System.out.println(String.format("参数值是:%s", var2));
    
            WithoutGenerics w3 = new WithoutGenerics(w1);
            w3.showTypeName();
        }
    }
    

    在Java 5之前,为了让类有通用性,往往将参数类型、返回类型设置为Object类型,当获取这些返回类型来使用时候,必须将其“强制”转换为原有的类型,然后才可以调用对象上的方法。

    • 使用泛型

    强制类型转换很麻烦,需要事先知道各个Object具体类型是什么,才能做出正确转换。否则,要是转换的类型不对,比如将“Hello Generics!”字符串强制转换为Double,那么编译的时候不会报错,可是运行的时候就挂了。那有没有不强制转换的办法----有,改用 Java5泛型来实现。

    public class WithGenerics <T> {
        public WithGenerics(T var) {
            this.var = var;
        }
    
        public T getVar() {
            return var;
        }
    
        public void setVar(T var) {
            this.var = var;
        }
    
        public void showTypeName() {
            System.out.println(String.format("参数的实际类型:%s", var.getClass().getSimpleName()));
        }
    
        private T var;
    
        public static void main(String[] args) {
            WithGenerics<Integer> w1 = new WithGenerics<>(Integer.valueOf(1));
            w1.showTypeName();
            // 1. 使用变量时,不需要显示进行强制类型转换。
            Integer var1 = w1.getVar();
            System.out.println(String.format("参数值是:%s", var1));
    
            WithGenerics<String> w2 = new WithGenerics<>("11234");
            w2.showTypeName();
            // 2. 使用变量时,不需要显示进行强制类型转换。
            String var2 = w2.getVar();
            System.out.println(String.format("参数值是:%s", var2));
            // 3. 如果没有声明实际的参数类型
            // 使用变量时,需要显示进行强制类型转换。
            WithGenerics w4 = new WithGenerics<>(Long.valueOf(123));
            w4.showTypeName();
            Object w4Var = w4.getVar();
        }
    }
    

    使用<T>来声明一个类型持有者名称,然后就可以把T当作一个类型代表来声明成员、参数和返回值类型。T仅仅是个名字,这个名字可以自行定义。
    class WithGenerics<T> 声明了一个泛型类,这个T没有任何限制,实际上相当于Object类型,实际上相当于 class WithGenerics<T extends Object>。
    与Object泛型类相比,使用泛型所定义的类在声明和构造实例的时候,可以使用“<实际类型>”来一并指定泛型类型持有者的真实类型。类如WithGenerics<Long> w4 = new WithGenerics<>(Long.valueOf(123));
    当然,也可以在构造对象的时候不使用尖括号指定泛型类型的真实类型,但是你在使用该对象的时候,就需要强制转换了。比如:WithGenerics w4 = new WithGenerics<>(Long.valueOf(123));
    实际上,当构造对象时不指定类型信息的时候,默认会使用Object类型,这也是要强制转换的原因。


    1. 泛型的语法限制

    • 泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
    • 泛型的类型参数可以有多个。
    • 泛型的参数类型可以使用extends语句。例如<T extends superClass>。习惯称为“有界类型”。
    • 泛型的类型参数可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String");

    通过上面的说可以说明第二篇文章(http://www.jianshu.com/writer#/notebooks/20714250/notes/22009385)中的改写为什么没有效果。自定义T类型,相当于 T extends Object。所有的类型都继承自Object。所以编译器检查类型时没有问题。

    相关文章

      网友评论

          本文标题:(三)什么是泛型

          本文链接:https://www.haomeiwen.com/subject/tokcnxtx.html