Types方法之isCastable-isConvertible
- 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.6. Numeric Promotions
 
如上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时,不太明白??
下面的逻辑需要明白如下两个概念:
举几个是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的更多相关文章
- Types方法之upperBound-lowerBound-isUnbounded-containsType
		
1.upperBound(Type t)方法 /** * The "rvalue conversion". * The upper bound of most types is t ...
 - Types方法之isSameType-isSuperType-isSubType
		
4.isSameType() 方法 /** * Is t the same type as s? */ public boolean isSameType(Type t, Type s) { retu ...
 - runtime第三部分方法和消息
		
接上一篇http://www.cnblogs.com/ddavidXu/p/5924049.html 转载来源http://www.jianshu.com/p/6b905584f536 http:// ...
 - Runtime 动态加载方法
		
动态加载 #import"ViewController.h" #import"Person.h" @interfaceViewController() @end ...
 - Objective-C Runtime 运行时之三:方法与消息
		
基础数据类型 SEL SEL又叫选择器,是表示一个方法的selector的指针,其定义如下: typedef struct objc_selector *SEL; objc_selector结构体的详 ...
 - Objective-C Runtime 运行时之三:方法与消息(转载)
		
前面我们讨论了Runtime中对类和对象的处理,及对成员变量与属性的处理.这一章,我们就要开始讨论Runtime中最有意思的一部分:消息处理机制.我们将详细讨论消息的发送及消息的转发.不过在讨论消息之 ...
 - iOS运行时使用(动态添加方法)
		
1 举例 我们实现一个Person类 然后Person 其实是没得对象方法eat:的 下面调用person的eat方法 程序是会奔溃的 那么需要借助运行时动态的添加方法 Person *p = [[ ...
 - 快速上手Runtime(四)之动态添加方法
		
如果一个类方法非常多,加载类到内存的时候也比较耗费资源,可以使用动态给某个类,添加方法解决.做到优化内存,节省资源的效果. // // Person.m // ResolveInstanceMetho ...
 - iOS---runtime介绍
		
本文目录 1.Runtime简介 2.Runtime相关的头文件 3.技术点和应用场景 3_1.获取属性\成员变量列表 3_2.交换方法实现 3_3.类\对象的关联对象,假属性 3_4.动态添加方法, ...
 
随机推荐
- Summary  #ToBeContinue......
			
一.请回望暑假时的第一次作业,你对于软件工程课程的想象1)对比开篇博客你对课程目标和期待,“希望通过实践锻炼,增强计算机专业的能力和就业竞争力”,对比目前的所学所练所得,在哪些方面达到了你的期待和目标 ...
 - Mac提示App已损坏 你应该将它移到废纸篓的解决方案
			
现象 "Elmedia Player.app"已损坏,打不开. 您应该将它移到废纸篓. 原因 很多朋友们在安装软件时Mac OS系统出现提示"XXXApp 已损坏&quo ...
 - 浏览器缓存和Service Worker
			
浏览器缓存和Service Worker @billshooting 2018-05-06 字数 6175 Follow me on Github 标签: BOM 1. 传统的HTTP浏览器缓存策略 ...
 - C# 使用 COALESCE 表达式简化 Null 检查
			
下面这个判断 null 的语句: a == null ? b: a 可以用 COALESCE 表达式,简化成: a ?? b
 - deepin jdk 安装
			
一.安装JDK环境 1 .卸载系统自带的Openjdk(可能不需要) 先用检测是否安装了openjdk dpkg -l | grep openjdk 如果安装了, 使用下面命令卸载. sudo apt ...
 - C# 键盘中的按键对应KeyValue
			
首先先看一下什麼情況下需要對按鍵進行識別: KeyPress事件響應函數中,有KeyPressEventArgs, 對應於e.KeyChar; KeyDown事件響應中有KeyEventArgs 求取 ...
 - robot framework学习笔记之七—连接mysql数据库
			
1.安装Database-Library 输入命令:pip install robotframework_databaselibrary 2.添加Database的Library 3.实例 * ...
 - HTTP请求报文支持的各种方法
			
常见的HTTP方法如下: 1.GET GET是最常用的方法.通常用于请求服务器发送某个资源. 2.HEAD HEAD与GET的行为类似,但服务器在响应中只返回首部,不会返回实体的部分.这就允许客户端在 ...
 - jquery源码解析:addClass,toggleClass,hasClass详解
			
这一课,我们将继续讲解jQuery对元素属性操作的方法. 首先,我们先看一下这几个方法是如何使用的: $("#div1").addClass("box1 box2&quo ...
 - python --爬虫基础 --爬取今日头条    使用 requests 库的基本操作, Ajax
			
'''思路一: 由于是Ajax的网页,需要先往下划几下看看XHR的内容变化二:分析js中的代码内容三:获取一页中的内容四:获取图片五:保存在本地 使用的库1. requests 网页获取库 2.fro ...