码迷,mamicode.com
首页 > 编程语言 > 详细

【ThinkingInJava】39、对于<?>和原生类型的判断

时间:2015-05-18 08:59:16      阅读:241      评论:0      收藏:0      [点我收藏+]

标签:java编程思想   原生类型   无界通配符的类型   

package Lesson15_generices;

//: generics/CovariantArrays.java

class Fruit {}
class Apple extends Fruit {}
class Jonathan extends Apple {}
class Orange extends Fruit {}

public class CovariantArrays {
  public static void main(String[] args) {
    Fruit[] fruit = new Apple[10];
    fruit[0] = new Apple(); // OK
    fruit[1] = new Jonathan(); // OK
    // Runtime type is Apple[], not Fruit[] or Orange[]:
    try {
      // Compiler allows you to add Fruit:
      fruit[0] = new Fruit(); // ArrayStoreException
    } catch(Exception e) { System.out.println(e); }
    try {
      // Compiler allows you to add Oranges:
      fruit[0] = new Orange(); // ArrayStoreException
    } catch(Exception e) { System.out.println(e); }
  }
} /* Output:
java.lang.ArrayStoreException: Fruit
java.lang.ArrayStoreException: Orange
*///:~


package Lesson15_generices;

//: generics/Holder.java

public class Holder<T> {
  private T value;
  public Holder() {}
  public Holder(T val) { value = val; }
  public void set(T arg) { value = arg; }
  public T get() { return value; }
  public boolean equals(Object obj) {
    return value.equals(obj);
  }	
  public static void main(String[] args) {
    Holder<Apple> Apple = new Holder<Apple>(new Apple());
    Apple d = Apple.get();
    Apple.set(d);
    // Holder<Fruit> Fruit = Apple; // Cannot upcast
    Holder<? extends Fruit> fruit = Apple; // OK
    Fruit p = fruit.get();
    d = (Apple)fruit.get(); // Returns 'Object'
    try {
      Orange c = (Orange)fruit.get(); // No warning
    } catch(Exception e) { System.out.println(e); }
    // fruit.set(new Apple()); // Cannot call set()
    // fruit.set(new Fruit()); // Cannot call set()
    System.out.println(fruit.equals(d)); // OK
  }
} /* Output: (Sample)
java.lang.ClassCastException: Apple cannot be cast to Orange
true
*///:~

/**
* 书本:《Thinking In Java》
* 功能:关于系统对于<?>和原生类型的判断,也就是原生类型和涉及无界通配符的类型之间的差异
* 文件:Wildcards.java
* 时间:2015年4月20日08:25:59
* 作者:cutter_point
*/
package Lesson15_generices;

public class Wildcards
{
	static void rawArgs(Holder holder, Object arg)
	{
		holder.set(arg);	//这里holder是泛型的,当使用set方法的时候,这个对象将被向上转型为Object类型的,所以编译器知道这里不安全
		holder.set(new Wildcards());
		
//		T t = holder.get();		//这个里面可没有T
		/*
		 * 所以无论何时,只要使用了原生类型都会放弃编译期的检查
		 */
	}
	
	static void unboundedArg(Holder<?> holder, Object arg)
	{
//		holder.set(arg);  //这里使用一个Object参数会报错,虽然实际上还是转化为Object,但是编译器认为Holder<?>是具有某种具体类型的同构集合
//		holder.set(new Wildcards());
//		holder = new Holder<Object>();		//这样用
		Object obj = holder.get();	//返回的就是一个Object类型
	}
	
	static <T> T exact1(Holder<T> holder)
	{
		T t = holder.get();
		return t;
	}
	
	static <T> T exact2(Holder<T> holder, T arg)
	{
		holder.set(arg);
		T t = holder.get();
		return t;
	}
	
	static <T>
	T wildSubtype(Holder<? extends T> holder, T arg)
	{
//		holder.set(arg);	//出错,这个类型是一个继承自T的类型,也就是无法放入超类
		T t = holder.get();
		return t;
	}
	
	static <T>
	void wildSupertype(Holder<? super T> holder, T arg)
	{
		
		holder.set(arg);	//出错,这个类型是一个继承自T的类型,也就是无法放入超类
//		T t = holder.get();		//这里返回的就不是T的类型了,因为T在传入的时候是可以是任何的T的超导类,所以这里用T来返回时不安全的,只能是Object类型
		Object t = holder.get();
	}
	
	
	public static void main(String[] args)
	{
		Holder raw = new Holder<Long>();
		//或者
		raw = new Holder();
		
		Holder<Long> qualified = new Holder<Long>();
		Holder<?> unbounded = new Holder<Long>();
		Holder<? extends Long> bounded = new Holder<Long>();
		Long lng = 1L;
		
		rawArgs(raw, lng);
		rawArgs(qualified, lng);
	    rawArgs(unbounded, lng);
	    rawArgs(bounded, lng); 
		
	    unboundedArg(raw, lng);
	    unboundedArg(qualified, lng);
	    unboundedArg(unbounded, lng);
	    unboundedArg(bounded, lng);
	    
//	    Object r1 = exact1(raw);		//警告,
	    Long r2 = exact1(qualified);
	    Object r3 = exact1(unbounded); // Must return Object
	    Long r4 = exact1(bounded);
	    
	    Long r6 = exact2(qualified, lng);
	    
	    Long r10 = wildSubtype(qualified, lng);
	    
	    /*
	     * static <T>
        	T wildSubtype(Holder<? extends T> holder, T arg)
        	{
        //		holder.set(arg);	//出错,这个类型是一个继承自T的类型,也就是无法放入超类
        		T t = holder.get();
        		return t;
        	}
	     */
	    //Object r11 = wildSubtype(unbounded, lng);	//不能放入超类,只能是Holder的导出类
	    Long r12 = wildSubtype(bounded, lng);
	    
	    wildSupertype(qualified, lng);
	    
		
	}

}

感觉<?>不是单纯的Object类型可以打发的,这个<?>表示一种未知的类型,比如Holder和Holder<?>是不一样的类型,应为Holder可以有各种类型的组合,而Holder只能是某种类型的同构集合,所以不能只是向里面传递Object


输出:

这里面会报错,根据main函数里面各种不同的参数传值






【ThinkingInJava】39、对于<?>和原生类型的判断

标签:java编程思想   原生类型   无界通配符的类型   

原文地址:http://blog.csdn.net/cutter_point/article/details/45814883

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!