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. Summary #ToBeContinue......

    一.请回望暑假时的第一次作业,你对于软件工程课程的想象1)对比开篇博客你对课程目标和期待,“希望通过实践锻炼,增强计算机专业的能力和就业竞争力”,对比目前的所学所练所得,在哪些方面达到了你的期待和目标 ...

  2. Mac提示App已损坏 你应该将它移到废纸篓的解决方案

    现象 "Elmedia Player.app"已损坏,打不开. 您应该将它移到废纸篓. 原因 很多朋友们在安装软件时Mac OS系统出现提示"XXXApp 已损坏&quo ...

  3. 浏览器缓存和Service Worker

    浏览器缓存和Service Worker @billshooting 2018-05-06 字数 6175 Follow me on Github 标签: BOM 1. 传统的HTTP浏览器缓存策略 ...

  4. C# 使用 COALESCE 表达式简化 Null 检查

    下面这个判断 null 的语句: a == null ? b: a 可以用 COALESCE 表达式,简化成: a ?? b

  5. deepin jdk 安装

    一.安装JDK环境 1 .卸载系统自带的Openjdk(可能不需要) 先用检测是否安装了openjdk dpkg -l | grep openjdk 如果安装了, 使用下面命令卸载. sudo apt ...

  6. C# 键盘中的按键对应KeyValue

    首先先看一下什麼情況下需要對按鍵進行識別: KeyPress事件響應函數中,有KeyPressEventArgs, 對應於e.KeyChar; KeyDown事件響應中有KeyEventArgs 求取 ...

  7. robot framework学习笔记之七—连接mysql数据库

    1.安装Database-Library 输入命令:pip install robotframework_databaselibrary 2.添加Database的Library     3.实例 * ...

  8. HTTP请求报文支持的各种方法

    常见的HTTP方法如下: 1.GET GET是最常用的方法.通常用于请求服务器发送某个资源. 2.HEAD HEAD与GET的行为类似,但服务器在响应中只返回首部,不会返回实体的部分.这就允许客户端在 ...

  9. jquery源码解析:addClass,toggleClass,hasClass详解

    这一课,我们将继续讲解jQuery对元素属性操作的方法. 首先,我们先看一下这几个方法是如何使用的: $("#div1").addClass("box1 box2&quo ...

  10. python --爬虫基础 --爬取今日头条 使用 requests 库的基本操作, Ajax

    '''思路一: 由于是Ajax的网页,需要先往下划几下看看XHR的内容变化二:分析js中的代码内容三:获取一页中的内容四:获取图片五:保存在本地 使用的库1. requests 网页获取库 2.fro ...