简体   繁体   English

在 For 循环外部声明的变量与在内部声明的变量

[英]Variable Declared Outside of For Loop Vs Inside

//assume there is a java class call Node, and node is an array of Node

for(Node i: node){
    Node j = i;
}

Node j;
for(Node i: node){
    j = i; 
}

Can someone please explain essentially what's the difference between this two?有人可以解释一下这两者之间有什么区别吗?

Node j; on its own isn't 'code', in the sense that it results in zero bytecode - it does nothing on its own.它本身不是“代码”,因为它导致零字节码 - 它自己什么都不做。 It's a 'declaration'.这是一个“宣言”。 It's an instruction to the compiler.这是对编译器的指令。

You're telling the compiler: There is this thing;你在告诉编译器:有这个东西; I shall call it j , and it is a local variable.我称它为j ,它是一个局部变量。 Please fail my compilation unless you can 100% ensure that this variable only ever holds either null or " reference to an object whose actual type is either Node or some subtype of Node ".请让我的编译失败,除非您可以 100% 确保此变量仅包含null或“对实际类型为NodeNode的某个子类型的对象的引用”。 It decline to assign something to this variable right now;它现在拒绝给这个变量赋值; please fail to compile if I attempt to access it before you can 100% guarantee that some code has already ran that definitely assigned it first.如果我在您可以 100% 保证某些代码已经运行并且肯定首先分配它之前尝试访问它,请编译失败。

That's a ton of instructions for the compiler and absolutely none of it requires any code right then and there - it's just instructions for what to do in other lines of code - for example, in your second snippet, without that Node j;这是编译器的大量指令,绝对不需要任何代码,它只是说明在其他代码行中做什么 - 例如,在你的第二个片段中,没有那个Node j; at the top, j = i;在顶部, j = i; is not something that the compiler can do for you.不是编译器可以为您做的事情。 It has no idea what you intend to do there;它不知道你打算在那里做什么; it does not know what j is, you did not inform the compiler about it, and in java, the language spec indicates that you can't just make up variable names without first telling the compiler about them.它不知道j是什么,你没有通知编译器它,并且在 java 中,语言规范表明你不能在不先告诉编译器的情况下只编造变量名。

Thus, bytecode wise, the exact difference between your 2 specific snippets here is nothing - local variables are a figment of javac's imagination: As a concept, 'local variable' doesn't exist, at all, at the JVM/bytecode level: It's just 'slots' in the local frame (ie local variables have a number, not a name), or on-stack space.因此,在字节码方面,您的 2 个特定片段之间的确切区别是什么- 局部变量是 javac 想象的虚构:作为一个概念,在 JVM/字节码级别根本不存在“局部变量”:它是只是局部框架中的“槽”(即局部变量有一个数字,而不是名称),或堆栈空间。

In other words, to figure out what the difference might be, it's entirely a matter of answering the question: How does javac interpret these 2 snippets?换句话说,要弄清楚可能有什么区别,完全可以回答这个问题: javac如何解释这两个片段? Because bytecode wise there is not going to be any difference, ever.因为字节码明智,永远不会有任何区别。 Node j; simply cannot be bytecode - there is no such thing as a 'local variable' there, after all.根本不可能是字节码——毕竟那里没有“局部变量”这样的东西。

The only crucial difference is that any given local variable declaration (such as Node j; ) declares its existence for a certain scope: It says: "There is this thing called j for these specific lines and not for any others".唯一关键的区别是任何给定的局部变量声明(例如Node j; )都声明了它在某个范围内的存在:它说:“对于这些特定的行,有一个叫做j的东西,而不是其他任何行”。 That scope is simply the next nearest pair of braces.该范围只是下一个最近的大括号对。 So, in:所以,在:

void foo() {
  Node j;
  for(Node i: node){
      j = i; 
  }
}

You have declared that there is one local variable named j , and this applies to the entire foo() method (given that those are the nearest pair of braces when you look 'outwards' from your Node j; declaration.您已声明有一个名为j的局部变量,这适用于整个 foo() 方法(假设当您从Node j;声明中“向外”看时,它们是最近的一对大括号。

Whereas with:鉴于:

void foo() {
  for(Node i: node){
      Node j = i; 
  }
}

The 'scope' of your j declaration is that for loop - after all, that's the 'nearest pair'.您的j声明的“范围”是for循环- 毕竟,这是“最近的对”。 In other words, this is almost legal:换句话说,这几乎是合法的:

void foo() {
  Node j;
  for(Node i: node){
      j = i; 
  }
  System.out.println(j);
}

Except for one tiny little detail: The compiler cannot 100% guarantee that j is actually assigned when we get to the println line - after all, what if your node collection is actually empty?除了一个很小的细节:编译器不能 100% 保证当我们到达 println 行时j被实际分配 - 毕竟,如果你的node集合实际上是空的怎么办? Then j = i;那么j = i; ran zero times.跑了零次。 So if you try to compile the above, the compiler will actually refuse, saying j is not definitely assigned .因此,如果您尝试编译上述内容,编译器实际上会拒绝,说j is not definitely assigned的。 But make that Node j = null;但是让那个Node j = null; and the above code would compile and run.上面的代码将编译并运行。 In contrast to:对比:

void foo() {
  for(Node i: node){
      Node j = i; 
  }
  System.out.println(j);
}

This one doesn't compile with the error j? What are you talking about这个没有编译错误j? What are you talking about j? What are you talking about - the j you declared here only applies to all lines within the {} that goes with the for loop, thus, the mentioning of j in the println line is mentioning an unknown thing, and thus the compiler will complain about it in those terms: What is j ? j? What are you talking about - 你在这里声明的j只适用于{}中与 for 循环一起使用的所有行,因此,在println行中提到j是在提到一个未知的东西,因此编译器会抱怨用这些术语来说:什么是j

So what do I do?那我该怎么办?

Follow conventions: When in rome, act like romans.遵守约定:在罗马时,表现得像罗马人。 When programming java, write it the way the vast majority of java coders would.在编写 Java 时,请按照绝大多数 Java 程序员的方式编写。 Which means: Declare local variables at the latest possible point, at the right scope level.这意味着:在可能的最新点,在正确的范围级别声明局部变量。 Thus, something like:因此,类似:

void foo() {
  System.out.println("Starting method");

  Node lastVisited = null;
  for (Node i : nodes) {
    lastVisited = i;
  }
  System.out.println("Last visited: " + lastVisited);
}
  • Don't declare lastVisited at the top of the method.不要在方法顶部声明lastVisited
  • Do declare it before the for loop as we need it outside of it.请在 for 循环之前声明它,因为我们需要它在它之外。
  • Names are important.名字很重要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM