1.元组
创建一个对象,用它来持有想返回的多个对象,这个概念称为元组。
它是将一组对象直接打包存储于其中的一个单一对象,这个容器对象允许读取其中元素,但是不允许向其中存放新的对象。(这个概念也称为数据传递对象)。
通常,元组可以具有任意长度,同时,元组中的对象可以是任意不同的类型。
/**
* @Author ZhangGJ
* @Date 2020/11/28 07:48
*/
public class TwoTuple<A, B> {
public final A first;
public final B second;
public TwoTuple(A a, B b) {
first = a;
second = b;
}
@Override
public String toString() {
return "(" + first + ", " + second + ")";
}
}
2.泛型类、方法
当使用泛型类时,必须在创建对象的时候指定类型参数的值,而使用泛型方法的时候,通常不必指明参数类型,因为编译器会为我们找出具体的类型,这称为类型参数推断。
3.擦除
考虑如下情况:
public class ErasedTypeEquivalence {
public static void main(String[] args) {
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);
}
}
Result:
true
你可能很疑惑为什么是true,没错,在泛型代码内部,无法获得任何有关泛型参数类型的信息。
Java泛型是使用擦除来实现的,这意味着当你在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象,因此List<String>
和List<Integer>
在运行时实际上是相同的类型,这两种形式都被擦除成为它们的“原生”类型,即List。
4.边界
如下代码无法编译:
/**
* @Author ZhangGJ
* @Date 2020/11/28 08:27
*/
class Manipulator<T> {
private T obj;
public Manipulator(T x) {
obj = x;
}
/**
* Error: cannot find symbol: method f():
*/
public void manipulate() {
// obj.f(); // error!
}
}
public class Manipulation {
public static void main(String[] args) {
HasF hf = new HasF();
Manipulator<HasF> manipulator = new Manipulator<HasF>(hf);
manipulator.manipulate();
}
}
由于有了擦除,Java编译器无法将manipulate()
方法必须能够在obj上调用f()
这一需求映射到HasF拥有f()
这一事实,为了能够调用f()
,我们必须协助泛型类,给定泛型类的边界,代码如下:
/**
* @Author ZhangGJ
* @Date 2020/11/28 08:36
*/
public class Manipulator2<T extends HasF> {
private T obj;
public Manipulator2(T x) {
obj = x;
}
public void manipulate() {
obj.f();
}
}
边界<T extends HasF>
声明T
必须具有类型HasF
或者从HasF
导出的类型。
泛型类型参数将擦除到它的第一个边界。
interface HasColor {
Color getColor();
}
class Colored<T extends HasColor> {
T item;
Colored(T item) {
this.item = item;
}
T getItem() {
return item;
}
java.awt.Color color() {
return item.getColor();
}
}
class Dimension {
public int x, y, z;
}
class ColoredDimension<T extends Dimension & HasColor> {
T item;
ColoredDimension(T item) {
this.item = item;
}
T getItem() {
return item;
}
java.awt.Color color() {
return item.getColor();
}
int getX() {
return item.x;
}
int getY() {
return item.y;
}
int getZ() {
return item.z;
}
}
interface Weight {
int weight();
}
class Solid<T extends Dimension & HasColor & Weight> {
T item;
Solid(T item) {
this.item = item;
}
T getItem() {
return item;
}
java.awt.Color color() {
return item.getColor();
}
int getX() {
return item.x;
}
int getY() {
return item.y;
}
int getZ() {
return item.z;
}
int weight() {
return item.weight();
}
}
class Bounded extends Dimension implements HasColor, Weight {
@Override
public Color getColor() {
return null;
}
@Override
public int weight() {
return 0;
}
}
/**
* @Author ZhangGJ
* @Date 2020/11/28 09:38
*/
public class BasicBounds {
public static void main(String[] args) {
Solid<Bounded> solid = new Solid<Bounded>(new Bounded());
solid.color();
solid.getY();
solid.weight();
}
}