目录
一、自定义泛型的设计
1.泛型类
2.泛型方法
3.泛型接口
二、泛型类型的限定
三、泛型实现的本质和约束
1.本质:
2.约束:
四、java类型的协变和逆变
1.java数组是协变的
2.java的(原始的)泛型是不变的
3.java数据变化。
就是比如之前我们使用list的时候,list
泛型类:ArrayList,HashSet,HashMap等
泛型方法:Collections.binarySearch,Arrays,sort等
泛型接口:List,Iterator等
查看示例,发现这些泛型后都有<>包括的结构:
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
public class NoClassCast {
public static void main(String[] args) {
//ArrayList支持泛型
// 限定了list只能存放字符串
ArrayList list = new ArrayList();
list.add("1583");
list.add("153");
list.add("456");
list.add("153");
list.add("789");
String a1 = list.get(1);
for(String o:list)
{
System.out.println(o);
}
//Java 7 菱形语法
//限定存储Integer
ArrayList list2 = new ArrayList();
list2.add(123);
list2.add(456);
list2.add(789);
int a2 = list2.get(1);
//Collections.binarySearch方法支持泛型
int pos1 = Collections.binarySearch(list, "456");
int pos2 = Collections.binarySearch(list2, 456);
System.out.println(pos1+" "+pos2);
HashSet set1 = new HashSet<>();
set1.add(1.23);
set1.add(4.56);
set1.add(7.89);
//Iterator接口支持泛型
Iterator iter = list.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
Iterator iter2 = set1.iterator();
while(iter2.hasNext()){
System.out.println(iter2.next());
}
}
}
在类名后用
public class Interval {
private T lower;
private T upper;
public Interval(T lower, T upper) {
this.lower = lower;
this.upper = upper;
}
public T getLower() {
return lower;
}
public void setLower(T lower) {
this.lower = lower;
}
public T getUpper() {
return upper;
}
public void setUpper(T upper) {
this.upper = upper;
}
}
泛型类的调用:
在修饰符后,返回类型前加入
public static Interval getReverse(Interval interval){
return new Interval(interval.getUpper(), interval.getLower());
}
在接口类名后加
public interface Calculator {
public T add(T operand1, T operand2);
}
package genericinterface;
public class IntegerCalculator
implements Calculator {
public Integer add(Integer operand1, Integer operand2) {
return operand1 + operand2;
}
public static void main(String[] args)
{
IntegerCalculator c1 = new IntegerCalculator();
System.out.println(c1.add(1,2));
Calculator c2 = new IntegerCalculator();//实例化子类对象转化为父类对象
System.out.println(c2.add(1,2));
}
}
备注:
注意:两个泛型类之间的继承关系和两个
泛型类的通配符:
上限界定符,如:Pair extends S>,表示能接收的类型时S自身或它的子类。
下限界定符:如:Pair super S>,表示能接受的类型是S自身或它的超类。
在JVM里没有泛型对象,而是采用类型擦除技术。
擦除之后,为了保证安全性,需要自动进行类型转换。
重载泛型方法,会利用自动桥方法进行翻译(只需理解子类对象优先调用子类方法,子类转化的父类也优先调用子类方法)。
类型变换关系:更复杂类型的子类型关系,与子类型之间 的关系相关联。
父类=子类实例是编译正确的,所以利用等后是否出现编译错误来判断属于什么形式化定义。
class A {
} // 第一代
class B extends A {
} // 第二代
class C extends B {
} // 第三代
public static void testArray() {
B[] array1 = new B[1];
array1[0] = new B();
A[] array2 = array1;
try {
array2[0] = new A();
// compile ok, runtime error
} catch (Exception ex) {
ex.printStackTrace();
}
try {
array2[0] = new C();
// compile ok, runtime ok
} catch (Exception ex) {
ex.printStackTrace();
}
}
jdk4重写要求方法参数和返回值一样。
jdk5+重写方法,参数要求一样,返回值协变的。
class Father
{
public B f1(B obj)
{
System.out.println("Father.f1()");
return new B();
}
}
class Son extends Father
{
public B f1(B obj)
//public C f1(B obj) //返回值是C,也是对的 但是在jdk4中是错误的
{
System.out.println("Son.f1()");
return new C();
}
}
public class MethodTest {
public static void main(String[] args) {
Father foo = new Son();
foo.f1(new B());
}
}
参考中国大学mooc《java核心技术》