java基础总结 --- 泛型 擦除、边界、通配符、


* 擦除的问题
 * 为什么要擦除: 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();
	}

}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值