【问题标题】:When should I use "this" in a class?我什么时候应该在课堂上使用“this”?
【发布时间】:2011-01-25 13:24:45
【问题描述】:

我知道this 指的是当前对象。但我不知道什么时候我真的需要使用它。例如,如果我在某些方法中使用x 而不是this.x,会有什么不同吗?可能是x 将引用所考虑方法的本地变量?我的意思是只有在这种方法中才能看到的变量。

this.method() 呢?我可以使用它吗?我应该使用它。如果我只使用method(),会不会默认应用到当前对象?

【问题讨论】:

    标签: java oop this


    【解决方案1】:

    java中的“this”关键字用于引用当前类对象。

    “this”关键字在java中有6种用法

    1. 访问类级别变量:通常在本地和类级别变量相同时使用
    2. 访问类方法:这是默认行为,可以忽略
    3. 用于调用同一类的其他构造函数
    4. 使用“this”关键字作为返回值:用于从方法返回当前实例
    5. 将“this”关键字作为参数传递给方法传递:用于将当前类实例作为参数传递
    6. this 关键字作为 构造函数的参数:用于将当前类实例作为参数传递

    参考:https://stacktraceguru.com/java/this-keyword-in-java

    【讨论】:

      【解决方案2】:

      有很多好的答案,但还有另一个非常小的理由将this 放在任何地方。如果您尝试从普通文本编辑器(例如记事本等)打开源代码,使用this 将使阅读更加清晰。

      想象一下:

      public class Hello {
          private String foo;
      
          // Some 10k lines of codes
      
          private String getStringFromSomewhere() {
              // ....
          }
      
          // More codes
      
          public class World {
              private String bar;
      
              // Another 10k lines of codes
      
              public void doSomething() {
                  // More codes
                  foo = "FOO";
                  // More codes
                  String s = getStringFromSomewhere();
                  // More codes
                  bar = s;
              }
          }
      }
      

      使用任何现代 IDE 都非常清楚,但使用常规文本编辑器阅读这将是一场噩梦。

      在您使用编辑器的“查找”功能之前,您将很难找到foo 所在的位置。然后你会出于同样的原因对getStringFromSomewhere() 尖叫。最后,在你忘记s是什么之后,bar = s会给你最后一击。

      对比一下:

      public void doSomething() {
          // More codes
          Hello.this.foo = "FOO";
          // More codes
          String s = Hello.this.getStringFromSomewhere();
          // More codes
          this.bar = s;
      }
      
      1. 您知道foo 是在外部类Hello 中声明的变量。
      2. 您知道getStringFromSomewhere() 也是在外部类中声明的方法。
      3. 您知道bar 属于World 类,而s 是在该方法中声明的局部变量。

      当然,每当您设计某物时,您都会创建规则。所以在设计你的 API 或项目时,如果你的规则包括“如果有人用记事本打开所有这些源代码,他或她应该朝自己的脑袋开枪”,那么你完全可以不这样做 /em>。

      【讨论】:

      • 很好的答案@Jai
      • shoot 的第一个原因是编写具有几行 10k 行代码的类,尤其是在代码已经拆分为不同的类时t需要嵌套:)
      • @LuCio Lol true xD
      【解决方案3】:

      关于William Brendel的帖子和dbconfessions的问题,关于案例2。这是一个例子:

      public class Window {
      
        private Window parent;
      
        public Window (Window parent) {
          this.parent = parent;
        }
      
        public void addSubWindow() {
          Window child = new Window(this);
          list.add(child);
        }
      
        public void printInfo() {
          if (parent == null) {
            System.out.println("root");
          } else {
            System.out.println("child");
          }
        }
      
      }
      

      在与对象建立父子关系时,我见过这种用法。但是,请注意,为了简洁起见,它被简化了。

      【讨论】:

        【解决方案4】:

        this 在构建器模式中很有用。

        public class User {
        
            private String firstName;
            private String surname;
        
            public User(Builder builder){
                firstName = builder.firstName;
                surname = builder.surname;
            }
        
            public String getFirstName(){
                return firstName;
            }
        
            public String getSurname(){
                return surname;
            }
        
            public static class Builder {
                private String firstName;
                private String surname;
        
                public Builder setFirstName(String firstName) {
                    this.firstName = firstName;
                    return this;
                }
        
                public Builder setSurname(String surname) {
                    this.surname = surname;
                    return this;
                }
        
                public User build(){
                    return new User(this);
                }
        
            }
        
            public static void main(String[] args) {
                User.Builder builder = new User.Builder();
                User user = builder.setFirstName("John").setSurname("Doe").build();
            }
        
        }
        

        【讨论】:

        • 这是我搜索并在这里结束时想要的答案类型,但您没有解释您的代码,所以大多数询问“this”的人不会理解“返回新用户(这个);”意思是,因为我不...
        • Builder 模式用于在构造时明确指定参数。与其让 new User(string, string) 没有简单的方法来分辨哪个字符串是哪个,不如使用 new Builder().setFirstName("Jane").setSurname("Smith").build()。您可以从 Builder.set...() 函数中返回它,以便将它们链接起来。
        【解决方案5】:

        @William Brendel 的回答很好地提供了三种不同的用例。

        用例 1:

        this 上的官方 java 文档页面提供了相同的用例。

        在实例方法或构造函数中,this 是对当前对象的引用——正在调用其方法或构造函数的对象。您可以使用 this 从实例方法或构造函数中引用当前对象的任何成员。

        它涵盖了两个例子:

        将此与字段一起使用将其与构造函数一起使用

        用例 2:

        本文未引用的其他用例:this 可用于同步多线程应用程序中的当前对象,以保护数据和方法的关键部分。

        synchronized(this){
            // Do some thing. 
        }
        

        用例 3:

        Builder 模式的实现依赖于使用this 来返回修改后的对象。

        参考这篇文章

        Keeping builder in separate class (fluent interface)

        【讨论】:

          【解决方案6】:

          this 关键字主要用于三种情况。第一个也是最常见的是在 setter 方法中消除变量引用的歧义。第二个是当需要将当前类实例作为参数传递给另一个对象的方法时。第三种是作为从构造函数中调用备用构造函数的一种方式。

          案例 1: 使用 this 消除变量引用的歧义。在 Java setter 方法中,我们通常传入一个与我们试图设置的私有成员变量同名的参数。然后我们将参数x 分配给this.x。这清楚地表明您正在将参数“name”的值分配给实例变量“name”。

          public class Foo
          {
              private String name;
          
              public void setName(String name) {
                  this.name = name;
              }
          }
          

          案例 2: 使用 this 作为参数传递给另一个对象。

          public class Foo
          {
              public String useBarMethod() {
                  Bar theBar = new Bar();
                  return theBar.barMethod(this);
              }
          
              public String getName() {
                  return "Foo";
              }
          }
          
          public class Bar
          {
              public void barMethod(Foo obj) {
                  obj.getName();
              }
          }
          

          案例 3: 使用 this 调用备用构造函数。在 cmets 中,trinithis 正确指出了 this 的另一个常见用法。当一个类有多个构造函数时,您可以使用this(arg0, arg1, ...) 调用您选择的另一个构造函数,前提是您在构造函数的第一行这样做。

          class Foo
          {
              public Foo() {
                  this("Some default value for bar");
          
                  //optional other lines
              }
          
              public Foo(String bar) {
                  // Do something with bar
              }
          }
          

          我还看到this 用于强调引用实例变量这一事实(无需消除歧义),但在我看来这种情况很少见。

          【讨论】:

          • +1 提到您也可以将 this 作为参数传递。 this 不仅用于范围消歧。
          • 当然构造函数内部也有this(arg1, arg2, ...)
          • @Hazior:我倾向于写一个简短的答案,然后随着时间的推移添加。有时这与其他人的答案重叠,有时则不然。在我最新的编辑中,trinithis 指出了我忘记的 this 的另一个常见用法,因此我将其添加到我的答案中。我认为这没有任何问题,因为最终结果是总体上更好的答案,这正是 SO 的目的。我也尽可能地给予信任,就像我在 trinithis 的情况下所做的那样。
          • 您有案例 1 和案例 3 的示例。您能否举一个案例 2 的示例,其中当前类实例用作另一个类的方法的参数?
          • @AStar 在我多年来使用的大多数 Java 代码库中,this 仅在确实需要消歧时才使用,就像我上面的 setter 示例一样。当然,编码风格和“最佳实践”可能会因您询问的对象而有很大差异,但总的来说,我建议选择合理的模式并坚持下去。一致性,即使只是在单个代码库内部,也有助于提高可读性和可维护性。
          【解决方案7】:

          以下是在java中使用'this'关键字的方法:

          1. 使用this关键字引用当前类实例变量
          2. 使用this() 调用当前类构造函数
          3. 使用this关键字返回当前类实例
          4. 使用this关键字作为方法参数

          https://docs.oracle.com/javase/tutorial/java/javaOO/thiskey.html

          【讨论】:

            【解决方案8】:

            this 是对当前对象的引用。它在构造函数中用于区分同名的本地和当前类变量。例如:

            public class circle {
                int x;
                circle(int x){
                    this.x =x;
                    //class variable =local variable 
                }
            } 
            

            this 也可用于从另一个构造函数调用一个构造函数。例如:

            public class circle {
                int x;
            
                circle() { 
                    this(1);
                }
            
                circle(int x) {
                    this.x = x; 
                }
            }
            

            【讨论】:

              【解决方案9】:

              确保使用当前对象的成员。在关注线程安全的情况下,某些应用程序可能会更改错误的对象成员值,因此应该将其应用于成员,以便使用正确的对象成员值。

              如果您的对象不关心线程安全,则没有理由指定使用哪个对象成员的值。

              【讨论】:

              • 事实并非如此。我什至不确定您在考虑什么情况,但举个例子可能有助于理解您想说的话。
              • 是的。我知道你在解释什么涉及线程安全。这个涉及线程安全的问题没有正确答案。如果“this”对于引用正确的对象是必要的,那么一旦它这样做了,当且仅当它被同步时,方法或属性将是线程安全的。如果引用完全不明确,那么多线程是否是一个问题也是不明确的。
              【解决方案10】:

              “this”在从另一个构造函数调用时也很有用:

              public class MyClass {
                  public MyClass(String foo) {
                      this(foo, null);
                  }
                  public MyClass(String foo, String bar) {
                      ...
                  }
              }
              

              【讨论】:

                【解决方案11】:

                当有两个变量一个实例变量和另一个同名的局部变量时,我们使用这个。引用当前执行对象以避免名称之间的冲突。

                【讨论】:

                  【解决方案12】:

                  this 的第二个重要用途(除了像许多答案已经说过的那样用局部变量隐藏)是从嵌套的非静态类访问外部实例时:

                  public class Outer {
                    protected int a;
                  
                    public class Inner {
                      protected int a;
                  
                      public int foo(){
                        return Outer.this.a;
                      }
                  
                      public Outer getOuter(){
                        return Outer.this;
                      }
                    }
                  }
                  

                  【讨论】:

                    【解决方案13】:

                    this 不会影响生成的代码 - 它是编译时运算符,无论有没有它生成的代码都是相同的。当你必须使用它时,取决于上下文。例如,正如您所说,当您有隐藏类变量的局部变量并且您想要引用类变量而不是本地变量时,您必须使用它。

                    编辑:“生成的代码将是相同的”我的意思当然是,当局部范围内的某些变量不隐藏属于类的变量时。因此

                    class POJO {
                       protected int i;
                    
                       public void modify() {
                          i = 9;
                       }
                    
                       public void thisModify() {
                          this.i = 9;
                       }
                    }
                    

                    两种方法的结果代码相同。不同之处在于,如果某些方法声明了同名的局部变量

                      public void m() {
                          int i;
                          i = 9;  // i refers to variable in method's scope
                          this.i = 9; // i refers to class variable
                      }
                    

                    【讨论】:

                      【解决方案14】:

                      Google turned up a page on the Sun site that discusses this a bit.

                      关于变量你是对的; this 确实可以用来区分方法变量和类字段。

                          private int x;
                          public void setX(int x) {
                              this.x=x;
                          }
                      

                      但是,我真的讨厌这种约定。给两个不同的变量赋予字面上相同的名称是错误的秘诀。我更喜欢以下内容:

                          private int x;
                          public void setX(int newX) {
                              x=newX;
                          }
                      

                      结果相同,但不会出现错误,即当您真正打算引用 x 时,您不小心引用了 x

                      至于将其与方法一起使用,您对效果是正确的;无论有没有它,你都会得到相同的结果。你能用吗?当然。你应该使用它吗?由你决定,但鉴于我个人认为这是毫无意义的冗长,不会增加任何清晰度(除非代码中塞满了静态导入语句),我不倾向于自己使用它。

                      【讨论】:

                      • 这不是约定,而是程序语言范围机制。您列出的内容——使用 newX(我更喜欢 pX 作为参数 x)是一种约定。
                      • @Bill K:我不明白你的区别。我可以选择将输入变量命名为 x、newX、pX 或 mangroveThroatWarblerX。如何选择给它一个与它设置的变量相同的名称而不是约定,而在前面加上“new”或“p”或“Gratuitous Monty Python References”是约定?
                      • “Gratuitoud Monty Python 参考”不是惯例,而是法律。
                      • +1:由于这个原因,我们对参数和方法变量使用与类变量不同的命名标准。我们缩写参数/方法变量并使用完整的词来表示类/实例变量。
                      • 通过使用命名约定来解决它是,嗯,约定。通过使用语言功能来解决它​​——我想选择从不使用该语言功能或始终使用它将是一种约定......使用这个。每次访问成员时都会是一个约定。猜猜这没关系,我也讨厌.this。
                      【解决方案15】:

                      您只需要使用this - 大多数人只使用它 - 当存在同名的重叠局部变量时。 (例如 Setter 方法。)

                      当然,使用 this 的另一个很好的理由是它会导致智能感知在 IDE 中弹出:)

                      【讨论】:

                      • 但是你必须在查找后退格。编程很累!
                      【解决方案16】:

                      如果我在某些方法中使用“x”而不是“this.x”会有什么不同吗?

                      通常不会。但有时它会有所不同:

                        class A {
                           private int i;
                           public A(int i) {
                              this.i = i; // this.i can be used to disambiguate the i being referred to
                           }
                        }
                      

                      如果我只使用“method()”,会不会默认应用到当前对象?

                      是的。但如果需要,this.method() 会澄清调用是由该对象进行的。

                      【讨论】:

                        【解决方案17】:

                        唯一需要使用this. 限定符是当前范围内的另一个变量共享相同名称并且您想要引用实例成员(如William 所述)。除此之外,xthis.x 之间的行为没有区别。

                        【讨论】:

                        • 如果你有重复的名字,你的变量之一应该被重命名,因为它几乎肯定命名不正确。或者至少,可以更好地命名。
                        • @Chad:这是 Java setter 方法中的常见做法。但是,在 setter 方法之外,您的语句通常成立。
                        • 您可能希望使用this.x 让您的代码阅读更清晰一些,代码的可维护性/可读性也是您应该考虑的一个因素...
                        • @Chad:我非常赞同。天哪,就因为“这个”。允许你给两个不同的变量同名,你为什么要这样做?
                        • @Blair:阅读您的回答清楚地表明您不喜欢在 setter 方法中使用这种做法,但很多人喜欢(我会将自己包括在该列表中)。如果我有一个接受值的 setter 方法,显然传入的值是“新”值,因此在变量名中添加“新”似乎会给公共 API 添加不必要的冗余。
                        【解决方案18】:

                        除非你有重叠的变量名,否则它真的只是为了在你阅读代码时清晰。

                        【讨论】:

                        • 当您经常看到this 关键字时,它只是不必要的样板代码,使代码更难阅读。
                        • 我刚遇到一个开源项目,它要求所有成员都以“this”为前缀。除此之外,这个项目写得很好,但我很想和他们进行宗教辩论。
                        • @AxeEffect 我知道这真的很老了,但是...this 不会使代码更难阅读 lmao。
                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2010-11-02
                        • 1970-01-01
                        相关资源
                        最近更新 更多