**Java泛型详解: 和Class的使用。 泛型类,泛型方法的详细使用实例**


一、 引入

1、 泛型是什么

ArrayList 就是泛型。那ArrayList能完成哪些想不到的功能呢?先看下面这段代码:

    ArrayList<String> strList = new ArrayList<String>();
    ArrayList<Integer> intList = new ArrayList<Integer>();
    ArrayList<Double> doubleList = new ArrayList<Double>();

这里构造了三个List分别装String、Integer和Double;这就是ArrayList的过人之处,既各种类型的变量都可以组装成对应的List。而不必针对每个类型分别实现一个构建ArrayList的类。下面看看如果没有泛型的话,我们要怎么做。

2、 没有泛型会怎样

先看下面这段代码:

我们实现两个能够设置点坐标的类,分别设置Integer类型的点坐标和Float类型的点坐标.

package cn.sakura.demo;

public class Interger {

    private Integer x;
    private Integer y;

    public Integer getX() {
        return x;
    }

    public void setX(Integer x) {
        this.x = x;
    }

    public Integer getY() {
        return y;
    }

    public void setY(Integer y) {
        this.y = y;
    }

    class FloatPoint {
        private Float x;
        private Float y;

        public Float getX() {
            return x;
        }

        public void setX(Float x) {
            this.x = x;
        }

        public Float getY() {
            return y;
        }

        public void setY(Float y) {
            this.y = y;
        }
    }

}

发现他们除了变量类型不一样,一个是Integer一个是Float以外,其他并没有是吗区别.下面将两个合成一个。因为Integer和Float都是派生自Object的,下面用代码演示:

package cn.sakura.demo;

public class ObjectPoint {
    private Object x;
    private Object y;

    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;
    }
}

既全部都用Object来代替所有的子类。

在使用的时候是这样:

        ObjectPoint integerPoint = new ObjectPoint();
        integerPoint.setY(new Integer(100));
        Integer integerX = (Integer) integerPoint.getX();

在设置的时候,使用new Integer(100)来创建一个Integer

        integerPoint.setY(new Integer(100));

然后在取值的时候,进行强制转换;

        Integer integerX = (Integer) integerPoint.getX();

由于在设置的时候,是设置的Integer所以在取值的时候,轻质转换是不会出错的。

同理,FloatPoint的设置和取值也是类似的,代码如下:

        ObjectPoint floatPoint = new ObjectPoint();
        integerPoint.setY(new Float(100,12f));
        Integer floatX = (Integer) floatPoint.getX();

如果改成下面这样也不会报错。

        ObjectPoint floatPoint = new ObjectPoint();
        integerPoint.setY(new Float(100,12f));
        String floatX = (String) floatPoint.getX();

强制转换时,因为编译器也不知道你传进去的是什么,而floatPoint.get()返回类型是Object,所以编译时,将Object强传成String事成立的。必然不会报错。

而在运行时,则不然,在运行时,floatPoint实例中期明明传进去的是Float类型的变量,非要把他强制转换成String类型,肯定会报类型转换的错误。

那有什么办法在编译阶段,既能合并成同一个,又能在编译时检查出来传回去类型不对呢?

当然,这就是泛型。

下面将对泛型的写法和做法一一讲解。

二、 各种泛型定义及使用

1、 泛型类定义及使用

先看看泛型的类是怎么定义的;

package cn.sakura.demo;

public class Point<T> {
    private T x;
    private T y;

    public T getX() {
        return x;
    }

    public void setX(T x) {
        this.x = x;
    }

    public T getY() {
        return y;
    }

    public void setY(T y) {
        this.y = y;
    }

    @Override
    public String toString() {
        return "Point{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }

    public static void main(String[] args) {
    
    //IntegerPoint使用  
        Point<Integer> pointInt = new Point<>();
        pointInt.setX(new Integer(100));
        System.out.println(pointInt.getX());
        
    //FloatPoint使用  
        Point<Float> floatPoint = new Point<>();
        floatPoint.setX(new Float(100.12f));
        System.out.println(floatPoint.getX());


    }

}

运行结果:

100
100.12

(1)、 定义泛型: Point

Point 既类名后面加一个尖括号,括号里是一个大写字母。这里写的是T,其实这个字母可以是任何大写字母,任何大写字母,意义相同。

(2)、 类中使用泛型

这个T表示派生自Object类的任何类,比如String,Integer,Double等等。这里要注意的是,T一定是派生于Object类的。为了方便起见,大家可以在这里把T当成String,既String在类中怎么使用,那T在类中就可以怎么用。下面是定义变量,作为返回值,作为参数传入的定义。

    //定义变量
    private T x;
    //作为返回值
    public T getX() {
        return x;
    }
    //作为参数
    public void setX(T x) {
        this.x = x;
    }

(3)、 使用泛型类

用法:

        Point<Integer> pointInt = new Point<>();
        pointInt.setX(new Integer(100));
        System.out.println(pointInt.getX());

        Point<Float> floatPoint = new Point<>();
        floatPoint.setX(new Float(100.12f));
        System.out.println(floatPoint.getX());

首先,是构造一个实例:

        Point<String> p = new Point<>();

这里与普通构造类实例的不同之点在于,普通类构造函数时这样的 Point p =new Point();

而泛型类的构造则需要在类名后添上,既一对尖括号,中间写上要传入的类型。

因为我们构造时,是这样的:class Point,所以在使用的时候也要在Point后加上类型来定义T代表的意义。

然后在getVar()和setVar() 时候就没有什么特殊的了,直接调用即可。

从上面的使用时,明显可以看出泛式的作用,在构造泛式的实例的时候:

        Point<Integer> pointInt = new Point<>();
        
        Point<Float> floatPoint = new Point<>();

尖括号中,你传进去的是什么,T就代表什么类型。这就是泛型的最大作用,我们只需要考虑逻辑实现,就能拿给各种类来用。

(4)、 使用泛型实现的优势

相比较开篇时使用Object的方式,又两个优点:

(4.1)、 不用强制转换

​ //使用Object作为返回值,要强制转化成指定类型

​ Float floatX = (Float)floatPoint.getX();

​ //使用泛型时,不用强制转换,直接出来就是String

​ System.out.println(p.getVar());

(4.2)、 在setX()如果传入类型不对,编译时会报错

​ 可以看出,当我们构造时使用的是String,而在setX时,传进去Integer类型时,就会报错,而不是像Object实现方式一样,在运行时才会报强制转换错误。

2、 多泛型变量定义及字母规范

(1)、 多泛型变量定义

上在我们只定义了一个泛型变量T,那如果我们需要传进去多个泛型呢?

只需要在类似下面这样就可以了;

class morePoint<T,U>{
}

也就是在原来的T后面用逗号隔开,多个就像下面这样:

class morePoint<T,U,A,C,B>{
}

举个例子,我们在Point上再加另一个字段name,也可泛型来表示,代码如下:

package cn.sakura.demo;

public class MorePoint<T, U> {

    private T x;
    private T y;

    private U name;

    public T getX() {
        return x;
    }

    public void setX(T x) {
        this.x = x;
    }

    public T getY() {
        return y;
    }

    public void setY(T y) {
        this.y = y;
    }

    public U getName() {
        return name;
    }

    public void setName(U name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "morePoint{" +
                "x=" + x +
                ", y=" + y +
                ", name=" + name +
                '}';
    }


    public static void main(String[] args) {
        MorePoint<Integer, String> morePoint = new MorePoint<Integer, String>();
        morePoint.setName("sakura");
        System.out.println(morePoint.getName());
    }


}

(2)、 字母规范

在定义泛型类时,我们已经提到用于指定泛型的变量是一个大写字母:

class Point<T>{  
 …………  
}  

其中任何大写字母都可以,他们的意义完全相同,但是为了提高可读性,大家默认在不同的情境下使用的字母意义如下:

  • E Element,常用在java,Collection里,如: List,lterator,Set
  • K,V Key,Value,代表Map的键值对
  • N Number,数字
  • T Type,类型,如String,Integer等等

3、 泛型接口定义及使用

在接口上定义泛型与在类中定义泛型是一样的,代码如下:

interface Info<T> {        // 在接口上定义泛型    
    public T getVar(); // 定义抽象方法,抽象方法的返回值就是泛型类型    

    public void setVar(T x);
}    

与泛型类的定义一样,也是在接口名后加尖括号;

(1)、 使用方法一:非泛型类

在使用的时候,就出现了问题,先看看下面的这个使用方法:

未完

转载原网址:

https://www.cnblogs.com/jpfss/p/9928747.html


The shortest way to do many things is to only one thing at a time.