5. Conversions and Promotions

5.1. Kinds of Conversion
5.1.1. Identity Conversion
5.1.2. Widening Primitive Conversion
5.1.3. Narrowing Primitive Conversion
5.1.4. Widening and Narrowing Primitive Conversion
5.1.5. Widening Reference Conversion
5.1.6. Narrowing Reference Conversion
5.1.7. Boxing Conversion
5.1.8. Unboxing Conversion
5.1.9. Unchecked Conversion
5.1.10. Capture Conversion
5.1.11. String Conversion
5.1.12. Forbidden Conversions
5.1.13. Value Set Conversion
如上11种基本类型的转换
5.2. Assignment Conversion
5.3. Method Invocation Conversion
5.4. String Conversion
5.5. Casting Conversion
5.5.1. Reference Type Casting
5.5.2. Checked Casts and Unchecked Casts
5.5.3. Checked Casts at Run Time
5.6. Numeric Promotions
5.6.1. Unary Numeric Promotion
5.6.2. Binary Numeric Promotion

如上5种转换上下文环境,每种环境可能允许一些基本类型转换

1、isConvertible()

 /**
     * Is t a subtype of or convertible via boxing/unboxing conversion to s?
     */
    public boolean isConvertible(Type t, Type s, Warner warn) {
        if (t.tag == ERROR)
            return true;
        boolean tPrimitive = t.isPrimitive();
        boolean sPrimitive = s.isPrimitive();
        if (tPrimitive == sPrimitive) {
            return isSubtypeUnchecked(t, s, warn);
        }

        if (!allowBoxing)
            return false;

        return tPrimitive
            ? isSubtype(boxedClass(t).type, s)
            : isSubtype(unboxedType(t), s);
    }  

当两个类型相同时(同时为原始类型或引用类型)通过调用isSubtypeUnchecked()方法来进一步判断。

 /**
     * Is t an unchecked subtype of s?
     */
    public boolean isSubtypeUnchecked(Type t, Type s, Warner warn) {
        boolean result = isSubtypeUncheckedInternal(t, s, warn);
        if (result) {
            checkUnsafeVarargsConversion(t, s, warn);
        }
        return result;
    }  

在如上方法中涉及到两个重要的方法isSubtypeUncheckedInternal()与checkUnsafeVarargsConversion(),不过优先调用前一个方法,如果是Unchecked Subtype关系,则需要检查是否为Unsafe Varargs Conversion。

private boolean isSubtypeUncheckedInternal(Type t, Type s, Warner warn) {
        if (t.tag == ARRAY && s.tag == ARRAY) {
            if (((ArrayType)t).elemtype.tag <= lastBaseTag) {
                return isSameType(elemtype(t), elemtype(s));
            } else {
                return isSubtypeUnchecked(elemtype(t), elemtype(s), warn);
            }
        }
        else if (isSubtype(t, s)) {
            return true;
        }
        else if (t.tag == TYPEVAR) {
            return isSubtypeUnchecked(t.getUpperBound(), s, warn);
        }
        else if (s.tag == UNDETVAR) {
            UndetVar uv = (UndetVar)s;
            if (uv.inst != null)
                return isSubtypeUnchecked(t, uv.inst, warn);
        }
        else if (!s.isRaw()) {
            Type t2 = asSuper(t, s.tsym);
            if (t2 != null && t2.isRaw()) {
                if (isReifiable(s))
                    warn.silentWarn(LintCategory.UNCHECKED);
                else
                    warn.warn(LintCategory.UNCHECKED);
                return true;
            }
        }
        return false;
    }

当两个类型是数组类型时,并且是原始数组类型时,则数组类型的元素类型必须相同,也就是byte[]与int[]没有父子类关系,如下代码会报错:

byte[] x = new byte[10];
int[] y = (int[])x;

如果数组类型的元素非原始类型,那么需要进一步比较数组中的元素类型。获取数组元素类型通过如下方法来完成。

/**
     * The element type of an array.
     */
public Type elemtype(Type t) {
        switch (t.tag) {
        case WILDCARD:
            return elemtype(upperBound(t));
        case ARRAY:
            return ((ArrayType)t).elemtype;
        case FORALL:
            return elemtype(((ForAll)t).qtype);
        case ERROR:
            return t;
        default:
            return null;
        }
}

需要说明的是类型变量的上界也可能是数组类型,虽然编译器好像不支持这么做,但是JLS7中确实有这么规定。如果是类型变量,那么就取上界后继续查找数组元素的类型。

而ForAll类型不太明白??  

当t的类型为类型变量时,如下:

public class Test<T extends FilterInputStream> {
	public void test(T dd) {
		InputStream p = (InputStream)dd;
	}
}

而当s为UNDETVAR时,不太明白??

下面的逻辑需要明白如下两个概念:  

4.7. Reifiable Types

4.8. Raw Types 

举几个是Reifiable Types的例子,如下:

class A{}
class B<T>{}
class C<T>{
	class D<X>{

	}
}

class TestType{
	public void test(){
		//It refers to a non-generic class or interface type declaration.
		A a;
		// It is a parameterized type in which all type arguments are unbounded wildcards
		B<?> b;
		// It is a primitive type
		int c;
		// It is an array type (§10.1) whose element type is reifiable.
		int[] d;
		// It is a nested type where, for each type T separated by a ".", T itself is reifiable.
		C<?>.D<?> e;
		// It is a raw type
	}
}

举几个是Raw Types的例子,如下:

class A{}
class B<T>{}
class C<T>{
	class D<X>{

	}
	class E{
		T e;
	}
}

class TestType{
	public void test(){
		// A non-generic class or interface type is not a raw type.
		A a;
		// The reference type that is formed by taking the name of a generic type declaration
		// without an accompanying type argument list.
		B b;
		// An array type whose element type is a raw type.
		B[] c;
		// A non-static member type of a raw type R that is not inherited from a superclass or superinterface of R
		C.D d;
		C.E e;
	}
}  

现在来理解如下的代码:

 else if (!s.isRaw()) {
            Type t2 = asSuper(t, s.tsym); // 根据s.tsym符号来查找t类型
            if (t2 != null && t2.isRaw()) {
                if (isReifiable(s))
                    warn.silentWarn(LintCategory.UNCHECKED);
                else
                    warn.warn(LintCategory.UNCHECKED);
                return true;
            }
}

回到isSubtypeUnchecked()方法继续来看另外一个方法,代码如下:

 private void checkUnsafeVarargsConversion(Type t, Type s, Warner warn) {
        // t为非数组或者t是数组,但是是一个reifiable的数组
        if (t.tag != ARRAY || isReifiable(t))
            return;

        // t是一个数组并且是一个非reifiable的数组
        ArrayType from = (ArrayType)t;
        boolean shouldWarn = false;
        switch (s.tag) {
            case ARRAY:
                ArrayType to = (ArrayType)s;
                shouldWarn = from.isVarargs() &&
                        !to.isVarargs() &&
                        !isReifiable(from);
                break;
            case CLASS:
                shouldWarn = from.isVarargs();
                break;
        }
        if (shouldWarn) {
            warn.warn(LintCategory.VARARGS);
        }
    }

举个例子,如下:

public void test2(){

		Map<String, Object> row1 = new HashMap<String, Object>();
		Map<String, Object> row2 = new HashMap<String, Object>();
		// Type safety: A generic array of Map<String,Object> is created for a varargs parameter
		mockInvokeDBHandler(row1, row2);

}

private void mockInvokeDBHandler(Map<String, Object>... rows) {
	    List<Map<String, Object>> allRows = Arrays.asList(rows);

	    Object o = (Serializable)rows;
	    // rest of method omitted
}

在调用方法时会将可变参数转换为数组类型,所以调用mockInvokeDBHandler()方法会给出警告。而将rows转换为Serializable类时同样会给出警告。  

再举个例子,如下:

public class Test {
	public <T extends ArrayList> void test(T dd) {
		// Type safety: The expression of type T needs unchecked conversion to conform to List<String>
		List<String> l = dd;
	}
}

在将dd赋值给List<String>类型时会调用isSubtypeUncheckedInternal()方法。

  

2、isCastable()

/**
     * Is t is castable to s?
     * s is assumed to be an erased type.
     * (not defined for Method and ForAll types).
     */
    public boolean isCastable(Type t, Type s, Warner warn) {
        if (t == s) {
            return true;
        }

        // 由于类型只有原始类型与引用类型两种,如果不相等,则必有一个原始类型,一个引用类型
        if (t.isPrimitive() != s.isPrimitive()) {
            if(!allowBoxing){
                return false;
            }
            if(isConvertible(t, s, warn)){
                return true;
            }
            /*
               e.g
                 Object a = 2;
                 int b = (int)a;
            */
            if( allowObjectToPrimitiveCast &&
                    s.isPrimitive() &&
                    isSubtype(boxedClass(s).type, t)){
                return true;
            }
            return false;
        }

        if (warn != warnStack.head) {
            try {
                warnStack = warnStack.prepend(warn);
                checkUnsafeVarargsConversion(t, s, warn);
                return isCastable.visit(t,s);
            } finally {
                warnStack = warnStack.tail;
            }
        } else {
            return isCastable.visit(t,s);
        }
    }

  

下面看一下checkUnsafeVarargsConversion()方法,代码如下:

 /*
        public  static <E> void addAll(E... array) {  // varargs warning
            // 如下的两个转换会调用下面的方法
            Integer[] e = (Integer[])array;
            Serializable s = (Serializable)array;
        }
     */
    private void checkUnsafeVarargsConversion(Type t, Type s, Warner warn) {
        // t 为非数组或者t是数组,但是是一个reifiable的数组
        if (t.tag != ARRAY || isReifiable(t))
            return;

        // t 是一个数组并且是一个非reifiable的数组
        ArrayType from = (ArrayType)t;
        boolean shouldWarn = false;
        switch (s.tag) {
            case ARRAY:
                ArrayType to = (ArrayType)s;
                shouldWarn = from.isVarargs() &&
                        !to.isVarargs() &&
                        !isReifiable(from);
                break;
            case CLASS:
                shouldWarn = from.isVarargs();
                break;
        }
        if (shouldWarn) {
            warn.warn(LintCategory.VARARGS);
        }
    }

  

重点看一下isCastable这个匿名类对象提供的一些访问者方法。

(1)visitType()方法

        public Boolean visitType(Type t, Type s) {
            if (s.tag == ERROR) {
                return true;
            }

            switch (t.tag) {
            case BYTE: case CHAR: case SHORT: case INT: case LONG: case FLOAT:
            case DOUBLE:
                return s.tag <= DOUBLE;
            case BOOLEAN:
                return s.tag == BOOLEAN;
            case VOID:
                return false;
            case BOT:
                return isSubtype(t, s);
            default:
                throw new AssertionError();
            }
        }

e.g

 byte a = 2;
Integer b = (int)a; // 则type转换为int时需要调用visitType()方法

  

(2)visitWildcardType()方法  

@Override
public Boolean visitWildcardType(WildcardType t, Type s) {
            return isCastable(upperBound(t), s, warnStack.head);
}

  

Types方法之isCastable-isConvertible的更多相关文章

  1. Types方法之upperBound-lowerBound-isUnbounded-containsType

    1.upperBound(Type t)方法 /** * The "rvalue conversion". * The upper bound of most types is t ...

  2. Types方法之isSameType-isSuperType-isSubType

    4.isSameType() 方法 /** * Is t the same type as s? */ public boolean isSameType(Type t, Type s) { retu ...

  3. runtime第三部分方法和消息

    接上一篇http://www.cnblogs.com/ddavidXu/p/5924049.html 转载来源http://www.jianshu.com/p/6b905584f536 http:// ...

  4. Runtime 动态加载方法

    动态加载 #import"ViewController.h" #import"Person.h" @interfaceViewController() @end ...

  5. Objective-C Runtime 运行时之三:方法与消息

    基础数据类型 SEL SEL又叫选择器,是表示一个方法的selector的指针,其定义如下: typedef struct objc_selector *SEL; objc_selector结构体的详 ...

  6. Objective-C Runtime 运行时之三:方法与消息(转载)

    前面我们讨论了Runtime中对类和对象的处理,及对成员变量与属性的处理.这一章,我们就要开始讨论Runtime中最有意思的一部分:消息处理机制.我们将详细讨论消息的发送及消息的转发.不过在讨论消息之 ...

  7. iOS运行时使用(动态添加方法)

    1 举例  我们实现一个Person类 然后Person 其实是没得对象方法eat:的 下面调用person的eat方法 程序是会奔溃的 那么需要借助运行时动态的添加方法 Person *p = [[ ...

  8. 快速上手Runtime(四)之动态添加方法

    如果一个类方法非常多,加载类到内存的时候也比较耗费资源,可以使用动态给某个类,添加方法解决.做到优化内存,节省资源的效果. // // Person.m // ResolveInstanceMetho ...

  9. iOS---runtime介绍

    本文目录 1.Runtime简介 2.Runtime相关的头文件 3.技术点和应用场景 3_1.获取属性\成员变量列表 3_2.交换方法实现 3_3.类\对象的关联对象,假属性 3_4.动态添加方法, ...

随机推荐

  1. Grails入门系列(一)

    Grails入门系列(一) JAVAweb开发技术相对于php,python,note.js等新式技术更为复杂,向来以繁杂的配置著称,但是Java任然被广泛的应用于大型企业级的项目,主要是因为技术成熟 ...

  2. MFC中的一般经验之谈3

    Window消息可以分为三类:(1)标准Window消息(CWnd子类处理),(2)控制通知消息(CWnd子类处理),(3)命令消息(应用中的5类都可以).所有派生自CCmdObjec对象的类都可以处 ...

  3. win32多线程-异步(asynchronous) I/O

    I/O设备是个慢速设备,无论打印机.调制解调器,甚至硬盘,与CPU相比都奇慢无比,坐下来干等I/O的完成是一件不甚明智事情. 异步(asynchronous) I/O在win32多线程程序设计中被称为 ...

  4. delphi http 403 获取不到服务器返回的错误消息 用浏览器打开url可以返回

    用delphi的idhttp Get一个url如下: http://117.135.237.4:9090/agent/api/treatmentModeUpdate?userName=VDAwMIMQ ...

  5. 自我介绍+github注册

    我是网络工程141的蒋易,学号是1413042018 个人兴趣:打篮球,打羽毛球,打游戏 github注册流程 id:Scorpio1 注册困难:1.刚开始网页没打开. 2.全英文的界面无法看懂,要查 ...

  6. web项目开发最佳做法

    一个成熟的web项目应该具备以下基础代码或做法 1.前端基础框架: 统一的ajax 通信/表单提交及调用结果弹窗显示 统一的数据验证 统一的数据列表 2.后端基础框架: 统一的异常处理捕获,可针对具体 ...

  7. [LeetCode 题解]: Partition List

    Given a linked list and a value x, partition it such that all nodes less than x come before nodes gr ...

  8. mdadm 软RAID

    mdadm是linux下用于创建和管理软件RAID的命令,是一个模式化命令.但由于现在服务器一般都带有RAID阵列卡,并且RAID阵列卡也很廉价,且由于软件RAID的自身缺陷(不能用作启动分区.使用C ...

  9. MSP430 G2553 基本时钟模块+ (Basic Clock Module+)

    一.时钟源 MSP430的Basic Clock Module+支持的时钟源有: DCOCLK:内部数字控制振荡器,Internal digitally contrlled oscillator.所有 ...

  10. Devexpress GridControl无限高度惹得祸

    异常提示: issue, place the grid into a container that will give a finite height to the grid, or manually ...