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. ZOJ1586 QS Network 2017-04-13 11:46 39人阅读 评论(0) 收藏

    QS Network Time Limit: 2 Seconds      Memory Limit: 65536 KB Sunny Cup 2003 - Preliminary Round Apri ...

  3. HttpServletRequest介绍

    HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息. 二 ...

  4. CentOS 系统状况查看

    1 磁盘 iostat    安装 yum install sysstat iostat -x Linux -.el7.x86_64 (sdw2) 2017年03月07日 _x86_64_ ( CPU ...

  5. Windows和linux通过命令互传文件

    下载pscp https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html 放在Windows的c:windows/system32下 ...

  6. Xamarin.Android RelativeLayout

    初次接触Xamarin.Android. 由于国内Xamarin的资料少见,我大多参考JAVA原生代码,慢慢摸索过来. 我把摸索出来的结果广而告之,希望后来人能少走一点弯路,也希望你也能做出一份贡献. ...

  7. Android ScrollView 去掉 scrollbar 和 阴影

    1. 在 layout 里: android:scrollbars="none" android:overScrollMode="never" 2. 代码里 / ...

  8. 关于Collections的操作方法

    Collections是一个包装类,其中包含有各种有关集合操作的静态多态方,比如可以作用在List和Set上,此类不能实例化. 排序 Integer[] array = new Integer[]{3 ...

  9. 学习笔记|Java 教程|菜鸟教程

    一.Java 教程 1.Java 教程 Java 在线工具 JDK 1.6 在线中文手册 我的第一个 JAVA 程序 创建文件 HelloWorld.java(文件名需与类名一致), 代码如下: pu ...

  10. PHP中运算符优先级

    运算符优先级指定了两个表达式绑定得有多“紧密”.例如,表达式 1 + 5 * 3 的结果是 16 而不是 18 是因为乘号(“*”)的优先级比加号(“+”)高.必要时可以用括号来强制改变优先级.例如: ...