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


267

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

this.method()呢 我可以使用吗?我应该使用它吗?如果仅使用method(),默认情况下是否不会将其应用于当前对象?

Answers:


347

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

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

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调用备用构造。在评论中,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过强调一个事实,即引用了实例变量(无需歧义化),但是在我看来,这是一种罕见的情况。


21
+1值得一提的是,您也可以将此作为参数传递。不仅用于范围消除。
亚历克斯·贾斯敏

12
当然,this(arg1, arg2, ...)内部也有构造函数。
Thomas Eding

12
@Hazior:我倾向于写一个简短的答案,然后随着时间的推移加进去。有时与其他人的答案重叠,有时不重叠。在我的最新编辑中,trinithis指出了this我忘记的另一种常用用法,因此我将其添加到了答案中。我认为这没有什么错,因为最终结果总体上是一个更好的答案,而这正是SO的目的。我也尽一切可能给予赞誉,就像在trinithis案中一样。
威廉·布伦德尔

4
您有案例1和3的示例。能否请给出案例2的示例,其中当前类实例用作另一个类的方法的参数?
dbconfession

4
@AStar在我多年来this使用的大多数Java代码库中,仅在确实需要消除歧义的情况下才使用@AStar ,例如上面的setter示例。当然,编码样式和“最佳做法”可能会因您要求的人而有很大差异,但总的来说,我建议选择合理的样式并坚持使用。一致性,甚至只是在单个代码库内部的一致性,都对可读性和可维护性大有帮助。
威廉·布伦德尔

71

第二个重要用途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;
    }
  }
}

46

this当存在具有相同名称的重叠局部变量时,您只需要使用-并且大多数人只使用它。(例如,设置方法。)

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


1
但是随后在查找后必须退格。编程很累!
LegendLength

25

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


3
而且,如果您有重复的名称,则应将您的变量之一重命名,因为几乎可以肯定它被错误地命名。或者至少可以命名得更好。
CaffGeek

3
@Chad:这是Java setter方法中的常见做法。但是,在setter方法之外,您的语句通常适用。
威廉·布伦德尔

2
您可能还想使用它this.x来使代码更清晰地阅读,代码的可维护性/可读性也是您应考虑的一个因素...
Bryan Rehbein 2010年

1
@乍得:我不能足够热情地表示同意。好主啊,只是因为“这个”。允许您给两个不同的变量使用相同的名称,为什么要这么做?
BlairHippo 2010年

2
@Blair:阅读您的答案可以很清楚地表明,您不喜欢使用setter方法中的这种做法,但是很多人都喜欢(我会在列表中包括自己)。如果我有一个使用值的setter方法,则显然传入的值将是“新”值,因此在变量名称中添加“新”似乎为公共API增加了不必要的冗余。
亚当·罗宾逊

15

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

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

11

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 2014年

Builder模式用于在构造时明确指定参数。有了新的Builder()。setFirstName(“ Jane”)。setSurname(“ Smith”)。build(),而不是没有新的User(string,string)并没有简单的方法来判断哪个字符串是哪个字符串。您可以从Builder.set ...()函数返回它,以便可以链接它们。
ChrisPhoenix

10

有很多好的答案,但是还有另一个非常次要的理由可以放在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或项目,如果你的规则包括:“如果有人打开一个记事本这些源代码,他或她应该拍他/她的头,”那么你是完全罚款不去做这个


好答案@Jai
gaurav

拍摄的第一个理由是编写包含几万行代码的类,尤其是如果代码已经
拆分

@LuCio Lol true xD
Jai

7

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


1
当您this在不需要时不断看到关键字时,它只是样板代码,使代码难以阅读。
AxeEffect 2013年

我刚遇到一个开源项目,该项目要求所有成员都以“ this”为前缀。除此之外,该项目写得很好,但我很想与他们进行宗教辩论。
LegendLength

4
@AxeEffect我知道这确实很旧,但是... this不会使代码更难读lmao。
Xatenev

4

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

用例1:

在官方Java文档页面提供同样的使用情况。

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

它涵盖了两个示例:

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

用例2:

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

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

用例3:

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

请参阅这篇文章

将构建器放在单独的类中(流利的界面)


2

Google在Sun网站上打开了一个页面,对此进行了一些讨论。

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

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

但是,我真的很讨厌那个约定。给两个不同的变量从字面上相同的名称是错误的秘诀。我更喜欢以下方面的东西:

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

结果相同,但是x当您确实要引用时,您不会偶然地引用错误x

至于将其与一种方法配合使用,您对效果的看法是正确的。使用或不使用它,您都会得到相同的结果。可以使用吗?当然。你应该使用它吗?由您决定,但是鉴于我个人认为毫无意义的冗长性不会增加任何清晰度(除非代码充满了静态导入语句),所以我不打算自己使用它。


4
这不是约定,它是一种程序语言作用域机制。您列出的内容-使用newX(我更喜欢使用pX作为参数x)是一种约定。
比尔K

@比尔·K:我不明白你在区分什么。我可以选择命名输入变量x或newX或pX或mangroveThroatWarblerX。在选择“ new”或“ p”或“ Gantuitous Monty Python References”为ARE约定的同时,如何选择为其赋予与所设置的变量相同的名称而不是约定?
BlairHippo

3
“ Gratuitoud Monty Python参考”不是约定,而是法律。
亚当·罗宾逊

+1:为此,我们对参数和方法变量使用的命名标准与对类变量使用的命名标准不同。我们缩写参数/方法变量,并对类/实例变量使用完整的单词。
劳伦斯·多尔

1
通过使用命名约定来解决它是一个约定。通过使用语言功能来解决它​​-我猜选择不使用该语言功能或始终使用它是一种惯例...使用此功能。对于您每次访问成员,都是一种惯例。猜猜没什么大不了,我也讨厌。
比尔K 2010年


1

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


1

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

0

如果在某些方法中使用“ 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()说明此对象进行了调用。


0

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
  }

0

关于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");
    }
  }

}

在与对象建立父子关系时,我已经看到了这种用法。但是,请注意,为简洁起见,将其简化。


0

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

Java中有“ this”关键字的6种用法

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

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


-8

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

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


事实并非如此。我什至不确定您在想什么情况,但是举个例子可能有助于您理解您要说的话。
David Berger 2010年

1
是。我知道您在解释什么涉及线程安全性。对于这个涉及线程安全的问题,没有正确的答案。如果必须使用“ this”来引用正确的对象,则一旦这样做,该方法或属性将在且仅当已同步时才是线程安全的。如果引用完全是模棱两可的,那么多线程是否是一个问题将是模棱两可的。
David Berger
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.