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.动态添加方法, ...
随机推荐
- Window vista 以上制作自定义证书并为端口配置ssl
此处的关键在于证书需要分两步,不然在配置ssl时总会有错误.也许makecert命令也会有些玄机,但是管他呢,请按以下步骤和命令配置,几分钟就可成功: 证书制作: 1, 在开始/所有程序(或其他地方 ...
- 两种步骤 更改 EBS R12界面LOGO以及内容
from:metalink more: Note 174219.1 - How To Change The Logo In The Oracle Application Menu Note 84975 ...
- [转]解决Mysql InnoDB: Failing assertion: ret || !assert_on_error问题
国庆回来后,发现mysql停止服务了,没办法继续启动了.查看日志,看到: 131008 09:56:03 mysqld_safe Starting mysqld daemon with databas ...
- kubernetes yaml
apiVersion: v1 #指定api版本,此值必须在kubectl apiversion中 kind: Deployment #指定创建资源的角色/类型 metadata: #资源的元数据/属性 ...
- postgres数据库参数配置说明介绍
访问 1. listen_addresses 监听访问地址 2. port 监听端口 3. max_connections 最大连接数 4. 性能 1. shared_buffers PostgreS ...
- Xshell传输文件
用rz,sz命令在xshell传输文件 很好用,然后有时候想在windows和linux上传或下载某个文件,其实有个很简单的方法就是rz,sz 首先你的Ubuntu需要安装rz.sz(如果没有安装请执 ...
- [Erlang28]使用匿名函数灵活组合不同的case
cowboy_http.erl里面的date1/2 启示: 以前一般写case里都是这样子: date1(Date) -> case month1(Date) of {error,badarg} ...
- 经典的兔子生兔子问题(C#递归解法)
古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 思路:先求出每个月新增的兔子,再用循环求和即可算出这个月 ...
- 利用反射(Reflection)处理对象
创建一个学生类: public class Student { public int Id { set; get; } public string Name { set; get; } public ...
- IdHTTPServer使用注意问题
如果在同一电脑上运行多个IdHTTPServer实例,IdHTTPServer使用时候,一定要注意“DefaultPort”属性,其实真正绑定端口是这个属性决定的,所以希望IdHTTPServer绑定 ...