Java 使用“时有无性能差异”;这是“xxx”;指向字段?

Java 使用“时有无性能差异”;这是“xxx”;指向字段?,java,performance,this,conventions,Java,Performance,This,Conventions,我刚刚开始使用Java,我想确保我的格式和约定从一开始就都是正确的 基本上,我的老师就是这么做的(这让我很恼火,因为它不可读) 而我更喜欢这样做: public class MyClass { private String name; private int age; public MyClass (String name, int age) { this.name = name; this.age = age; }

我刚刚开始使用Java,我想确保我的格式和约定从一开始就都是正确的

基本上,我的老师就是这么做的(这让我很恼火,因为它不可读)

而我更喜欢这样做:

public class MyClass
{   
    private String name;
    private int age;

    public MyClass (String name, int age)
    {
        this.name = name;
        this.age = age;
    }
}
public class MyClass {

    // ...

    public int calculateAgeDifference(MyClass other) {
        int age = other.age; // This hides this.age, don't do this
        return this.age - age;
    }
}
我只是想知道两者之间是否存在性能差异,以及哪一个更容易被接受。

我使用a来反编译此源代码:

public class Test {

    String s;

    public void a(String p){
        s=p;
    }

    public void b(String p){
        this.s=p;
    }

}
反编译器根据字节码创建了此源:

public class Test {

    String s;

    public void a(String p){
        this.s=p;
    }

    public void b(String p){
        this.s=p;
    }

}

正如@Brian在上面的评论中所说的那样。这两种方法完全相同。

两种形式生成的字节码相同,因此性能相同

如果编译后
javap-v
您的
MyClass
对象,则这两种情况下的头将具有相同的md5校验和值

表单
this.name
和不符合条件的表单
name
都会生成与下面的输出相同的putfield操作码,如
6:putfield#2

javap-vmyclass的完整输出

Classfile /tmp/java/MyClass.class
  Last modified Aug 14, 2013; size 309 bytes
  MD5 checksum a6981396520454dd2aeb9a474dd92c90
  Compiled from "MyClass.java"
public class MyClass
  SourceFile: "MyClass.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #5.#16         //  java/lang/Object."<init>":()V
   #2 = Fieldref           #4.#17         //  MyClass.name:Ljava/lang/String;
   #3 = Fieldref           #4.#18         //  MyClass.age:I
   #4 = Class              #19            //  MyClass
   #5 = Class              #20            //  java/lang/Object
   #6 = Utf8               name
   #7 = Utf8               Ljava/lang/String;
   #8 = Utf8               age
   #9 = Utf8               I
  #10 = Utf8               <init>
  #11 = Utf8               (Ljava/lang/String;I)V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               SourceFile
  #15 = Utf8               MyClass.java
  #16 = NameAndType        #10:#21        //  "<init>":()V
  #17 = NameAndType        #6:#7          //  name:Ljava/lang/String;
  #18 = NameAndType        #8:#9          //  age:I
  #19 = Utf8               MyClass
  #20 = Utf8               java/lang/Object
  #21 = Utf8               ()V
{
  java.lang.String name;
    flags: 

  int age;
    flags: 

  public MyClass(java.lang.String, int);
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=3
         0: aload_0       
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0       
         5: aload_1       
         6: putfield      #2                  // Field name:Ljava/lang/String;
         9: aload_0       
        10: iload_2       
        11: putfield      #3                  // Field age:I
        14: return        
      LineNumberTable:
        line 7: 0
        line 8: 4
        line 9: 9
        line 10: 14
}
Classfile/tmp/java/MyClass.class
最后修改日期:2013年8月14日;大小309字节
MD5校验和a6981396520454dd2aeb9a474dd92c90
从“MyClass.java”编译而来
公共类MyClass
源文件:“MyClass.java”
次要版本:0
主要版本:51
旗帜:ACC_公共、ACC_超级
固定池:
#1=Methodref#5.#16//java/lang/Object.“:()V
#2=Fieldref#4.#17//MyClass.name:Ljava/lang/String;
#3=Fieldref#4.#18//MyClass.年龄:I
#4=类别#19//MyClass
#5=类#20//java/lang/Object
#6=Utf8名称
#7=Utf8 Ljava/lang/String;
#8=Utf8年龄
#9=Utf8 I
#10=Utf8
#11=Utf8(Ljava/lang/String;I)V
#12=Utf8代码
#13=Utf8行号表
#14=Utf8源文件
#15=Utf8 MyClass.java
#16=名称和类型#10:#21/“”:()V
#17=name和type#6:#7//name:Ljava/lang/String;
#18=姓名和类型#8:#9//年龄:I
#19=Utf8 MyClass
#20=Utf8 java/lang/Object
#21=Utf8()V
{
java.lang.String名称;
旗帜:
智力年龄;
旗帜:
公共MyClass(java.lang.String,int);
旗帜:ACC_PUBLIC
代码:
堆栈=2,局部变量=3,参数大小=3
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:aload_0
5:aload_1
6:putfield#2//字段名:Ljava/lang/String;
9:aload_0
10:iload_2
11:putfield#3//现场年龄:I
14:返回
LineNumberTable:
第7行:0
第8行:4
第9行:9
第10行:14
}
这两个代码片段之间绝对没有性能差异。这只能归结为可读性


第二种变体通常是首选的,因为您对构造函数参数使用有意义的名称,而不是真正没有意义的
n
a
。看起来你的老师使用不同的名字只是为了避免使用
这个。
,我不建议这样做,因为显式的
这个。
强调你在分配类的字段,而不仅仅是任意变量,这可能是构造函数中的一个重要区别。

在这两种情况下,访问字段的字节码完全相同。对于第一个,
javap-c
返回:

public MyClass(java.lang.String, int);
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   aload_1
   6:   putfield        #2; //Field name:Ljava/lang/String;
   9:   aload_0
   10:  iload_2
   11:  putfield        #3; //Field age:I
   14:  return

}
相反,要:

int otherAge = other.age;

这使您的代码更具可读性。因此,如果您使用阴影,请仅在setter和constructor中使用阴影,我强烈建议在其他地方避免使用阴影。

没有性能差异。事实上,编译器在每次引用每个成员变量时都会使用
this.
预先挂起它。这是一个你喜欢用哪种方式来做的问题

没有任何区别-后者是标准的。事实上,使用变量名隐藏字段是唯一可以接受的。生成的字节码实际上是完全相同的。我真的是指这里。所以,没有性能差异。你所说的配置文件是什么意思?使用像“jprofiler”这样的配置文件器
public class MyClass {

    // ...

    public int calculateAgeDifference(MyClass other) {
        int age = other.age; // This hides this.age, don't do this
        return this.age - age;
    }
}
int otherAge = other.age;