一个类的成员变量,一个函数中的参数,都具有一种数据类型,可以为基本数据类型(如int
类型)或者引用类型(如Car
类型)。
假设我们想描述平面坐标的一个点,那么我们创建一个Point
类,这个类要包含表示X坐标和Y坐标的成员变量:
public class Point{
private int x;
private int y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
如果我们发现int
类型描述平面坐标上的点精度不够,希望换做double
类型,那么代码应该大部分是类似的,可是上面的代码我们却无法复用。我们只能再定义一个非常类似的DoublePoint
重新定义为:
public class DoublePoint{
private double x;
private double y;
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
}
能否只定义一个类就能满足坐标既可能为int
类型,也可能为double
类型的情况呢?如果可以的话将可以让代码更加通用,减少大量的重复代码。答案是肯定的,这个时候你需要泛型。
在使用泛型时,我们可以把类型作为参数传入到泛型类中。类似于把参数传入到方法中一样。我们来实现一个通用的泛型Point类:
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;
}
}
此时Point
成为了一个泛型类,T
是则是类型参数,T
具体是什么类型那要看程序运行的时候我们传入什么类型给他。
使用泛型类时,注意实际传入的类型参数不能是原生类型,必须是引用类型,因此如果希望传入int
类型的话,那么需要传入int
对应的包装类Interger
。对应地,double
类型则要传入包装类Double
。
public class Test{
public static void main(String[] args){
// 坐标为int类型,把int类型的包装类Integer作为参数传入泛型类中
Point<Integer> point1 = new Point<Integer>();
point1.setX(1);
point1.setY(1);
// 坐标为double类型,把double类型的包装类Double作为参数传入泛型类中
Point<Double> point2 = new Point<Double>();
point2.setX(3.456);
point2.setY(4.789);
}
}
Point<Integer>
基本等价于第一节中的Point
类,而Point<Double
>则基本等价于DoublePoint
类。
我们再举一个例子,我们定义一个容器类Container
,这个容器中可以存放各种类型的对象,可以使用泛型类实现这一特性。
public class Container<T> {
private T variable;
public Container () {
variable = null;
}
public Container (T variable) {
this.variable = variable;
}
public T get() {
return variable;
}
public void set(T variable) {
this.variable = variable;
}
public static void main(String[] args) {
Container<String> stringContainer = new Container<String>();
stringContainer.set("this is a string");
}
}
我们实例化Container对象时,只需设置它使用的类型,如:
Container<String> stringContainer = new Container<String>();
stringContainer.set("this is a string");
在下一节中,我们将学习到Java为我们提供的非常实用的容器类(也称之为集合类)。
泛型类支持多个类型参数。比方说我们需要实现一个三元组Triple
类,存储三个类型的变量,我们可以实现如下:
public class Triple<A, B, C> {
private A a;
private B b;
private C c;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
public C getC() {
return c;
}
public void setC(C c) {
this.c = c;
}
}
使用Triple
类的方式如下:
Triple<String, Integer, Float> triple = new Triple<String, Integer, Float>();
triple.setA("something");
triple.setB(1);
triple.setC(1.0f);
编译器会根据你的实例化代码以及泛型代码来生成运行时代码。
泛型也可以直接应用在一个方法中,不要求这个方法所属的类为泛型类。例如我们要获取一个对象的类名称:
public class Printer {
public static <T> void printArray(T[] objects) {
if (objects != null) {
for(T element : objects){
System.out.printf("%s",element);
}
}
}
public static void main(String[] args) {
Integer[] intArray = { 1, 2, 3, 4, 5 };
Character[] charArray = { 'T', 'I', 'A', 'N', 'M', 'A', 'Y', 'I', 'N', 'G' };
printArray(intArray);
printArray(charArray);
}
}
与泛型类不同的是泛型方法需要在方法返回值前用尖括号声明泛型类型名,这样才能在方法中使用这个标记作为返回值类型或参数类型。
登录发表评论 登录 注册
谢谢勘误

我们再举一个例子,我们定义一个容器类
Conatainer
,这个容器中可以存放各种类型的对象,可以使用泛型类实现这一特性。Container 不应该是 Conatainer 吧
最后一节最后一句“与泛型类的是”应该是“与泛型类不同的是”吧?
这句话能举个具体的例子吗?不太知道尖括号放在哪里。
@564778568 @阿弗莱克 谢谢你们的提醒,修改过来了。
这是笔误吧。
public Container<T>() { variable = null; }
构造器貌似不能带<T>啊 会报错
这里报错
笔误,谢谢提出,已经修改
Point<T>
Point<Double, Double> point2 = new Point<Double, Double>();
这里面不是只有一个类型T吗? 为什么new他时候传2个Double进去?