搜索
写经验 领红包
 > 影视

java泛型的实现原理(java中的泛型指的是什么)

导语:Java进阶知识,轻松理解Java泛型

在学习泛型之前我们先回顾下Java的数据类型以及涉及到的一些概念。

Java数据类型

Java的两大数据类型分为基础类型和引用类型。基本类型的数值不是对象,不能调用对象的toString()、hashCode()、getClass()、equals()等方法。

自动装箱

把基本类型用它们对应的引用类型包装起来,使它们具有对象的特质,可以调用toString()、hashCode()、getClass()、equals()等方法。

例如:

//自动装箱Integer i=1;

而实际上编译器会调用static Integer valueOf(int i)这个方法,返回一个表示指定int值的Integer对象。Integer i=1; ->. Integer i=Integer.valueOf(1);

拆箱

跟自动装箱的方向相反,将引用类型转换为基本类型。

//拆箱int i = new Integer(1);

自动装箱和拆箱是由编译器来完成的,编译器会在编译期根据语法决定是否进行装箱和拆箱动作。

假如我们定义一个类来表示坐标,要求类中基础类型可以为整数 、小数、字符串,例如:

Object x=116,y=54;Object x=116.92,y=54.31;Object x=,y=;

我们知道,基本数据类型可以自动装箱,被转换成对应的包装类。Object 是所有类的祖先类,任何一个类的实例都可以向上转型为 Object 类型,例如:

int -> Integer -> Objectdouble -> Double -> ObjectString -> Object

泛型的使用

如果要取出坐标值就需要向下转型,向下转型存在着风险,而且编译期间不容易发现,只有在运行期间才会抛出异常,所以要尽量避免使用向下转型。例如下面的实例:

public class Test {    public static void main(String[] args){        Point point = new Point();        //int -> Integer -> Object        point.setX(116);        point.setY(54);        //向下转型        int x = (Integer) point.getX();        int y = (Integer) point.getY();        System.out.println(+x++y);        //double -> Double -> Object        point.setX(116.92);        point.setY();        //向下转型        Double x1 = (Double) point.getX();        //会抛出ClassCastException异常        Double y1 = (Double) point.getY();        System.out.println(+x1++y1);    }}class Point{    Object x = null;    Object y = null;    public Object getX() {        return x;    }    public void setX(Object x) {        this.x = x;    }    public Object getY() {        return y;    }    public void setY(Object y) {        this.y = y;    }}

那么Java中如何避免这样的情况发生呢?

Java中泛型出现就是解决出现这样的问题,所谓的“泛型”就是任意的数据类型。以下代码将利用泛型解决上面的问题。

public class Test {    public static void main(String[] args){        //实例化泛型        Point<Integer,Integer> point = new Point<Integer,Integer>();        point.setX(116);        point.setY(54);        int x = point.getX();        int y =  point.getY();        System.out.println(+x++y);        Point<Double,String> point1 = new Point<Double,String>();        point1.setX(116.92);        point1.setY();        Double x1 =  point1.getX();        String y1 = point1.getY();        System.out.println(+x1++y1);    }}//定义泛型类class Point<T1,T2>{    T1 x = null;    T2 y = null;    public T2 getY() {        return y;    }    public void setY(T2 y) {        this.y = y;    }    public T1 getX() {        return x;    }    public void setX(T1 x) {        this.x = x;    }}

实例中的T1和T2叫类型参数,类型参数是用来表示自定义标识符,用来传递数据的类型。Java中传值参数用小括号包围,泛型参数用尖括号包围,多个参数用逗号间隔,例如:

<T>或<T,E>

类型参数需要在类名后面给出。一旦给出了类型参数,就可以在类中使用了。类型参数必须是一个合法的标识符,习惯上使用单个大写字母,通常情况下,K 表示键,V 表示值,E 表示异常或错误,T 表示一般意义上的数据类型。

泛型类在实例化时必须指出具体的类型,也就是向类型参数传值,格式为:

className variable<dataType1, dataType2> = new className<dataType1, dataType2>();

也可以省略等号右边的数据类型,但是会产生警告,即:

className variable<dataType1, dataType2> = new className();

泛型的优点:使用泛型类时指明了数据类型,赋给其他类型的值会抛出异常,既不需要向下转型,也没有潜在的风险。

除了定义泛型类,还可以定义泛型接口和泛型方法,使用泛型方法时不必指明参数类型,编译器会根据传递的参数自动查找出具体的类型。

限制泛型的可用类型

通过 extends 关键字可以限制泛型的类型

public <T extends Number> T getMax(T array[]){    T max = null;    for(T element : array){        max = element.doubleValue() > max.doubleValue() ? element : max;    }    return max;}

<T extends Number> 表示 T 只接受 Number 及其子类,传入其他类型的数据会报错。这里的限定使用关键字 extends,后面可以是类也可以是接口。但这里的 extends 已经不是继承的含义了,应该理解为 T 是继承自 Number 类的类型。

本文内容由小苹整理编辑!