泛型的主要目的之一就是用来指定容器要持有什么类型的对象,而且由编译器来来保证正确性。
// 类型参数T
public class Holder3 {
private T t;
public Holder3(T a) {
this.t = a;
}
public void set(T a){
this.t = a;
}
public T get() {
return t;
}
public static void main(String[] args) {
Holder3 h2 = new Holder3(new Automobile());
Automobile a = (Automobile) h2.get();
}
}
使用类型参数T可以暂时不指定类型,在创建对象时必须指明类型。
/**
* 元组持有数据
* @author Administrator
*
*/
public class TwoTuple {
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. 一个堆栈类
// 自定义堆栈
public class LinkedStack {
private static class Node {
U item;
Node next;
Node() {
item = null;
next = null;
}
Node(U item,Node next){
this.item = item;
this.next = next;
}
boolean end(){
return item == null && next == null;
}
}
private Node top = new Node();
public void push(T item){
top = new Node(item, top);
}
public T pop(){
T result = top.item;
if(!top.end()){
top = top.next;
}
return result;
}
public static void main(String[] args) {
LinkedStack s = new LinkedStack();
for (String string : "Phasers on stun!".split("")) {
s.push(string);
}
Print.print(s.pop());
}
}
使用了末端哨兵来判断堆栈是否为空。
3. RandomList
泛型也可用于接口。
public interface Generator {
T next();
}
泛型接口应用:
生成器利用工程模式生成对象。
利用适配器模式可以实现迭代功能。
使用泛型了时,在创建对象时必须指明类型参数;使用泛型方法时,不必指明参数类型。编译器会找出具体的类型,被称为参数推断。
定义泛型方法,只需将泛型参数列表置于返回值之前。
//泛型方法
public void f(T t) {
System.out.println(t.getClass().getName());
}
//可变参数与泛型方法可以很好的共存
public class GenericVarargs {
public static List makeList(T... args) {
List result = new ArrayList();
for (T t : args) {
result.add(t);
}
return result;
}
public static void main(String[] args) {
List list = makeList("A");
System.out.println(list);
list = makeList("A","B","C");
System.out.println(list);
}
}
class Frob{}
class Fnorkle{}
class Quark{}
class Practice{}
public class LostInformation {
public static void main(String[] args) {
List list = new ArrayList();
Map map = new HashMap();
Quark quark = new Quark();
Practice practice = new Practice();
System.out.println(Arrays.toString(list.getClass().getTypeParameters()));
System.out.println(Arrays.toString(map.getClass().getTypeParameters()));
System.out.println(Arrays.toString(quark.getClass().getTypeParameters()));
System.out.println(Arrays.toString(practice.getClass().getTypeParameters()));
}
}
输出:
[E]
[K, V]
[Q]
[POSITION, MOMENTUM]
在泛型代码内部,无法获得任何有关泛型参类型的信息。
擦除的代价是:泛型不能显式地应用运行时类型操作。因为所有参数 类型信息都丢失了。
泛型擦除无法在运行时获取类型信息,可以通过传入类型解决。
/**
* 通过传入Class获取类型
* @author Administrator
*/
class Building{}
class House extends Building{}
public class ClassTypeCapture {
Class kind;
public ClassTypeCapture(Class kind) {
this.kind = kind;
}
public boolean f(Object arg) {
return kind.isInstance(arg);
}
public static void main(String[] args) {
ClassTypeCapture ct2 =
new ClassTypeCapture(House.class);
System.out.println(ct2.f(new Building()));
System.out.println(ct2.f(new House()));
}
}
泛型擦除创建对象方式:工厂方式和模板方式。
不能创建泛型数组解决方式:使用ArrayList。
边界使得你可以在用于泛型的参数类型上设置条件。
< ? extends 接口名或类名>
任何从某个类继承的类型都适用。
< ? super 接口名或类名> 超类型通配符
无界通配符:>
ClassA extens ClassB
自限定会强制要求将正在定义的类当做参数传递给基类。
1.5以后可以使用Collections工具类中的checkedList(list, type),checkedMap()等方法检查传入容器的类型。
类型参数可应用于一个方法的throws子句中。
混型:混个多个类的能力,产生一个可以表示混型中所有类型的类。
class Dog:
def speak(self):
print "atf:
def sit(self):
print "Sitting"
def reproduce(self):
pass
class Robot:
def speak(self):
print "atf:
def sit(self):
print "Sitting"
def reproduce(self):
pass
a = Dog()
b = Robot()
perform(a)
perform(b)
perform(anything) 没有针对任何anything类型,anything包含的接口是潜在的。
Java不支持潜在类型机制。
/**
* 适配器模式实现潜在类型机制
* @author Administrator
*
* @param
*/
interface Addable { void add(T t);}
class AddableCollectionAdapter implements Addable{
private Collection c;
public AddableCollectionAdapter(Collection c) {
this.c = c;
}
@Override
public void add(T t) {
c.add(t);
}
}
class Adapter{
public static Addable collectionAdapter(Collection c) {
return new AddableCollectionAdapter(c);
}
}
class AddableSimpleQueue extends SimpleQueue implements Addable{
public void add(T t) {
super.add(t);
}
}
public class Fill2 {
public static void fill(Addable addable,
Class extends T> classToken,int size) {
for (int i = 0; i < size; i++) {
try {
addable.add(classToken.newInstance());
} catch (Exception e) {
throw new RuntimeException();
}
}
}
public static void fill(Addable addable,
Generator< T> generator,int size) {
for (int i = 0; i < size; i++) {
try {
addable.add(generator.next());
} catch (Exception e) {
throw new RuntimeException();
}
}
}
public static void main(String[] args) {
List coffees = new ArrayList<>();
Fill2.fill(new AddableCollectionAdapter(coffees), Coffee.class, 3);
Fill2.fill(Adapter.collectionAdapter(coffees), Coffee.class, 3);
for (Coffee coffee : coffees) {
System.out.println(coffee);
}
System.out.println("--------------------");
AddableSimpleQueue coffeequeue = new AddableSimpleQueue();
Fill2.fill(coffeequeue, Mocha.class, 5);
Fill2.fill(coffeequeue, Latte.class, 6);
for (Coffee coffee : coffeequeue) {
System.out.println(coffee);
}
}
}
策略设计模式将变化的事物隔离到函数对象中。
泛型的作用除了提供类型检查,还可以编写更"泛化"的代码。