类字段和最终变量

时间:2013-07-08 16:30:01

标签: java

据我所知,匿名内部类中的内部方法可以使用final varibles或class字段。 它们之间有显着差异吗? 例如:

 final int[] intArr = new int[1];

Button testButton1 = (Button) findViewById(R.id.btnTest1);
testButton1.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
    intArr[0]++;
    Log.i("test", String.valueOf(intArr[0]));
  }
});

Button testButton2 = (Button) findViewById(R.id.btnTest2);
testButton2.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
    intArr[0]--;
    Log.i("test", String.valueOf(intArr[0]));
  }
});

我有2个按钮,它们都使用 intArr [0] ,可以获取并设置它的值。如果我将 intArr [0] 替换为某些类字段,例如 private int value; ,则会出现相同的行为 基于此,我得出结论,类字段和最终变量基本相同(我的意思是它们在字节码中表示相同)并且仅在范围和分配值的可能性方面存在差异。 我是对的吗?

4 个答案:

答案 0 :(得分:2)

  

(我的意思是它们在字节码中表示相同)

让我们来看看。拿这个代码

class Example {

  private static int[] outside = new int[]{1};

  public static void main(String [] args){
    final int[] inside = new int[]{2};

    Object inner = new Object(){{
      System.out.println(outside[0]);
      System.out.println(inside[0]);
    }};
   }
  }

将其编译为两个类,然后使用javap -c对其进行反汇编以获取

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

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1      
       1: newarray       int
       3: dup           
       4: iconst_0      
       5: iconst_2      
       6: iastore       
       7: astore_1      
       8: new           #3                  // class Example$1
      11: dup
      12: aload_1       
      13: invokespecial #4                  // Method Example$1."<init>":([I)V
      16: astore_2      
      17: return        

  static int[] access$000();
    Code:
       0: getstatic     #1                  // Field outside:[I
       3: areturn       

  static {};
    Code:
       0: iconst_1      
       1: newarray       int
       3: dup           
       4: iconst_0      
       5: iconst_1      
       6: iastore       
       7: putstatic     #1                  // Field outside:[I
      10: return        
}

final class Example$1 {
  final int[] val$inside;

     Example$1(int[]);
        Code:
           0: aload_0       
           1: aload_1       
           2: putfield      #1                  // Field val$inside:[I
           5: aload_0       
           6: invokespecial #2                  // Method java/lang/Object."<init>":()V
           9: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
          12: invokestatic  #4                  // Method Example.access$000:()[I
          15: iconst_0      
          16: iaload        
          17: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
          20: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
          23: aload_0       
          24: getfield      #1                  // Field val$inside:[I
          27: iconst_0      
          28: iaload        
          29: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
          32: return        
    }

我们看到变量inside是作为类Example$1内的字段创建的,而变量outside是通过{{1}中自动生成的方法access$000访问的}}。因此没有 - 它们在字节码中没有相同的表示。

答案 1 :(得分:1)

最终变量仍然是变量。不同之处在于您只能分配一次值。否则他们的行为相同。字段也可以是最终的(尽管它被称为常量),它的范围保持不变。

final关键字也称为“修饰符”,因为它会修改成员的行为,而不是将其转换为其他内容。

请记住,您仍然可以更改最终变量指向的对象。在您的情况下,您可以修改数组,尽管变量是最终的。你不能做的是为你的变量分配另一个数组。

答案 2 :(得分:0)

final指的是常量变量。你不能改变常量的值。但是你可以改变非最终成员变量的值

答案 3 :(得分:0)

外部类中的字段通过Outer.this引用,实际上是final本地字段。所以在某种程度上,并没有什么区别。显然,final只对变量有意义,而不是它指向的对象。

想象一下,如果您将外部this复制到封闭方法中的本地final字段。

final Outer outer = this;
testButton1.setOnClickListener(new View.OnClickListener() {

outer与匿名内部类中的Outer.this行为相同。