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.动态添加方法, ...
随机推荐
- Grails入门系列(一)
Grails入门系列(一) JAVAweb开发技术相对于php,python,note.js等新式技术更为复杂,向来以繁杂的配置著称,但是Java任然被广泛的应用于大型企业级的项目,主要是因为技术成熟 ...
- 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 ...
- HttpServletRequest介绍
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息. 二 ...
- CentOS 系统状况查看
1 磁盘 iostat 安装 yum install sysstat iostat -x Linux -.el7.x86_64 (sdw2) 2017年03月07日 _x86_64_ ( CPU ...
- Windows和linux通过命令互传文件
下载pscp https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html 放在Windows的c:windows/system32下 ...
- Xamarin.Android RelativeLayout
初次接触Xamarin.Android. 由于国内Xamarin的资料少见,我大多参考JAVA原生代码,慢慢摸索过来. 我把摸索出来的结果广而告之,希望后来人能少走一点弯路,也希望你也能做出一份贡献. ...
- Android ScrollView 去掉 scrollbar 和 阴影
1. 在 layout 里: android:scrollbars="none" android:overScrollMode="never" 2. 代码里 / ...
- 关于Collections的操作方法
Collections是一个包装类,其中包含有各种有关集合操作的静态多态方,比如可以作用在List和Set上,此类不能实例化. 排序 Integer[] array = new Integer[]{3 ...
- 学习笔记|Java 教程|菜鸟教程
一.Java 教程 1.Java 教程 Java 在线工具 JDK 1.6 在线中文手册 我的第一个 JAVA 程序 创建文件 HelloWorld.java(文件名需与类名一致), 代码如下: pu ...
- PHP中运算符优先级
运算符优先级指定了两个表达式绑定得有多“紧密”.例如,表达式 1 + 5 * 3 的结果是 16 而不是 18 是因为乘号(“*”)的优先级比加号(“+”)高.必要时可以用括号来强制改变优先级.例如: ...