Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/395.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么不干脆禁用未检查的警告?_Java_Generics_Unchecked - Fatal编程技术网

Java 为什么不干脆禁用未检查的警告?

Java 为什么不干脆禁用未检查的警告?,java,generics,unchecked,Java,Generics,Unchecked,当开发人员与非通用API交互时,他们通常会遇到“未检查”的警告。考虑下面的例子: import java.util.AbstractList; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class IterableNodeList<T extends Node> extends AbstractList<T> { private NodeList list; public

当开发人员与非通用API交互时,他们通常会遇到“未检查”的警告。考虑下面的例子:

import java.util.AbstractList;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class IterableNodeList<T extends Node> extends AbstractList<T>
{
    private NodeList list;

    public IterableNodeList(NodeList list)
    {
        this.list = list;
    }

    public T get(int index)
    {
        return (T)this.list.item(index);
    }

    public int size()
    {
        return this.list.getLength();
    }
}
import java.util.AbstractList;
导入org.w3c.dom.Node;
导入org.w3c.dom.NodeList;
公共类IterableNodeList扩展了AbstractList
{
私有节点列表;
公共IterableNodeList(节点列表)
{
this.list=列表;
}
公共T获取(整数索引)
{
返回(T)该列表项(索引);
}
公共整数大小()
{
返回此.list.getLength();
}
}
当然,我们可以投入精力,以这样一种方式编写它:在类上使用类型参数
T
,并使用构造函数参数
class
,匹配成员变量和
cast()
调用

或者,可以考虑简单地编辑IDE配置和构建脚本(例如Maven POM),以完全禁用此编译器警告。现在,如果我们这样做,代码可以保持原样,但我确信这样做肯定有缺点。然而,我想不出任何合理、现实的例子

  • 此警告提供的价值大于“在此处粘贴
    @SuppressWarnings
    ,反正没有其他选项”,以及
  • 结果代码的行为实际上与我们忽略(禁用)警告的代码不同(更安全)
你能想出这样的例子吗?或者说出另一个为什么在全球范围内禁用这些“未经检查”的警告是个坏主意的原因吗?或者这真的是个好主意

更新
前面的例子实际上并没有引起警告。有些答案现在不再有意义了。很抱歉给您带来不便。

根据
有效Java第二版
第24项
,广泛而频繁地使用
@superswarnings
通常是一个坏主意,特别是如果您将此注释应用于整个类,因为此类警告显示您的代码中可能存在危险的部分,这可能导致
ClassCastException

但在某些情况下,它可能很有用,例如在
ArrayList
toArray
方法实现中:

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}
@SuppressWarnings(“未选中”)
公共T[]toArray(T[]a){
如果(a.长度<尺寸)
//创建a的运行时类型的新数组,但我的内容:
return(T[])array.copyOf(elementData,size,a.getClass());
System.arraycopy(elementData,0,a,0,size);
如果(a.长度>尺寸)
a[size]=null;
返回a;
}

您的第二个示例不会在我的eclipse中导致编译器警告,我也想不出它应该出现的原因。因此,这是我首选的解决方案

存在未经检查的警告的原因是忽略它们会导致堆污染:

检查普通类型转换,即如果值与所需类型不兼容,则会导致
ClassCastException
。未选中的强制转换不能保证成功,即即使值的类型不正确,也可以成功。这可能导致一个变量包含的值不是其声明类型的子类型,这是Java规范“堆污染”的条件。为了确保运行时类型系统的完整性,每当使用泛型类型的变量时,Java编译器将插入普通类型转换。在存在堆污染的情况下,这些强制转换可能会失败

例如,该计划:

static void appendTo(List list) {
    list.add(1); // unchecked warning
}

static void printLengths(List<String> strings) {
    for (String s : strings) { // throws ClassCastException
        System.out.println(s.length());
    }
}

public static void main(String[] args) throws Exception {
    List<String> strings = new ArrayList<>();
    strings.add("hello");
    appendTo(strings);
    printLengths(strings);
}
摘自Java第二版:

SuppressWarnings
注释可以从 对整个类的单个局部变量声明始终在尽可能小的范围内使用
SuppressWarnings
注释。通常情况下,这将是一个 变量声明或非常短的方法或构造函数。切勿对整个类使用
SuppressWarnings
。这样做可能会掩盖严重警告

如果您发现自己在方法上使用
SuppressWarnings
注释,或 如果构造函数的长度超过一行,则可以将其移动到本地 变量声明。您可能需要声明一个新的局部变量,但这是值得的 它

在return语句上放置
SuppressWarnings
注释是非法的, 因为它不是一个声明[JLS,9.7]。您可能会尝试放置注释 在整个方法上,但不要。相反,声明一个局部变量来保存 返回值并注释其声明


我的问题是要得到这些“可能是危险的代码片段”的例子,因为我想不出一个。如果我们不能给出编译器发出此类警告的好例子,我们可以使用构建脚本/IDE(Maven,eclipse)设置禁用它们,然后甚至不必到处添加@SuppressWarnings@JensBannmann查看我的答案,并向下滚动到“关于堆污染的说明”以查看危险代码的示例。@PaulBellora好的,这是一个很好的答案-尤其是“在调用站点而不是方法中爆炸”部分。你能在这里发表你的评论作为答案吗,或者甚至把“关于堆污染的注释”部分复制到答案中?目前我的问题没有一个直接的答案,我认为如果有,对其他人可能会有用。@JensBannmann实际上非常接近同一点:“程序……在源代码中不包含强制转换的行中抛出ClassCastException。这可能会严重迷惑大多数程序员。”但我会在有机会的时候考虑把这一部分变成答案。这个问题其实更合适。@PaulBellora:我又一次被这个问题绊倒了。请在这里将您的堆污染注释转换为答案:-)在示例中,我没有处理键入的列表,我现在已经使这一点更加明显。我的第二个示例确实引发了编译器警告,第三个则没有。但是,在第三个例子中,我们得到了什么
class Habitat<T> {
    private final Class<T> clazz;

    private List<T> inhabitants;

    void add(Object o) {
        inhabitants.add(clazz.cast(o));
    }
}