Khi nào tôi nên sử dụng phiên bản này trong một lớp học?


267

Tôi biết rằng thisđề cập đến một đối tượng hiện tại. Nhưng tôi không biết khi nào tôi thực sự cần sử dụng nó. Ví dụ, sẽ có sự khác biệt nào nếu tôi sử dụng xthay vì this.xtrong một số phương pháp? Có thể xsẽ đề cập đến một biến là cục bộ cho phương thức được xem xét? Tôi có nghĩa là biến chỉ được nhìn thấy trong phương pháp này.

Thế còn this.method()? Tôi có thể sử dụng nó? Tôi có nên sử dụng nó. Nếu tôi chỉ sử dụng method(), theo mặc định, nó sẽ không được áp dụng cho đối tượng hiện tại chứ?

Câu trả lời:


347

Các thistừ khóa được sử dụng chủ yếu trong ba tình huống. Đầu tiên và phổ biến nhất là trong các phương thức setter để phân tán các tham chiếu biến. Thứ hai là khi có nhu cầu chuyển thể hiện của lớp hiện tại làm đối số cho một phương thức của đối tượng khác. Thứ ba là một cách để gọi các hàm tạo thay thế từ bên trong một hàm tạo.

Trường hợp 1: Sử dụng thisđể định hướng các tham chiếu biến. Trong các phương thức setter Java, chúng ta thường truyền vào một đối số có cùng tên với biến thành viên riêng mà chúng ta đang cố gắng đặt. Chúng tôi sau đó gán đối số xcho this.x. Điều này cho thấy rõ rằng bạn đang gán giá trị của "name" cho tham số "name".

public class Foo
{
    private String name;

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

Trường hợp 2: Sử dụng thislàm đối số được truyền cho đối tượng khác.

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

Trường hợp 3: Sử dụng thisđể gọi các nhà xây dựng thay thế. Trong các ý kiến, trinithis đã chỉ ra một cách sử dụng phổ biến khác this. Khi bạn có nhiều hàm tạo cho một lớp, bạn có thể sử dụng this(arg0, arg1, ...)để gọi một hàm tạo khác mà bạn chọn, miễn là bạn làm như vậy trong dòng đầu tiên của hàm tạo.

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

        //optional other lines
    }

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

Tôi cũng đã thấy thisđược sử dụng để nhấn mạnh thực tế là một biến thể hiện đang được tham chiếu (không cần phải định hướng), nhưng đó là một trường hợp hiếm gặp theo quan điểm của tôi.


21
+1 Để đề cập rằng bạn cũng có thể vượt qua điều này như một đối số. điều này không chỉ được sử dụng cho định hướng phạm vi.
Alex Jasmin

12
Tất nhiên cũng có this(arg1, arg2, ...)bên trong một nhà xây dựng.
Thomas Eding

12
@Hazior: Tôi có xu hướng viết một câu trả lời ngắn và sau đó thêm vào nó theo thời gian. Đôi khi điều đó trùng lặp với câu trả lời của người khác, đôi khi không. Trong trường hợp chỉnh sửa mới nhất của tôi, trinithis đã chỉ ra một cách sử dụng phổ biến khác thismà tôi đã quên, vì vậy tôi đã thêm nó vào câu trả lời của mình. Tôi không thấy có gì sai với điều này vì kết quả cuối cùng là một câu trả lời tốt hơn về tổng thể, đó chính xác là mục đích của SO. Tôi cũng cố gắng cung cấp tín dụng bất cứ nơi nào có thể, như tôi đã làm trong trường hợp của trinithis.
William Brendel

4
Bạn có ví dụ cho trường hợp 1 và 3. Bạn có thể vui lòng cho một ví dụ về trường hợp 2 trong đó thể hiện của lớp hiện tại được sử dụng làm đối số cho một phương thức của lớp khác không?
dbconfession

4
@AStar Trong hầu hết các cơ sở mã Java mà tôi đã làm việc trong nhiều năm qua, thischỉ được sử dụng nếu sự định hướng là thực sự cần thiết, như trong ví dụ setter của tôi ở trên. Tất nhiên, phong cách mã hóa và "thực tiễn tốt nhất" có thể khác nhau tùy thuộc vào người bạn yêu cầu, nhưng nói chung, tôi khuyên bạn nên chọn các mẫu hợp lý và bám sát chúng. Tính nhất quán, thậm chí chỉ là nội bộ trong một cơ sở mã duy nhất, đi một chặng đường dài hướng tới khả năng đọc và bảo trì.
William Brendel

71

Việc sử dụng quan trọng thứ hai của this(bên cạnh việc ẩn với một biến cục bộ như nhiều câu trả lời đã nói) là khi truy cập một thể hiện bên ngoài từ một lớp không tĩnh được lồng nhau:

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

Bạn chỉ cần sử dụng this- và hầu hết mọi người chỉ sử dụng nó - khi có một biến cục bộ chồng chéo có cùng tên. (Ví dụ, các phương thức Setter.)

Tất nhiên, một lý do tốt khác để sử dụng thislà nó khiến intellisense bật lên trong IDE :)


1
Nhưng sau đó bạn phải backspace nó sau khi bạn tìm nó. Lập trình thật mệt mỏi!
Truyền thuyết Bước sóng

25

Nhu cầu duy nhất để sử dụng this.vòng loại là khi một biến khác trong phạm vi hiện tại có cùng tên và bạn muốn tham chiếu đến thành viên thể hiện (như William mô tả). Ngoài ra, không có sự khác biệt trong hành vi giữa xthis.x.


3
Và nếu bạn có tên trùng lặp, một trong các biến của bạn sẽ được đổi tên vì nó gần như chắc chắn được đặt tên không đúng. Hoặc ít nhất, có thể được đặt tên tốt hơn.
CaffGeek

3
@Chad: Đó là cách làm phổ biến trong các phương thức setter Java. Tuy nhiên, bên ngoài các phương thức setter, các câu lệnh của bạn thường được giữ.
William Brendel

2
Bạn có thể muốn sử dụng this.xđể làm cho mã của mình đọc rõ hơn một chút, khả năng duy trì / khả năng đọc của mã cũng là một yếu tố mà bạn nên xem xét ...
Bryan Rehbein

1
@Chad: Tôi không thể đồng ý nhiệt tình đủ. Chúa ơi, chỉ vì "cái này." cho phép bạn đặt hai biến khác nhau cùng tên, tại sao bạn MUỐN?
BlairHippo

2
@Blair: Đọc câu trả lời của bạn cho thấy rõ rằng bạn không thích thực hành này trong các phương thức setter, nhưng nhiều người làm (tôi bao gồm bản thân mình trong danh sách đó). Nếu tôi có một phương thức setter nhận một giá trị, thì rõ ràng giá trị được truyền vào là giá trị "mới", do đó, việc thêm "mới" vào tên biến dường như thêm sự dư thừa không cần thiết vào API công khai.
Adam Robinson

15

"này" cũng hữu ích khi gọi một hàm tạo từ một hàm khác:

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

11

this là hữu ích trong mô hình xây dựng.

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
Đây là loại câu trả lời tôi muốn khi tôi tìm kiếm và kết thúc ở đây, nhưng bạn không có lời giải thích nào về mã của mình, vì vậy hầu hết những người đang hỏi về "cái này", sẽ không hiểu "trả lại người dùng mới (cái này);" có nghĩa là, như tôi không ...
nckbrz

Mẫu Builder được sử dụng để xác định rõ các tham số khi xây dựng. Thay vì có Người dùng mới (chuỗi, chuỗi) không có cách dễ dàng để biết đó là chuỗi nào, bạn sẽ có Trình tạo mới (). SetFirstName ("Jane"). SetSurname ("Smith"). Build (). Bạn trả lại cái này từ các hàm Builder.set ... () để bạn có thể xâu chuỗi chúng.
ChrisPhoenix

10

Có rất nhiều câu trả lời hay, nhưng có một lý do rất nhỏ khác để đưa ra thiskhắp nơi. Nếu bạn đã thử mở mã nguồn từ trình soạn thảo văn bản thông thường (ví dụ: notepad, v.v.), việc sử dụng thissẽ giúp việc đọc trở nên rõ ràng hơn rất nhiều.

Hãy tưởng tượng điều này:

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

Điều này rất rõ ràng để đọc với bất kỳ IDE hiện đại nào, nhưng đây sẽ là một cơn ác mộng hoàn toàn khi đọc với một trình soạn thảo văn bản thông thường.

Bạn sẽ đấu tranh để tìm ra nơi foocư trú, cho đến khi bạn sử dụng chức năng "tìm" của trình soạn thảo. Sau đó, bạn sẽ hét lên getStringFromSomewhere()với lý do tương tự. Cuối cùng, sau khi bạn quên mất những gì s, điều đó bar = ssẽ cho bạn cú đánh cuối cùng.

So sánh nó với điều này:

public void doSomething() {
    // More codes
    Hello.this.foo = "FOO";
    // More codes
    String s = Hello.this.getStringFromSomewhere();
    // More codes
    this.bar = s;
}
  1. Bạn biết foolà một biến được khai báo trong lớp bên ngoài Hello.
  2. Bạn biết getStringFromSomewhere()là một phương thức được khai báo trong lớp bên ngoài là tốt.
  3. Bạn biết rằng nó barthuộc về Worldlớp và slà một biến cục bộ được khai báo trong phương thức đó.

Tất nhiên, bất cứ khi nào bạn thiết kế một cái gì đó, bạn tạo ra các quy tắc. Vì vậy, trong khi thiết kế API hoặc dự án của bạn, nếu quy tắc của bạn bao gồm "nếu ai đó mở tất cả các mã nguồn này bằng notepad, anh ấy hoặc cô ấy sẽ tự bắn vào đầu mình", thì bạn hoàn toàn không nên làm điều này .


câu trả lời tuyệt vời @Jai
gaurav

Lý do đầu tiên để bắn sẽ là viết các lớp với vài dòng mã 10k, đặc biệt là nếu mã đã được chia thành các lớp khác nhau mà không cần phải lồng nhau :)
LuCio

@LuCio Lol đúng xD
Jai

7

Trừ khi bạn có các tên biến chồng chéo, nó thực sự chỉ rõ ràng khi bạn đọc mã.


1
Khi bạn thấy thistừ khóa liên tục khi không cần thiết, nó chỉ là mã soạn sẵn làm cho mã khó đọc hơn.
AxeEffect

Tôi vừa bắt gặp một dự án nguồn mở đang yêu cầu tất cả các thành viên được bắt đầu bằng 'cái này'. Ngoài ra, dự án được viết rất tốt nhưng tôi rất muốn tham gia vào cuộc tranh luận tôn giáo với họ.
Truyền thuyết Chiều dài

4
@AxeEffect Tôi biết điều này thực sự cũ nhưng ... thisKHÔNG làm cho mã khó đọc lmao hơn.
Xatenev

4

@William Brendel trả lời cung cấp ba trường hợp sử dụng khác nhau theo cách tốt đẹp.

Trường hợp sử dụng 1:

Trang tài liệu java chính thức về điều này cung cấp các trường hợp sử dụng tương tự.

Trong một phương thức cá thể hoặc một hàm tạo, đây là một tham chiếu đến đối tượng hiện tại - đối tượng có phương thức hoặc hàm tạo đang được gọi. Bạn có thể tham chiếu đến bất kỳ thành viên nào của đối tượng hiện tại từ bên trong một phương thức cá thể hoặc hàm tạo bằng cách sử dụng phương thức này.

Nó bao gồm hai ví dụ:

Sử dụng công cụ này với TrườngSử dụng công cụ này với Trình xây dựng

Trường hợp sử dụng 2:

Trường hợp sử dụng khác chưa được trích dẫn trong bài viết này: thiscó thể được sử dụng để đồng bộ hóa đối tượng hiện tại trong một ứng dụng đa luồng để bảo vệ phần quan trọng của dữ liệu & phương thức.

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

Trường hợp sử dụng 3:

Việc thực hiện mẫu Builder tùy thuộc vào việc sử dụng thisđể trả về đối tượng đã sửa đổi.

Tham khảo bài viết này

Giữ trình xây dựng trong lớp riêng biệt (giao diện lưu loát)


2

Google đã bật lên một trang trên trang Sun nói về điều này một chút.

Bạn nói đúng về biến số; thisthực sự có thể được sử dụng để phân biệt biến phương thức với trường lớp.

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

Tuy nhiên, tôi thực sự ghét quy ước đó. Đưa ra hai biến khác nhau theo tên theo nghĩa đen là một công thức cho lỗi. Tôi rất thích một cái gì đó dọc theo dòng:

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

Kết quả tương tự, nhưng không có khả năng xảy ra lỗi khi bạn vô tình đề cập đến xkhi bạn thực sự muốn nói đến xthay thế.

Đối với việc sử dụng nó với một phương pháp, bạn đã đúng về các hiệu ứng; bạn sẽ nhận được kết quả tương tự có hoặc không có nó. Bạn có thể dùng nó không? Chắc chắn rồi. Bạn có nên sử dụng nó? Tùy thuộc vào bạn, nhưng cá nhân tôi nghĩ rằng tính dài dòng vô nghĩa không thêm bất kỳ sự rõ ràng nào (trừ khi mã được nhồi nhét đầy đủ các câu lệnh nhập tĩnh), tôi không có xu hướng sử dụng nó.


4
Đây không phải là một quy ước, đó là một cơ chế phạm vi ngôn ngữ chương trình. Những gì bạn đã liệt kê - sử dụng newX (tôi thích pX cho tham số x) là một quy ước.
Bill K

@Bill K: Tôi không hiểu sự khác biệt mà bạn tạo ra. Tôi có thể chọn đặt tên cho biến đầu vào x, hoặc newX, hoặc pX hoặc mangroveTh họngWarblerX. Làm thế nào là chọn đặt cho nó một cái tên giống hệt với biến mà nó đặt KHÔNG phải là quy ước, trong khi chuẩn bị các quy ước "mới" hoặc "p" hoặc "Tham chiếu Monty Python"?
BlairHippo

3
"Tài liệu tham khảo Python Gratuitoud Monty" không phải là một quy ước, đó là LUẬT.
Adam Robinson

+1: Chúng tôi sử dụng một tiêu chuẩn đặt tên khác cho các biến đối số và biến phương thức so với biến lớp vì lý do này. Chúng tôi viết tắt các đối số / vars phương thức và sử dụng các từ đầy đủ cho các biến lớp / thể hiện.
Lawrence Dol

1
Giải quyết nó bằng cách sử dụng quy ước đặt tên là, hmm, một quy ước. Giải quyết nó bằng cách sử dụng một tính năng ngôn ngữ - Tôi đoán việc chọn không bao giờ sử dụng tính năng ngôn ngữ đó hoặc luôn luôn sử dụng nó sẽ là một quy ước ... Sử dụng điều này. cho mỗi lần bạn truy cập một thành viên sẽ là một quy ước. Đoán nó không quan trọng lắm, tôi cũng ghét. Điều này cũng vậy.
Bill K

2

Sau đây là các cách sử dụng từ khóa 'this' trong java:

  1. Sử dụng thistừ khóa để tham chiếu các biến thể hiện của lớp hiện tại
  2. Sử dụng this()để gọi hàm tạo của lớp hiện tại
  3. Sử dụng thistừ khóa để trả về thể hiện của lớp hiện tại
  4. Sử dụng thistừ khóa làm tham số phương thức

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


1

Khi có hai biến một biến đối tượng và biến cục bộ khác có cùng tên thì chúng ta sử dụng biến này. để chỉ đối tượng thực thi hiện tại để tránh xung đột giữa các tên.


1

thislà một tham chiếu đến đối tượng hiện tại. Nó được sử dụng trong hàm tạo để phân biệt giữa biến cục bộ và biến lớp hiện tại có cùng tên. ví dụ:

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

thiscũng có thể được sử dụng để gọi một hàm tạo từ một hàm tạo khác. ví dụ:

public class circle {
    int x;

    circle() { 
        this(1);
    }

    circle(int x) {
        this.x = x; 
    }
}

0

Sẽ có sự khác biệt nào nếu tôi sử dụng "x" thay vì "this.x" trong một số phương thức?

Thường thì không. Nhưng đôi khi nó làm cho một sự khác biệt:

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

Nếu tôi chỉ sử dụng "phương thức ()", theo mặc định, nó sẽ không được áp dụng cho đối tượng hiện tại chứ?

Đúng. Nhưng nếu cần, hãy this.method()làm rõ rằng cuộc gọi được thực hiện bởi đối tượng này.


0

thiskhông ảnh hưởng đến mã kết quả - đó là toán tử thời gian biên dịch và mã được tạo có hoặc không có nó sẽ giống nhau. Khi bạn phải sử dụng nó, phụ thuộc vào bối cảnh. Ví dụ, bạn phải sử dụng nó, như bạn đã nói, khi bạn có biến cục bộ biến bóng lớp và bạn muốn tham chiếu đến biến lớp chứ không phải biến cục bộ.

chỉnh sửa: bởi "mã kết quả sẽ giống nhau" Tất nhiên, ý tôi là, khi một số biến trong phạm vi cục bộ không ẩn cái thuộc về lớp. Như vậy

class POJO {
   protected int i;

   public void modify() {
      i = 9;
   }

   public void thisModify() {
      this.i = 9;
   }
}

mã kết quả của cả hai phương thức sẽ giống nhau. Sự khác biệt sẽ là nếu một số phương thức khai báo biến cục bộ có cùng tên

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

0

Đối với William Brendel bài viết và 's dbconfessions câu hỏi, liên quan đến trường hợp 2 . Đây là một ví dụ:

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

}

Tôi đã thấy điều này được sử dụng, khi xây dựng mối quan hệ cha-con với các đối tượng. Tuy nhiên, xin lưu ý rằng nó được đơn giản hóa vì lợi ích của sự ngắn gọn.


0

Từ khóa này trong java được sử dụng để chỉ các đối tượng lớp hiện tại.

Có 6 cách sử dụng từ khóa này trong từ khóa java trong java

  1. Truy cập biến cấp độ lớp : chủ yếu được sử dụng nếu biến cấp cục bộ và cấp lớp giống nhau
  2. Truy cập các phương thức lớp : đây là hành vi mặc định và có thể bỏ qua
  3. Để gọi các nhà xây dựng khác cùng lớp
  4. Sử dụng từ khóa 'this' làm giá trị trả về : để trả về thể hiện hiện tại từ phương thức
  5. Truyền từ khóa 'this' làm đối số cho phương thức Passing: để truyền đối tượng lớp hiện tại làm đối số
  6. từ khóa này làm đối số cho hàm tạo : để truyền thể hiện của lớp hiện tại làm đối số

tham chiếu: https://stacktraceguru.com/java/this-keyword-in-java


-8

Để đảm bảo rằng các thành viên của đối tượng hiện tại được sử dụng. Trong trường hợp an toàn luồng là mối quan tâm, một số ứng dụng có thể thay đổi giá trị thành viên của đối tượng sai, vì lý do đó nên áp dụng cho thành viên để sử dụng giá trị thành viên đối tượng chính xác.

Nếu đối tượng của bạn không quan tâm đến an toàn luồng thì không có lý do nào để chỉ định giá trị của thành viên đối tượng nào được sử dụng.


Đây thực sự không phải là trường hợp. Tôi thậm chí không chắc bạn đang nghĩ về trường hợp nào, nhưng một ví dụ có thể hữu ích để hiểu những gì bạn đang cố gắng nói.
David Berger

1
Đúng. Tôi biết những gì bạn đang giải thích liên quan đến an toàn chủ đề. Không có câu trả lời chính xác cho câu hỏi này liên quan đến an toàn chủ đề. Nếu "điều này" là cần thiết để tham chiếu đúng đối tượng, thì một khi nó làm như vậy, phương thức hoặc thuộc tính sẽ là luồng an toàn khi và chỉ khi nó được đồng bộ hóa. Nếu tham chiếu hoàn toàn mơ hồ, nó sẽ mơ hồ cho dù đa luồng có phải là một vấn đề hay không.
David Berger
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.