资讯专栏INFORMATION COLUMN

java表示泛型的方法

hosition / 951人阅读

摘要:使用表示泛型中的基本思想就是可以通过使用像这样适当的超类来实现泛型类。请看例子使用实现泛型使用接口类型表示泛型当有多个类要在一个通用的方法里表示泛型时,来表示可能就显得捉襟见肘了,因为这个时候无法明确的知道用户到底需要拆箱为哪种类。

1.1 使用Object表示泛型
Java中的基本思想就是可以通过使用像Object这样适当的超类来实现泛型类。--《数据结构与算法分析 Java语言描述》

文中的超类也就是父类的意思。
使用Object这样特殊的类来实现泛型是用到了Object是所有类的父类这个基本思想,但是这种实现方法带来了两个问题:

1. 没有覆盖基本类型,因为基本类型不是引用类型,所以不能用类表示基本类型,因此Object不是基本类型的父类
2. 在使用泛型后的对象时需要强制转换,如果强转失败了也不会在编译时报错,只会在运行时报强转失败ClassCastException

这样Object在实际使用中就不是一个非常完美的实现泛型的一个方法,但是提供了一个实现泛型的基本思想,就是通过父类来实现泛型。请看例子

/**
 * 使用Object实现泛型
 */
public class ObjectGeneric {

    private Object storedValue;

    public Object read(){
        return storedValue;
    }

    public void write(Object value){
        storedValue = value;
    }

    public static void main(String[] args) {
        ObjectGeneric objectGeneric = new ObjectGeneric();
        objectGeneric.write("23");
        String val = (String)objectGeneric.read();
        System.out.println(val);
    }
}
1.2 使用接口类型表示泛型

当有多个类要在一个通用的方法里表示泛型时,Object来表示可能就显得捉襟见肘了,因为这个时候无法明确的知道用户到底需要拆箱为哪种类。例如,String和Shape类的数组要用同一个findMax函数来找出最大的元素,这时在实现findMax的时候可能需要随时要判断入参的类型,这对于泛型的意义(减少代码量)来说是毁灭性的。
因此这个时候需要找到String和Shape类的共同之处,抽象出一个接口,并在findMax里面用作入参来替代直接传入String或Shape类。findMax的核心在于元素间的比较,在jdk中有一个接口java.lang.Comparable是满足findMax需求的。
首先,定义一个实现了Comparable接口的抽象类Shape

public abstract class Shape implements Comparable{
    protected Double area;
    @Override
    public int compareTo(Object o) {
        Shape shape = (Shape)o;
        return area.compareTo(shape.getArea());
    }

    public Double getArea() {
        return area;
    }

    public void setArea(Double area) {
        this.area = area;
    }
}

然后派生出两个具体的Shape子类:Square,Circle

public class Square extends Shape{
    public Square(double len){
        area = len*len;
    }
}
public class Circle extends Shape{
    public Circle(double radius){
        area = radius*radius*3.14;
    }
}

最后是findMax函数

import static com.google.common.base.Preconditions.checkArgument;
public class InterfaceGeneric {
    public static void main(String[] args) {
        Shape[] sh = {
                new Circle(3.0),
                new Square(3.0)
        };
        String[] str = {
                "John",
                "Benjamin",
                "Steve"
        };
        Comparable[] comparables = {
                new Circle(3.0),
                "Benjamin"
        };
        System.out.println(findMax(sh));
        System.out.println(findMax(str));
        System.out.println(findMax(comparables));
    }

    public static Comparable findMax(Comparable[] arr){
        checkArgument(arr.length>0);
        int max = 0;
        for(int i = 0 ;i0){
                max = i;
            }
        }
        return arr[max];
    }
}

在findMax函数中,因为已知入参是实现了Comparable接口的类,因此可以不用转换直接使用compareTo函数,这是利用了接口的特性来实现的泛型。
System.out.println(findMax(comparables))会抛出ClassCastException异常,这是因为在compareTo中拆箱时无法将String类强转为Shape类导致的。
以上两种方式都存在编译不会报错,但是会在运行时报错的问题,这样就导致程序是不可控的,因为无法提前预知程序哪里会抛RuntimeException,所以需要一种泛型方法来强制使得异常能够出现在编译阶段而不是运行时。

1.3 利用Java5泛型特性实现泛型构件

在java5中引入了泛型类的概念,通过<>运算符实现泛型。将第一个例子用<>运算符实现如下:

public class DiamondGeneric {
    private AnyType storedValue;

    public AnyType read(){
        return storedValue;
    }

    public void write(AnyType value){
        storedValue = value;
    }

    public static void main(String[] args) {
        DiamondGeneric val = new DiamondGeneric<>();
        val.write("this is a test");
        System.out.println(val.read());
    }
}

在这里DiamondGeneric操作限制read,write函数入参出参的类型只能为String,避免了运行时强转带来的Exception。
在这里还用到了Java7增加的一种新的语言特性,菱形运算符:new DiamondGeneric<>(),在前面已经指定AnyType为String,因此在后面不必再指定类型。

1.4 带有限制的通配符

想一种复杂的状况,如果一个接口的多态实现需要在一个通用方法做同样的操作,例如,Shape接口有一个area方法,有一个实现Circle,一个实现Square,需要一个findAreaCount来计算出Shape集合的面积总数,那么需要在<>里面加入怎样的限制才能做到?
答案是Collection

public class DiamondInterfaceGeneric {
    public static void main(String[] args) {
        List sh = new ArrayList();
        sh.add(new Circle(3.0));
        sh.add(new Square(3.0));
        System.out.println(totalArea(sh));
    }

    public static double totalArea(Collection arr){
        double total = 0;
        for(Shape s : arr){
            if(s!=null)
                total+= s.getArea();
        }
        return total;
    }
}
1.5 类型限界

在考虑一个更加极端的状况,Comparable是泛型的,指定的类型为Shape,也即Comparable,同时Shape继承了Comparable,也存在Square类或Circle类实现了Shape接口,那么这时候该如何表示Square extends Comparable或Circle extends Comparable这种类呢?
答案是AnyType extends Comparable

public abstract class ShapeGeneric implements Comparable{
    protected Double area;
    @Override
    public int compareTo(ShapeGeneric o) {
        return area.compareTo(o.area);
    }

    public Double getArea() {
        return area;
    }

    public void setArea(Double area) {
        this.area = area;
    }
}
public class CircleGeneric extends ShapeGeneric{
    public CircleGeneric(double radius){
        area = radius*radius*3.14;
    }
}
public class SquareGeneric extends ShapeGeneric{
    public SquareGeneric(double len){
        area = len*len;
    }
}
public class ComplexInterfaceGeneric {
    public static void main(String[] args) {
        ShapeGeneric[] sh = {
                new CircleGeneric(3.0),
                new SquareGeneric(3.0)
        };
        System.out.println(findMax(sh));
    }

    public static > AnyType findMax(AnyType[] arr){
        checkArgument(arr.length>0);
        int max = 0;
        for(int i = 0 ;i0){
                max = i;
            }
        }
        return arr[max];
    }
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76322.html

相关文章

  • Java泛型

    摘要:虚拟机中并没有泛型类型对象,所有的对象都是普通类。其原因就是泛型的擦除。中数组是协变的,泛型是不可变的。在不指定泛型的情况下,泛型变量的类型为该方法中的几种类型的同一个父类的最小级,直到。 引入泛型的主要目标有以下几点: 类型安全 泛型的主要目标是提高 Java 程序的类型安全 编译时期就可以检查出因 Java 类型不正确导致的 ClassCastException 异常 符合越早出...

    woshicixide 评论0 收藏0
  • java的集合和型的知识点归纳1

    摘要:接口也是集合中的一员,但它与接口有所不同,接口与接口主要用于存储元素,而主要用于迭代访问即遍历中的元素,因此对象也被称为迭代器。迭代器的实现原理我们在之前案例已经完成了遍历集合的整个过程。 【Collection、泛型】 主要内容 Collection集合 迭代器 增强for 泛型 教学目标 [ ] 能够说出集合与数组的区别 [ ] 说出Collection集合的常用功能 [ ]...

    daryl 评论0 收藏0
  • Java系列之泛型

    摘要:总结泛型的类型必须是引用类型,不能是基本类型,泛型的个数可以有多个,可以使用对创建对象时的泛型类型以及方法参数类型进行限制,如使用关键字和对泛型的具体类型进行向下限制或向上限制,最后一点,可以声明泛型数组,但是不能创建泛型数组的实例。 自从 JDK 1.5 提供了泛型概念,泛型使得开发者可以定义较为安全的类型,不至于强制类型转化时出现类型转化异常,在没有反省之前,可以通过 Object...

    MadPecker 评论0 收藏0
  • JAVA泛型笔记

    摘要:泛型类泛型类和普通类的区别就是类定义时,在类名后加上泛型声明。泛型类的内部成员方法就可以使用声明的参数类型。 泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type),即所操作的数据类型在定义时被指定为一个参数。当我们使用的时候给这个参数指定不同的对象类型,就可以处理不同的对象。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和...

    n7then 评论0 收藏0
  • Java泛型总结

    摘要:静态变量是被泛型类的所有实例所共享的。对于这个类型系统,有如下的一些规则相同类型参数的泛型类的关系取决于泛型类自身的继承体系结构。在代码中避免泛型类和原始类型的混用。参考泛型类型擦除 Java泛型总结 Java泛型是JDK5引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter)。声明的类型参数在使用的时候使用具体的类型来替换。泛型最主要的应用是在JDK5...

    CoreDump 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<