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.动态添加方法, ...
随机推荐
- B-Spline 样条学习笔记
(1) 对于clamped样条曲线,节点区间的数目等于曲线段的数目. eg: B-样条曲线有11个控制点(即,n = 10), 3次P样条 (即, p=3) ,由 m=n+p+1 则有15 个节点 ...
- leetcode-8-String to Integer (atoi) (已总结)
8. String to Integer (atoi) Total Accepted: 93917 Total Submissions: 699588 Difficulty: Easy Impleme ...
- [SAP]编辑表
SAP中,不能直接修改表的内容,可以用SE16N进行调试打开编辑选项,进行修改. (注:直接修改数据有风险,首先要确认修改数据的关系或做好必要的备份) 1:运行SE16N ,填好表名,参数等. 2:在 ...
- Android源码设计模式分析开源项目
简述 该项目通过分析Android系统中的设计模式来提升大家对设计模式的理解,从源码的角度来剖析既增加了对Android系统本身的了解,也从优秀 的设计中领悟模式的实际运用以及它适用的场景,避免在实际 ...
- mysql5.7 创建新表时提示时间戳非法
# 背景 mysql版本5.7.8,需要创建新表,研发提供的sql文件,执行后报错如下: ERROR (): Invalid default value for 'deleted_at' 就猜测到时因 ...
- 什么是ODBC和JDBC?
jdbc是使用通过JAVA的数据库驱动直接和数据库相连,而jdbc-odbc连接的是ODBC的数据源,真正与数据库建立连接的是ODBC! 建议使用JDBC直接连接,同时最好使用连接池! JDBC 是 ...
- C#语言各个版本特性(一)
一.c#版本中添加的功能: C#2.0 泛型 部分类型 匿名方法 迭代器 可空类型 Getter / setter单独可访问性 方法组转换(代表) Co- and Contra-variance fo ...
- DataGridView添加一行数据、全选、取消全选、清空数据、删除选中行
.net 2005下的Windows Form Application,一个DataGridView控件和4个Button,界面设置如下: 代码如下,有注解,相信大家都看得明白: ...
- roadflow企业微信工作流程的配置与使用
1.在您的微信后台添加应用 应用地址: 待办事项 :http://demo.roadflow.net/RoadFlowCore/Mobile/WaitTask 已办事项:http://demo.roa ...
- WP8.1StoreApp(WP8.1RT)---发送邮件和短信
在WP7/8中,发送短信是利用了EmailComposeTask和SmsComposeTask来实现的. 在WP8.1 Store App中,原来的方式已经失效,采用了新的方法:ChatMessage ...