the unchecked warnings

本文深入探讨Java中的泛型使用、非检查转换及其潜在风险,包括从原始类型到参数化类型的非检查转换规则,以及如何在新旧代码间平滑过渡。通过实例说明了非检查警告的触发条件,以及在访问成员或构造函数时可能出现的警告情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

5.1.9. Unchecked Conversion 

 

Let G name a generic type declaration with n type parameters. 

There is an unchecked conversion from the raw class or interface type (§4.8G to any parameterized type of the form G<T1,...,Tn>. 

There is an unchecked conversion from the raw array type G[] to any array type type of the form G<T1,...,Tn>[].  

Use of an unchecked conversion causes a compile-time unchecked warning unless G<...> is a parameterized type in which all type arguments are unbounded wildcards (§4.5.1), or the unchecked warning is suppressed by the SuppressWarnings annotation (§9.6.3.5).

 

Unchecked conversion is used to enable a smooth interoperation of legacy code, written before the introduction of generic types, with libraries that have undergone a conversion to use genericity (a process we call generification). In such circumstances (most notably, clients of the Collections Framework in java.util), legacy code uses raw types (e.g. Collection instead of Collection<String>). Expressions of raw types are passed as arguments to library methods that use parameterized versions of those same types as the types of their corresponding formal parameters. 

 

Such calls cannot be shown to be statically safe under the type system using generics. Rejecting such calls would invalidate large bodies of existing code, and prevent them from using newer versions of the libraries. This in turn, would discourage library vendors from taking advantage of genericity. To prevent such an unwelcome turn of events, a raw type may be converted to an arbitrary invocation of the generic type declaration to which the raw type refers. While the conversion is unsound, it is tolerated as a concession to practicality. An unchecked warning is issued in such cases. 

 

 

5.5.2. Checked Casts and Unchecked Casts

 

A cast from a type S to a type T is statically known to be correct if and only if <: T (§4.10). 

A cast from a type S to a parameterized type (§4.5T is unchecked unless at least one of the following conditions holds:

  • <: T

  • All of the type arguments (§4.5.1) of T are unbounded wildcards

  • <: S and S has no subtype X other than T where the type arguments of X are not contained in the type arguments of T. 

A cast from a type S to a type variable T is unchecked unless <: T. 

An unchecked cast from S to T is completely unchecked if the cast from |S| to |T| is statically known to be correct. Otherwise, it is partially unchecked. 

An unchecked cast causes a compile-time unchecked warning, unless suppressed by the SuppressWarnings annotation (§9.6.3.5). 

A cast is checked if it is not statically known to be correct and it is not unchecked. 

If a cast to a reference type is not a compile-time error, there are several cases: 

  • The cast is statically known to be correct.

    No run-time action is performed for such a cast.

  • The cast is a completely unchecked cast.

    No run-time action is performed for such a cast.

  • The cast is a partially unchecked cast.

    Such a cast requires a run-time validity check. The check is performed as if the cast had been a checked cast between |S| and |T|, as described below.

  • The cast is a checked cast.

    Such a cast requires a run-time validity check. If the value at run time is null, then the cast is allowed. Otherwise, let R be the class of the object referred to by the run-time reference value, and let T be the erasure (§4.6) of the type named in the cast operator. A cast conversion must check, at run time, that the class R is assignment compatible with the type T, via the algorithm in §5.5.3.

    Note that R cannot be an interface when these rules are first applied for any given cast, but R may be an interface if the rules are applied recursively because the run-time reference value may refer to an array whose element type is an interface type.

 

 

4.8 Raw Types

参考地址:https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.8

The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of generics into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.

To make sure that potential violations of the typing rules are always flagged, some accesses to members of a raw type will result in compile-time unchecked warnings. The rules for compile-time unchecked warnings when accessing members or constructors of raw types are as follows:

  • At an assignment to a field: if the type of the left-hand operand is a raw type, then a compile-time unchecked warning occurs if erasure changes the field's type.

  • At an invocation of a method or constructor: if the type of the class or interface to search (§15.12.1) is a raw type, then a compile-time unchecked warning occurs if erasure changes any of the formal parameter types of the method or constructor.

  • No compile-time unchecked warning occurs for a method call when the formal parameter types do not change under erasure (even if the result type and/or throwsclause changes), for reading from a field, or for a class instance creation of a raw type.

Note that the unchecked warnings above are distinct from the unchecked warnings possible from unchecked conversion (§5.1.9), casts (§5.5.2), method declarations (§8.4.1§8.4.8.3§8.4.8.4§9.4.1.2), and variable arity method invocations (§15.12.4.2).

The warnings here cover the case where a legacy consumer uses a generified library. For example, the library declares a generic class Foo<T extends String> that has a field f of type Vector<T>, but the consumer assigns a vector of integers to e.f where e has the raw type Foo. The legacy consumer receives a warning because it may have caused heap pollution (§4.12.2) for generified consumers of the generified library.

(Note that the legacy consumer can assign a Vector<String> from the library to its own Vector variable without receiving a warning. That is, the subtyping rules (§4.10.2) of the Java programming language make it possible for a variable of a raw type to be assigned a value of any of the type's parameterized instances.)

The warnings from unchecked conversion cover the dual case, where a generified consumer uses a legacy library. For example, a method of the library has the raw return type Vector, but the consumer assigns the result of the method invocation to a variable of type Vector<String>. This is unsafe, since the raw vector might have had a different element type than String, but is still permitted using unchecked conversion in order to enable interfacing with legacy code. The warning from unchecked conversion indicates that the generified consumer may experience problems from heap pollution at other points in the program.

 

 

例1:

class Cell<E> {
    E value;

    Cell(E v)     { value = v; }
    E get()       { return value; }
    void set(E v) { value = v; }

    public static void main(String[] args) {
        Cell x = new Cell<String>("abc"); // unchecked warning
        System.out.println(x.value);  // OK, has type Object
        System.out.println(x.get());  // OK, has type Object
        x.set("def");                 // unchecked warning
    }
}

Cell x  = new Cell<String>("abc")出现非检查警告:

At an assignment to a field: if the type of the left-hand operand is a raw type, then a compile-time unchecked warning occurs if erasure changes the field's type. 

x.set("def")出现非检查警告:

At an invocation of a method or constructor: if the type of the class or interface to search (§15.12.1) is a raw type, then a compile-time unchecked warning occurs if erasure changes any of the formal parameter types of the method or constructor.

 

例2:

import java.util.*;
class NonGeneric {
    Collection<Number> myNumbers() { return null; }
}

abstract class RawMembers<T> extends NonGeneric implements Collection<String> {
    static Collection<NonGeneric> cng =  new ArrayList<NonGeneric>();

    public static void main(String[] args) {
        RawMembers rw = null;
        Collection<Number> cn = rw.myNumbers();     // OK
        Iterator<String> is = rw.iterator();        // Unchecked warning
        Collection<NonGeneric> cnn = rw.cng;      // OK, static member
    }
}

 

Collection<Number> cn = rw.myNumbers();没有出现警告:

No compile-time unchecked warning occurs for a method call when the formal parameter types do not change under erasure (even if the result type and/or throwsclause changes), for reading from a field, or for a class instance creation of a raw type.

 

In this program, RawMembers<T> inherits the method:

Iterator<String> iterator()

from the Collection<String> superinterface. However, the type RawMembers inherits iterator() from the erasure of Collection<String>, which means that the return type of iterator() is the erasure of Iterator<String>Iterator.

As a result, the attempt to assign to rw.iterator() requires an unchecked conversion (§5.1.9) from Iterator to Iterator<String>, causing an unchecked warning to be issued.

In contrast, the static member cng retains its full parameterized type even when accessed through a object of raw type. (Note that access to a static member through an instance is considered bad style and is to be discouraged.) The member myNumbers is inherited from the NonGeneric class (whose erasure is also NonGeneric) and so retains its full parameterized type.

 

Raw types are closely related to wildcards. Both are based on existential types. Raw types can be thought of as wildcards whose type rules are deliberately unsound, to accommodate interaction with legacy code. Historically, raw types preceded wildcards; they were first introduced in GJ, and described in the paper Making the future safe for the past: Adding Genericity to the Java Programming Language by Gilad Bracha, Martin Odersky, David Stoutamire, and Philip Wadler, in Proceedings of the ACM Conference on Object-Oriented Programming, Systems, Languages and Applications (OOPSLA 98), October 1998.

  

 

 

 

 

 

 

 

 

 

 

 

 

  

  

 

转载于:https://www.cnblogs.com/extjs4/p/8526318.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值