我应该在课堂上什么时候使用“this”?

When should I use "this" in a class?

提问人:Roman 提问时间:3/10/2010 最后编辑:Gabriel ŠčerbákRoman 更新时间:4/10/2020 访问量:289313

问:

我知道这是指当前对象。但我不知道什么时候真正需要使用它。例如,如果我使用而不是某些方法,会有什么区别吗?可能是指所考虑方法的局部变量?我的意思是仅在此方法中看到的变量。thisxthis.xx

怎么样?我可以使用它吗?我应该使用它吗?如果我只使用 ,默认情况下它不会应用于当前对象吗?this.method()method()

java oop 这个

评论


答:

463赞 William Brendel 3/10/2010 #1

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

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

public class Foo
{
    private String name;

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

案例二:用作传递给另一个对象的参数。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();
    }
}

案例三:用于调用备用构造函数。在评论中,trinithis 正确地指出了 .当单个类有多个构造函数时,可以使用调用所选的另一个构造函数,前提是在构造函数的第一行中执行此操作。thisthisthis(arg0, arg1, ...)

class Foo
{
    public Foo() {
        this("Some default value for bar");

        //optional other lines
    }

    public Foo(String bar) {
        // Do something with bar
    }
}

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

评论

33赞 Alex Jasmin 3/10/2010
+1 提到你也可以把它作为一个参数传递。这不仅用于消除范围歧义。
12赞 Thomas Eding 3/10/2010
当然,内部也有一个构造函数。this(arg1, arg2, ...)
14赞 William Brendel 3/10/2010
@Hazior:我倾向于写一个简短的答案,然后随着时间的推移添加它。有时这与其他人的答案重叠,有时则不然。在我最新的编辑中,trinithis 指出了我忘记的另一个常见用法,所以我把它添加到我的答案中。我不认为这有什么问题,因为最终结果总体上是一个更好的答案,这正是 SO 的目的。我也尽可能地给予赞扬,就像我在三位一体的情况下所做的那样。this
4赞 dbconfession 9/12/2014
您有案例 1 和 3 的示例。您能否举例说明情况 2,其中当前类实例用作另一个类方法的参数?
5赞 William Brendel 2/26/2016
@AStar 在我多年来使用的大多数 Java 代码库中,只有在真正需要消除歧义时才会使用,就像我上面的 setter 示例一样。当然,编码风格和“最佳实践”可能会因你问的人而异,但总的来说,我建议选择合理的模式并坚持下去。一致性,即使只是在单个代码库内部,也对可读性和可维护性大有帮助。this
8赞 ChickenMilkBomb 3/10/2010 #2

除非你有重叠的变量名称,否则它实际上只是为了在你阅读代码时清楚起见。

评论

2赞 AxeEffect 10/8/2013
当你经常看到关键词时,当它没有必要时,它只是样板代码,使代码更难阅读。this
0赞 LegendLength 10/12/2017
我刚刚遇到一个开源项目,它要求所有成员都以“this”为前缀。除此之外,这个项目写得很好,但我很想和他们进行宗教辩论。
10赞 Xatenev 11/14/2017
@AxeEffect我知道这真的很老了,但是...... 不会使代码更难阅读 lmao。this
32赞 Adam Robinson 3/10/2010 #3

唯一需要使用限定符的是,当前作用域中的另一个变量具有相同的名称,并且您想要引用实例成员(如 William 描述的那样)。除此之外,和 之间的行为没有区别。this.xthis.x

评论

3赞 CaffGeek 3/10/2010
如果你有重复的名字,你的一个变量应该被重命名,因为它几乎肯定是命名不正确的。或者至少,可以命名得更好。
3赞 William Brendel 3/10/2010
@Chad:这是 Java setter 方法中的常见做法。但是,在 setter 方法之外,您的语句通常成立。
2赞 Astra 3/10/2010
您可能还想使用使您的代码阅读得更清晰一点,代码的可维护性/可读性也是您应该考虑的一个因素......this.x
1赞 BlairHippo 3/10/2010
@Chad:我怎么都同意。天哪,仅仅因为“这个”允许你给两个不同的变量起相同的名字,你为什么要这样做?
2赞 Adam Robinson 3/10/2010
@Blair:阅读你的答案可以清楚地看出,你不喜欢 setter 方法中的这种做法,但很多人都喜欢(我会把自己包括在内)。如果我有一个接受值的 setter 方法,显然传入的值是“new”值,因此在变量名称中添加“new”似乎会给公共 API 添加不必要的冗余。
0赞 amit kumar 3/10/2010 #4

如果我在某些方法中使用“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()

51赞 froadie 3/10/2010 #5

你只需要使用--大多数人只在有一个同名的重叠局部变量时才使用它。(例如,Setter 方法。this

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

评论

4赞 LegendLength 10/12/2017
但是,您必须在查找后将其退格。编程很累!
0赞 mip 3/10/2010 #6

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
  }
2赞 BlairHippo 3/10/2010 #7

谷歌在Sun网站上发现了一个页面,对这个问题进行了一些讨论。

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

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

但是,我真的很讨厌那个惯例。给两个不同的变量提供字面上相同的名称是错误的根源。我更喜欢这样的东西:

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

相同的结果,但不会出现错误,即您不小心引用了您真正想要引用的时间。xx

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

评论

4赞 Bill K 3/10/2010
它不是约定,而是一种程序语言范围机制。你列出的 - 使用 newX(我更喜欢参数 x 的 pX)是一种约定。
0赞 BlairHippo 3/10/2010
@Bill K:我不明白你所做的区分。我可以选择将输入变量命名为 x、newX、pX 或 mangroveThroatWarblerX。选择给它一个与它设置的变量相同的名称不是约定,而前面的“new”或“p”或“无偿的Monty Python References”是约定,这怎么可能不是约定?
3赞 Adam Robinson 3/10/2010
“Gratuitoud Monty Python References”不是惯例,而是法律。
0赞 Lawrence Dol 3/10/2010
+1:出于这个原因,我们对参数和方法变量使用的命名标准与类变量的命名标准不同。我们缩写参数/方法变量,并使用完整的单词来表示类/实例变量。
1赞 Bill K 3/10/2010
通过使用命名约定来解决它,嗯,是一种约定。通过使用语言功能来解决它——我想选择从不使用该语言功能或总是使用它将是一种惯例......使用这个。因为每次您访问成员时,都会有一个约定。我想这没什么大不了的,我也讨厌 .this。
81赞 Christopher Oezbek 3/10/2010 #8

第二个重要用途(除了使用局部变量隐藏之外,正如许多答案已经说过的那样)是从嵌套的非静态类访问外部实例时: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;
    }
  }
}
1赞 giri 3/10/2010 #9

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

15赞 Benjamin 3/10/2010 #10

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

public class MyClass {
    public MyClass(String foo) {
        this(foo, null);
    }
    public MyClass(String foo, String bar) {
        ...
    }
}
-10赞 Myster October 3/10/2010 #11

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

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

评论

0赞 David Berger 3/12/2010
事实并非如此。我什至不确定你在想什么情况,但一个例子可能有助于理解你想说什么。
1赞 David Berger 5/10/2012
是的。我知道你解释的内容涉及线程安全。这个问题涉及线程安全,没有正确的答案。如果“this”是引用正确对象所必需的,那么一旦它这样做,当且仅当它是同步的时,它才是线程安全的。如果引用完全不明确,那么多线程是否是一个问题将是不明确的。
13赞 Kieren Dixon 7/28/2011 #12

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();
    }

}

评论

1赞 nckbrz 4/12/2014
这是我搜索并最终到达这里时想要的答案类型,但是您没有对您的代码进行解释,因此大多数询问“this”的人不会理解“return new user(this)”是什么意思,因为我不明白......
0赞 ChrisPhoenix 9/8/2015
Builder 模式用于在构造时明确指定参数。与其让 new User(string, string) 没有简单的方法来分辨哪个字符串是哪个字符串,不如使用 new Builder().setFirstName(“Jane”).setSurname(“Smith”).build()。您从 Builder.set 返回此内容...() 函数,以便您可以链接它们。
1赞 nouman shah 6/28/2015 #13

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; 
    }
}
4赞 Ravindra babu 9/18/2016 #14

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

用例 1:

关于此的官方 Java 文档页面提供了相同的用例。

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

它包括两个例子:

将 this 与 Field 一起使用,并将其与构造函数一起使用

用例 2:

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

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

用例 3:

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

请参阅此帖子

将构建器保留在单独的类中(Fluent interface)

2赞 roottraveller 10/10/2016 #15

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

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

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

0赞 Alija 12/6/2017 #16

关于威廉·布伦德尔(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");
    }
  }

}

我已经看到,在与对象建立父子关系时,它被使用了。但是,请注意,为了简洁起见,它进行了简化。

14赞 Jai 2/22/2018 #17

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

想象一下:

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 阅读都非常清楚,但使用常规文本编辑器阅读这将是一场噩梦。

在使用编辑器的“查找”功能之前,您将很难找到驻留位置。然后你会因为同样的原因而尖叫。最后,在你忘记了是什么之后,这将给你最后一击。foogetStringFromSomewhere()sbar = s

与此进行比较:

public void doSomething() {
    // More codes
    Hello.this.foo = "FOO";
    // More codes
    String s = Hello.this.getStringFromSomewhere();
    // More codes
    this.bar = s;
}
  1. 你知道是一个在外部类中声明的变量。fooHello
  2. 你知道,这也是一个在外部类中声明的方法。getStringFromSomewhere()
  3. 你知道它属于类,并且是该方法中声明的局部变量。barWorlds

当然,每当你设计一些东西时,你都会创建规则。因此,在设计你的 API 或项目时,如果你的规则包括“如果有人用记事本打开所有这些源代码,他或她应该朝自己的头部开枪”,那么你完全可以不这样做

评论

0赞 Gaurav 5/22/2018
很棒的答案 @Jai
1赞 LuCio 10/10/2018
拍摄的第一个原因是用几行 10k 行代码编写类,特别是如果代码已经拆分为不需要嵌套的不同类:)
0赞 Jai 10/11/2018
@LuCio Lol true xD