* 擦除的问题
* 为什么要擦除: 1.5版本才出现泛型 为了兼容之前地代码
* 它使得泛化的客户端可以用非泛化的类库来使用。
* 以及不破坏现有类库的情况下,将泛型融入java语言。
* 擦除使得现有的非泛型客户端代码能够在不改变的情况继续使用,直至客户端准备号用泛型重写这些代码。
* 擦除的代价:泛型不能用于显示地引用运行时类型的操作值中,例如转型instanceof操作和new表达式。
* 因为所有关于参数的类型都丢失了。无论何时,当你在编写泛型代码时,必须时刻提醒自己,
* 你只是看起来好像拥有关于参数的类型信息而已。提醒自己:T 不,它值时一个Object
* 擦除使用泛型并不是强制的
package com.zghw.base.generic;
import java.util.*;
/**
* 擦除的问题
* 为什么要擦除: 1.5版本才出现泛型 为了兼容之前地代码
* 它使得泛化的客户端可以用非泛化的类库来使用。
* 以及不破坏现有类库的情况下,将泛型融入java语言。
* 擦除使得现有的非泛型客户端代码能够在不改变的情况继续使用,直至客户端准备号用泛型重写这些代码。
* 擦除的代价:泛型不能用于显示地引用运行时类型的操作值中,例如转型instanceof操作和new表达式。
* 因为所有关于参数的类型都丢失了。无论何时,当你在编写泛型代码时,必须时刻提醒自己,
* 你只是看起来好像拥有关于参数的类型信息而已。提醒自己:T 不,它值时一个Object
* 擦除使用泛型并不是强制的
* @author zghw
*
*/
class Frob{}
class Fnorkle{}
class Quark<Q>{}
class Particle<POSITION,MOMENTUM>{}
public class ErasedTypeEquivalence {
/**
* ArrayList<String>和ArrayList<Integer>很容易认为是不同的类型,
* 不同的类型在行为方面肯定不同 但输出发现c1==c2为true
* @param args
*/
public static void main(String[] args) {
Class c1=new ArrayList<String>().getClass();
Class c2=new ArrayList<Integer>().getClass();
System.out.println(c1==c2);//输出为true
List<Frob> list = new ArrayList<Frob>();
Map<Frob,Fnorkle> map = new HashMap<Frob,Fnorkle>();
Quark<Fnorkle> quark = new Quark<Fnorkle>();
Particle<Long,Double> part=new Particle<Long,Double>();
//Class.getTypeParameters()将返回一个Typeariable对象数组,表示有泛型声明
//的类型参数...
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(part.getClass().getTypeParameters()));
/**
* 输出结果:
* [E]
[K, V]
[Q]
[POSITION, MOMENTUM]
*/
/**
* 输出结果是一些占位符
* 说明:在泛型代码内部,无法获得任何有关泛型参数类型的信息。
* 当你在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。
* 因此,List<String>和List<Integer>在运行时事实上是相同的类型。这两种形式都被
* 擦除成它们的原生类型,即List
*/
}
}
package com.zghw.base.generic;
/**
* 擦除带来的问题
* 1.无法创建类型实例
* 2.无法使用instanceof
* 3.无法调用类型实例方法
* 解决办法
* 通过引入类型标签来对擦除进行补偿。这意味着你需要显示地传递你地类型地Class对象,
* 以便你可以在类型表达式中使用它。
* 可以使用?extends T 继承来实现可以调用方法
* @author zghw
*/
class Erased<T>{
public static void f(Object arg){
//if(arg instanceof T){}//Error无法使用instanceof
//T var = new T();//Error无法创建类型实例
}
}
class Building {}
class House extends Building{}
public class ClassTypeCapture<T> {
Class<T> kind;
T t ;
public ClassTypeCapture(Class<T> kind){
this.kind = kind;
try {
t=kind.newInstance();//创建类型实例
} catch (Exception e) {
throw new RuntimeException();
}
}
public boolean isInstance(Object arg){
return kind.isInstance(arg);
}
public static void main(String[] args) {
ClassTypeCapture<Building> c1=new ClassTypeCapture<Building>(Building.class);
ClassTypeCapture<House> c2=new ClassTypeCapture<House>(House.class);
System.out.println(c1.isInstance(c2));
System.out.println(c1.isInstance(new Building()));
System.out.println(c1.isInstance(new House()));
System.out.println(c2.isInstance(new Building()));
System.out.println(c2.isInstance(new House()));
}
}
package com.zghw.base.generic;
/**
* 使用简单工厂来创建泛型T 建议创建泛型对象使用此方法
*
* @author zghw
*
*/
interface Factory<T> {
T creat();
}
class IntegerGen implements Factory<Integer> {
@Override
public Integer creat() {
return new Integer(0);// 由于Integer没有默认构造方法,无法使用Class创建泛型实例
}
}
class Widget {
public static class FactoryInner implements Factory<Widget> {
@Override
public Widget creat() {
return new Widget();
}
}
}
class Foo<T> {
private T x;
public <F extends Factory<T>> Foo(F factory) {
x = factory.creat();
}
public T get() {
return x;
}
}
public class FactoryConstraint {
public static void main(String[] args) {
Integer i = new Foo<Integer>(new IntegerGen()).get();
Widget w = new Foo<Widget>(new Widget.FactoryInner()).get();
}
}
package com.zghw.base.generic;
/**
* 使用模板方法创建泛型实例
*
* @author zghw
*
*/
abstract class GenericWithCreator<T> {
final T element;
public GenericWithCreator() {
element = creat();
}
abstract T creat();
}
class Obj {
}
class Creator extends GenericWithCreator<Obj> {
@Override
Obj creat() {
return new Obj();
}
void f() {
System.out.println(element.getClass().getSimpleName());
}
}
public class CreatorGeneric {
public static void main(String[] args) {
new Creator().f();
}
}
package com.zghw.base.generic;
import java.awt.Color;
/**
* 边界 边界作用: 可以用于在泛型地参数上设置限制条件。
* 你可以按照自己的边界类型来调用方法。
* 因为擦除移除了类型,所以你可以用泛型参数调用的方法只是Object调用的方法。
* 但是,如果能够将这个参数限制在某个类型子类,那么你就可以用这些类型子集来调用方法。
* 为了执行这种限制,Java泛型重用了extends关键字
*
* @author zghw
*
*/
interface HasColor {
Color getColor();
}
class Dimension {
public int x, y, z;
}
interface Weight {
int weight();
}
class HoldItem<T> {
T item;
HoldItem(T item) {
this.item = item;
}
T getItem() {
return item;
}
}
class Colored<T extends HasColor> {
T item;
Colored(T item) {
this.item = item;
}
Color getColor() {
return item.getColor();
}
}
class Colored2<T extends HasColor> extends HoldItem<T> {
Colored2(T item) {
super(item);
}
Color getColor() {
return item.getColor();
}
}
class ColoredDimension<T extends Dimension & HasColor> {
T item;
ColoredDimension(T item) {
this.item = item;
}
Color getColor() {
return item.getColor();
}
int getX() {
return item.x;
}
int getY() {
return item.y;
}
int getZ() {
return item.z;
}
}
class ColoredDimension2<T extends Dimension & HasColor> extends Colored2<T> {
ColoredDimension2(T item) {
super(item);
}
int getX() {
return item.x;
}
int getY() {
return item.y;
}
int getZ() {
return item.z;
}
}
class Solid2<T extends Dimension & HasColor & Weight> extends
ColoredDimension2<T> {
Solid2(T item) {
super(item);
}
int weight() {
return item.weight();
}
}
class Solid<T extends Dimension & HasColor & Weight> {
T item;
Solid(T item) {
this.item = item;
}
Color getColor() {
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 int weight() {
return 0;
}
@Override
public Color getColor() {
return null;
}
}
public class BasicBounds {
public static void main(String args[]) {
Solid<Bounded> s = new Solid<Bounded>(new Bounded());
Solid2<Bounded> s2 = new Solid2<Bounded>(new Bounded());
s.getColor();
s.getX();
s2.getColor();
s2.getY();
}
}
package com.zghw.base.generic;
/**
* 只有当你希望使用的类型参数比某个具体类型(以及它的所有子类型)更加“泛化”时--也就是说,当你希望
* 代码能够跨多个类工作时,时用泛型才有所帮助,通常比简单的类替换要更复杂
* 必须查看所有的代码,并确定它是否“足够复杂”到必须时用泛型的程度
* @author zghw
*
*/
class HasF{
void f(){
System.out.println();
}
}
class Manipulator<T>{
private T obj;
public Manipulator(T obj){
this.obj =obj;
}
public void set(T obj){
this.obj = obj;
}
public T get(){
return obj;
}
}
//没有泛型的类 比较上面的泛型类 可以发现泛型并没有任何好处
//T擦除了HasF,就好像在类的声明中用HasF一样
class Manipulator1{
private HasF obj;
public Manipulator1(HasF obj){
this.obj =obj;
}
public void set(HasF obj){
this.obj = obj;
}
public HasF get(){
return obj;
}
}
public class Manipulation {
public static void main(String[] args) {
Manipulator<HasF> m = new Manipulator<HasF>(new HasF());
Manipulator1 m1 = new Manipulator1(new HasF());
//T擦除了HasF,就好像在类的声明中用HasF一样
}
}
package com.zghw.base.generic;
import java.util.*;
/**
* 通配符
* 为什么需要通配符?
* 泛型没有内建的协变类型
* 通配符
* 1.? extends T 用作方法返回值 意味着 它可以是任何事物包括子类,而编译器无法验证“任何事物”的安全性
* 2.? super T 用作方法参数 将一个T类型的对象或者从T导出的任何对象作为参数传入使用类型的方法
* 3.?
* 因此你可能会根据如何能够向一个泛型类型”写入“(传递给一个方法),
* 以及如何能够从一个泛型类型中“读取”(从一个方法中返回),来左手思考子类型和超类型边界。
* @author zghw
*
*/
class Fruit{}
class Apple extends Fruit{}
class Jonathan extends Apple{}
class Orange extends Fruit{}
public class Covariance{
public static void main(String[] args) {
List<Fruit> list1 =new ArrayList<Fruit>();
List<Apple> list2 =new ArrayList<Apple>();
//编译不通过 Apple的List在类型上不等价于Fruit的List,即使Apple是Fruit的子类
//我们在讨论的是容器的类型,而不是容器持有的类型
//但是,我们想要在两个类型之间建立某种类型的向上转型关系,
//就需要通配符
//List<Fruit> list3 =new ArrayList<Apple>();//编译不通过
//List<? extends Fruit> :你可以读作”具有任何从Fruit继承的类型的列表“
//但List不会持有任何类型的Fruit. list3引用没有指定具体的类型
//只是为了向上转型
List<? extends Fruit> list3 =new ArrayList<Apple>();
//只接受 add(? extends Fruit e) 不了解到底需要Fruit的那个具有子类型
//因此它不会接受任何Fruit,甚至只接受null
//? extends Fruit 意味着 它可以是任何事物,而编译器无法验证“任何事物”的安全性
//list3.add(new Apple());//编译不通过
//list3.add(new Fruit());//编译不通过
//list3.add(new Object());//编译不通过
list3.add(null);
writeTo(new ArrayList<Fruit>(),new Apple());
}
/**
* ? super T 只作用泛型参数中,List将持有从T导出的某种具体类型,这样就可以安全的将一个T类型的对象
*或者从T导出的任何对象作为参数给List方法
* @param fruit
* @param item
*/
static <T> void writeTo(List<? super T> fruit,T item){
fruit.add(item);
}
}
package com.zghw.base.generic;
import java.util.*;
/**
* 通配符 ? extends T ? super T 的应用
*
* @author zghw
*
*/
public class GenericWriterReader {
static <T> void writeExact(List<T> list, T item) {
list.add(item);
}
static <T> void writeWild(List<? super T> list, T item) {
list.add(item);
}
static <T> T readExact(List<T> list) {
return list.get(0);
}
static class Reader<T> {
static <T> T readExact(List<T> list) {
return list.get(0);
}
}
static class ReadWild<T> {
static <T> T readExact(List<? extends T> list) {
return list.get(0);
}
}
static List<Fruit> fruitsw = new ArrayList<Fruit>();
static List<Apple> applesw = new ArrayList<Apple>();
static List<Fruit> fruits = Arrays.asList(new Fruit());
static List<Apple> apples = Arrays.asList(new Apple());
static void w1() {
writeExact(applesw, new Apple());
writeExact(fruitsw, new Apple());
}
static void w2() {
writeWild(applesw, new Apple());
writeWild(fruitsw, new Apple());
}
static void r1() {
Apple a = readExact(apples);
Fruit f = readExact(fruits);
f = readExact(apples);
}
static void r2() {
Reader<Fruit> r = new Reader<Fruit>();
Apple a = r.readExact(apples);
Fruit f = r.readExact(fruits);
f = r.readExact(apples);
}
static void r3() {
ReadWild<Fruit> r = new ReadWild<Fruit>();
Apple a = r.readExact(apples);
Fruit f = r.readExact(fruits);
f = r.readExact(apples);
}
public static void main(String[] args) {
w1();
w2();
r1();
r2();
r3();
}
}