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.动态添加方法, ...
随机推荐
- (轉)CSS 单行溢出文本显示省略号...的方法(兼容IE FF)
轉自:http://www.cnblogs.com/hlz789456123/archive/2009/02/18/1392972.html html代码:<div><p>&l ...
- 笔记01 登录、常用配置参数、Action访问Servlet API 和设置Action中对象的值、命名空间和乱码处理、Action中包含多个方法如何调用
Struts2登录 1. 需要注意:Struts2需要运行在JRE1.5及以上版本 2. 在web.xml配置文件中,配置StrutsPrepareAndExecuteFilter或FilterDis ...
- AndroidStudio-Error Please select Android SDK
这里是×错误信息: 点击运行提示,Error:Please select Android SDK: 网上说了很多解决办法都不靠谱,只有这种方式是可以解决的: 点击:Exit: 红框的感叹号!已经提示了 ...
- md1
a b link to baidu 我不懂啊 这是什么意思 http://example.com/ 这里是一段代码' adsfasdf 你 你输得算好了 反正就这样吧,大概也值能这样了注 我想写一段引 ...
- 疑难杂症--在Windows Server 2008 R2上运行SQL Server 2008情况下,CPU过多导致的问题
64位的Windows7和Windows Server 2008 R2为了能够在一台机器上,支持超过64个逻辑CPU, 引入了Processor Group这个概念.Processor Group会把 ...
- vscode怎样新建项目
首先,vscode本身没有新建项目的选项,所以要先创建一个空的文件夹喔. 然后打开vscode,再在vscode里面打开文件夹,这样才可以创建项目. 选择之前创建的空文件将作为vscode的文 ...
- 字体变色详解链接:https://www.cnblogs.com/daofaziran/p/9015284.html
格式:\033[显示方式;前景色;背景色m + 结尾部分:\033[0m 字体色 | 背景色 | 颜色描述 ------------------------------------------- 30 ...
- html中事件调用JavaScript函数时有return与没有return的区别
JAVASCRIPT在事件中调用函数时用return返回值实际上是对window.event.returnvalue进行设置. 而该值决定了当前操作是否继续.当返回的是true时,将继续操作.当返回是 ...
- 黄包车比赛 python学习
将性别进行编码: https://github.com/Bifzivkar/Boutique-Travel-Services-Predict/blob/master/feature/2_feature ...
- 【文文殿下】[BZOJ4327] JSOI2012 玄武密码
SAM裸题.这道题卡空间.要小心数组别开炸了. #include<cstdio> #include<cstring> typedef long long ll; const i ...