Java 为什么可以';我不能在try with resources try子句中重用引用变量吗?

Java 为什么可以';我不能在try with resources try子句中重用引用变量吗?,java,java-7,Java,Java 7,我注意到这不会编译: PrintWriter printWriter = new PrintWriter("test.txt"); printWriter.append('a'); printWriter.close(); printWriter = null; try(printWriter = new PrintWriter("test.txt")) { } 带有:Error:(17,24)java:应为 此时只有一个新变量起作用: try(PrintWriter printWrite

我注意到这不会编译:

PrintWriter printWriter = new PrintWriter("test.txt");
printWriter.append('a');
printWriter.close();
printWriter = null;

try(printWriter = new PrintWriter("test.txt")) {

}
带有:
Error:(17,24)java:应为

此时只有一个新变量起作用:

try(PrintWriter printWriter2 = new PrintWriter("test.txt")) {

}

我的直觉是,只需要一个新的对象,但显然需要一个新的引用。很明显,这是编译时类型检查的结果,但是为什么旧的引用不起作用呢?

答案很简单,因为它将在try with resources完成后关闭。更具体地说

部分(加粗)表示

ResourceSpecification使用初始值设定项表达式声明一个或多个局部变量,作为try语句的资源

如果资源规范中声明的资源未明确声明为最终资源,则该资源隐式声明为最终资源(§4.12.4)

ResourceSpecification中声明的变量类型必须是AutoCloseable的子类型,否则会发生编译时错误


对于最不满意的答案,因为规范中定义的语法需要变量声明。看看语法是什么

TryWithResourcesStatement:
    try ResourceSpecification Block Catchesopt Finallyopt

ResourceSpecification:
    ( Resources ;opt )

Resources:
    Resource
    Resource ; Resources

Resource:
    VariableModifiers[opt] Type VariableDeclaratorId = Expression
我们可以看到
TryWithResourcesStatement
需要一个
ResourceSpecification
,它是一个或多个
资源
,由圆括号包围并用分号分隔。每个资源都需要一个类型和名称(
type
VariableDeclaratorId


因此,编译器需要它,因为规范需要它。您需要深入研究创建此功能的过程,以了解为什么它被认为是必要的

从规范的角度来看,我认为@Elliot的答案中有加粗的关键词。如果变量必须是局部变量,那么这就解释了为什么需要类型标识符。我建议@Elliots answer中的重要单词是在“一个ResourceSpecification声明一个或多个…”中声明的。OP中的变量是一个局部变量(作用域与try with resource块位于同一个块中)。但是说ResourceSpecification声明了一个变量有一个非常具体的含义。它再次归结为“因为spec这么说”Elliot更喜欢文本描述,我更喜欢形式语法,两者说的都一样。被关闭的对象和它作为局部变量之间的联系是什么?外部范围中的引用可以被关闭,然后重新初始化。