- 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); }