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

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函数里面各种不同的参数传值

时间: 2024-12-22 09:59:57

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

jquery中关于对象类型的判断原理

class2type[ core_toString.call(obj) ] jquery中关于对象类型的判断原理 jquery源码中关于类型判断的工具函数为type,调用方法为$.type()或者jQuery.type(),关于type函数的实现为: 1 type: function( obj ) { 2 if ( obj == null ) { 3 return String( obj ); 4 } 5 // Support: Safari <= 5.1 (functionish RegExp

利用toString做类型的判断

//利用toString做类型的判断 : /*var arr = []; alert( Object.prototype.toString.call(arr) == '[object Array]' ); */ //'[object Array]'

#定义一个方法get_num(num),num参数是列表类型,判断列表里面的元素为数字类型。其他类型则报错,并且返回一个偶数列表:(注:列表里面的元素为偶数)。

1 #定义一个方法get_num(num),num参数是列表类型,判断列表里面的元素为数字类型.其他类型则报错,并且返回一个偶数列表:(注:列表里面的元素为偶数). 2 def get_num(num): 3 if type(num)!= list: 4 return '您传入的不是列表!' 5 else: 6 for i in num: 7 if not isinstance(i,int): 8 return '请全部传入整数!' 9 return list(filter(lambda x:x

JavaScript - 数值类型的判断与常用转换方式

主要参考: isNaN() - JavaScript | MDN Number.isNaN() - JavaScript | MDN parseInt() - JavaScript | MDN parseFloat() - JavaScript | MDN 数值类型的判断方法isNaN()和Number.isNaN() 可接受任意参数,用来判断其参数是否为NaN(not a number) 由于把NaN与任何值(包括其自身)相比得到的结果都是false,因此无法通过==或===运算符来判断某个值

JavaScript各变量类型的判断方法

我们很容易被漂亮的代码吸引,也不知不觉的在自己的代码库中加入这些.却没有冷静的想过它们的优劣.这不,我就收集了一系列形如 "是否为……?" 的判断的boolean函数. isNull: function(a){ return a === null; }, isUndefined: function(a){ return a === undefined; }, isNumber: function(a){ return typeof a === 'number'; }, isString

javascript中对变量类型的判断

本文正式地址:http://www.xiabingbao.com/javascript/2015/07/04/javascript-type 在JavaScript中,有5种基本数据类型和1种复杂数据类型,基本数据类型有:Undefined, Null, Boolean, Number和String:复杂数据类型是Object,Object中还细分了很多具体的类型,比如:Array, Function, Date等等.今天我们就来探讨一下,使用什么方法判断一个出一个变量的类型. 在讲解各种方法之

JS 中对变量类型的判断

总结:1. 一般简单的使用 typeof 或 instanceof 检测(这两种检测的不完全准确)          2. 完全准确的使用 原生js中的 Object.prototype.toString.call  或 jquery中的 $.type 检测 在 JS 中,有 5 种基本数据类型和 1 种复杂数据类型,基本数据类型有:Undefined, Null, Boolean, Number和String:复杂数据类型是Object,Object中还细分了很多具体的类型,比如:Array,

5、使用泛型替代原生类型

java1.5中提供了泛型,简单来说就是将类型作为参数传入,这样java会自动转换类型,不需要我们进行强制转换. Map<String, Integer> map = new HashMap<>(); map.put("age", 18); Integer age = map.get("age"); 我们看到,没有任何instanceOf的判断,也没有任何强制类型转换.泛型是我们在编译的时候就能确保类型的正确性,是写出强健代码的良好方式.

四、Mp3文件类型及其判断

根据前两篇文章的分析,帧分为标签帧和数据帧,MP3文件类型是根据数据帧的类型来分的,文件类型如下表: 位率相等(Constant BitRate) CBR  Mp3文件 位率不等(Variable BitRate) Xing  Mp3文件 VBRI  Mp3文件 一.如何判断一个Mp3文件的类型,CBR文件,VBRI文件还是Xing文件 以功能流程图的形式: 二.文件播放时长的计算问题. 区分了文件类型就可以计算Mp3文件的播放时长了. 1.CBR文件的时长计算(duration) 对于计算CB