2

为什么我不能在 line 上放置断点String a;

public void localMethod() {
    String a;
    a = "haha";
    System.out.println(a);
}

我知道局部变量在我明确地为其赋值之前不会被初始化。但它是一行代码,它做了一些事情。为什么我不能停在那里?哪些行有资格成为断点?

我正在使用 Eclipse,jdk6_31

4

4 回答 4

4

声明本身并不是真正的可执行代码——它只是声明某些东西的存在。您应该能够在第二行放置一个断点,这实际上了一些事情。

诚然,我看不出 IDE 不支持将断点添加到不可执行行的概念的任何原因——它可能必须真正将断点安装在执行环境中的可执行点...

编辑:为了澄清我的意思,这段代码:

public void foo() {
    String a;
    String b;
    a = "hello";
    b = " world";
    System.out.println(a + b);        
}

将编译为与以下相同的字节码:

public void foo() {
    String a;
    a = "hello";
    String b;
    b = " world";
    System.out.println(a + b);        
}

由于声明,没有代码必须执行 - 它不会在那个时间点或类似的地方保留空间。编译器在方法的堆栈空间内分配一个“槽”,并将在整个方法中使用该槽——但它可以重用同一个槽而无需额外初始化,例如,即使变量是在循环中声明的。

于 2012-04-26T15:06:17.577 回答
4

断点由 IDE/编译器生成,用于监视正在执行的某些行。这些由字节码中的行号表示。表示变量声明和初始化的字节码在编译过程中合并为一个步骤。因此,如果从赋值中分离出变量的声明,则生成的字节码中没有可用的断点。

这是您的示例的字节码:

public class Example {
    public void localMethod() {
        String a;
        a = "haha";
        System.out.println(a);
    }
}

到:

public class stackoverflow/Example {

  // compiled from: Example.java

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 6 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lstackoverflow/Example; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x1
  public localMethod()V
   L0
    LINENUMBER 9 L0
    LDC "haha"
    ASTORE 1
   L1
    LINENUMBER 10 L1
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 1
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L2
    LINENUMBER 11 L2
    RETURN
   L3
    LOCALVARIABLE this Lstackoverflow/Example; L0 L3 0
    LOCALVARIABLE a Ljava/lang/String; L1 L3 1
    MAXSTACK = 2
    MAXLOCALS = 2
}

请注意,第 8 行没有 LINENUMBER 标记,在我的 IDE 中它代表String a声明。

于 2012-04-26T15:07:14.113 回答
1

没有对应于a局部变量声明的字节码,因此您不能在声明时设置断点,只能在初始化时设置。

示例.java:

class Sample {
public void localMethod() {
    String a;
    a = "haha";
    System.out.println(a);
}
}

javac 示例.java; javap -c 示例

class Sample extends java.lang.Object{
Sample();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public void localMethod();
  Code:
   0:   ldc #2; //String haha
   2:   astore_1
   3:   getstatic   #3; //Field java/lang/System.out:Ljava/io/PrintStream;
   6:   aload_1
   7:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   10:  return

}
于 2012-04-26T15:12:16.727 回答
0

断点允许用户在特定位置暂停程序的执行。断点通常与源代码一起显示在 UI 中。当程序执行过程中遇到断点时,程序会挂起并触发以 BREAKPOINT 为原因的 SUSPEND 调试事件。现在..当你编译它时..声明和赋值属于一个步骤..首先它被声明然后赋值..所以最后一步是赋值..因此,你可以在赋值上放一个断点,但不能关于申报。

于 2012-04-26T15:13:36.217 回答