**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
(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
然后在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)、 使用方法一:非泛型类
在使用的时候,就出现了问题,先看看下面的这个使用方法:
未完