자바에서 허용되는 메소드 호출에서 'this'를 전달하고 있습니다.


93

메서드 호출에서 현재 개체를 전달하는 것이 좋은 / 나쁜 / 용인 할 수있는 방법입니까? 에서와 같이 :

public class Bar{
    public Bar(){}

    public void foo(Baz baz){
        //  modify some values of baz
    }
}

public class Baz{
    //constructor omitted

    public void method(){
        Bar bar = new Bar();
        bar.foo(this);
    }
}

구체적으로, 라인이 bar.foo(this)허용됩니까?


60
왜 그럴 수 없습니까? 일반적입니다.
— Denys Séguret 2013

3
그래서 ... 그 8 네의 : (. 그리고 그래, 내가 그것을 업데이 트 유지하고있어)이다
— 알렉스 Gittemeier는

2
비 정적 익명 클래스는 슈퍼 클래스의이 참조를 자동으로 전달하므로 허용됩니다. 유일한주의는 순환 참조에주의하는 것입니다.
— Mehul Rathod

5
하지만 한 가지주의 할 점이 있습니다. 생성자에서이를 전달하면 객체가 일관성없는 상태로 노출되므로이를 전달해서는 안됩니다. 사람들은 일반적으로 콜백 (예 : ActionListener)을 익명의 내부 클래스로 생성 한 다음이를 다른 객체에 전달할 때 그렇게합니다.
— Tamas Rev

3
@dystroy는 수용 가능하다는 데 동의하지만 일반적이기 때문에 수용 가능하다는 것을 암시하는 것은 정말 나쁜 논리입니다. 뭔가를하는 것은 그것의 일반적인 많은 문제에 당신을 얻을 수 있기 때문에
— 캐리 켄달

답변:


155

사용하지 않을 이유가 없으며 this현재 인스턴스이며 사용하기에 완벽하게 합법적입니다. 사실 그것을 생략 할 수있는 깨끗한 방법은 종종 없습니다.

그래서 그것을 사용하십시오.

예없이 받아 들일 수 있다고 확신하기 어렵 기 때문에 (이러한 질문에 대한 부정적인 대답은 항상 논쟁하기 쉽습니다), 방금 가장 일반적인 java.lang클래스 중 하나 인 하나를 열었고 String물론이 사용 사례를 찾았습니다.

1084        // Argument is a String
1085        if (cs.equals(this))
1086            return true;

을 찾아 (this큰 "수용"프로젝트에, 당신은 그것을 찾기 위해 실패하지 않습니다.


6
완벽한 대답입니다.
— maxf130

15
-1 양방향 클래스 관계가 단방향 관계보다 더 복잡하다는 사실에 대한 언급이 없기 때문입니다. 소프트웨어를 가능한 한 명확하게하는 것이 중요합니다. 위의 특정 예제 에서 두 클래스 사이에 양방향 참조를 피하고 동작과 데이터를 함께 가져 오기 위해 메서드 foo를 Baz 클래스 로 이동하는 것이 더 합리적 입니다.
— JW.

35
-1 질문에서 의견을 제시 할 수있는 추가 사소한 세부 사항을 찾았 기 때문에 답변에 대해? 정말 ?
— Denys Séguret 2013

13
@dystroy 예, "사용하지 않을 이유가 없습니다"라는 시작 문구에 동의하지 않습니다.
— JW.

4
실제로 실제 코드 (OP의 단순화 된 예와 달리)에서 전달 this은 예를 들어 상속 및 인터페이스로 인해 양방향 링크를 추가하는 것을 의미하지 않습니다.
— Denys Séguret 2013

165

그게 잘못이 아닙니다. 무엇인가 좋은 연습을하지 않는 것은 당신이 아직 완전 초기화되지 않은 개체에 대한 참조를 줄 것이기 때문에, 같은 내부의 생성자를하는 것입니다.

여기에 비슷한 포스트가 있습니다. Java가 생성자 에서 이것을 유출 하고 후자가 왜 나쁜 습관인지에 대한 설명을 제공합니다.


18
+1 : 생성자에서 'this'를 참조 할 때 위험을 지적하는 것이 좋습니다.
— Bathsheba

반드시 나쁜 습관은 아닙니다. 예를 들어 Car생성자는 Wheel인스턴스를 생성 할 수 있습니다 . Car없는 경우 Wheel는 불완전하게 초기화되는 반면, Wheel없는 경우 Car는 불완전하게 초기화됩니다. 이 경우 Car의 생성자 this에서 Wheel의 생성자 에 전달 하는 것이 허용 될 수 있습니다 . 다른 대안은 Car와 Wheel 모두에 개인 생성자를 만들고 Car, Wheel을 구성하고 Car에 Wheel을 설치하는 팩토리 함수를 사용하는 것입니다. 그러나 그것은 Car의 정적 메소드 여야합니까 아니면 Wheel의 정적 메소드 여야합니까?
— Lie Ryan

분명히 CarFactoryWheelInstallerProxy바퀴를 설치하는를 만들어야 합니다.
— Kevin

6
@LieRyan Wheel은에 완전히 종속되어 Car있으며 IMO는 전혀 알 수 없습니다 Car.
— Izkata 2013

3
this생성자 내에서 사용 하는 것에 대한 유일한 나쁜 점은 this아직 완전히 구성되지 않은 개체 참조가 신뢰할 수 없거나 알 수없는 클라이언트 (또는 클라이언트에 대한보기가 있다고 가정하는 클라이언트 코드에 게시되는 메서드 또는 컨텍스트로 전달되는 경우) 입니다. 완전히 구성된 개체). this생성자에서 일반적인 초기화를 수행하는 패키지 전용 메서드로 전달 하는 것은 제 생각에 수용 가능할뿐만 아니라 바람직하다고 생각합니다.
— scottb

42

예 ,하지만 두 가지에주의해야합니다.

  1. 전달 이 개체가 구성되지 않은 경우 아직 (즉 생성자에서)
  2. 살아 참조를 유지되고 방지하는 장수 객체에이 전달 이 쓰레기 수집되는 개체를.

1
Java의 생성자는 실제로 생성자가 아닙니다. Java의 생성자 "initializer"를 호출하는 것이 더 적절할 것입니다. Java 생성자 내에서 객체는 실제로 메모리가 할당되었으며, 객체는 실제로 생성자 내에 이미 존재 / 구성되었습니다.
— Lie Ryan

1
실제로 객체에는 아직 초기화되지 않은 인스턴스 변수가있을 수 있으므로 객체가 아직 완전히 작동하지 않을 수 있습니다. 따라서 생성자에서이를 두 번째 객체에 전달할 수 있습니다.이 객체는 아직 모든 인스턴스 변수를 초기화하지 않은 객체에 메서드를 호출 할 수 있습니다.
— Stefanos T.

그러나 두 번째 객체가 전달 된 객체가 초기화되지 않았 음을 인식하고 불투명 객체로 취급하거나 그러한 상태에서 안전하다고 선언 된 메서드 만 호출하는 한 문제가 발생하지 않습니다 this. 객체가 할당되지 않았다면 불가능했을 것입니다.
— Lie Ryan

13

그것은 완벽하게 정상적이고 완벽하게 수용 가능합니다.


5

이것은 현재 객체를 나타냅니다. 당신이하고있는 일은 체계적으로 정확하지만 동일한 클래스에서 메서드를 호출하는 경우 이것이 필요하지 않습니다.


2
예제 코드에서 Baz.method ()는 Baz의 인스턴스를 매개 변수로 사용하여 Bar.foo ()를 호출하는 인스턴스 메소드입니다. 따라서 OP는 동일한 클래스에서 메서드를 호출하지 않습니다.
— a CVn

@ MichaelKjörling 저는 Juned가 foo () 메서드를 Baz 클래스로 이동 this하면 두 클래스 사이 를 전달할 필요가 없다고 말하고 있다고 생각 합니다. 따라서 추가 복잡성을 추가 할 필요가 없습니다.
— JW.

4

동일한 동작을 달성하기위한 덜 복잡한 대안이있는 경우 메서드 호출에서 현재 개체를 전달하는 것은 좋지 않습니다 .

정의에 따라 양방향 연결은 this한 개체에서 다른 개체로 전달되는 즉시 생성됩니다 .

Martin Fowler의 리팩토링을 인용하려면 :

양방향 연결을 단방향으로 변경 (200)

양방향 연결은 유용하지만 가격이 있습니다. 가격은 양방향 링크를 유지하고 개체가 올바르게 생성 및 제거되도록하는 데 따른 추가 복잡성입니다. 양방향 연결은 많은 프로그래머에게 자연스럽지 않으므로 종종 오류의 원인이됩니다.

...

필요한 경우 양방향 연결을 사용해야하지만 그렇지 않은 경우에는 사용하지 않아야합니다. 양방향 연관이 더 이상 무게를 당기지 않는 것을 보자 마자 불필요한 끝을 삭제하십시오.

따라서 이론적으로 우리는 통과해야 할 때 알람 벨을 듣고 당면한 this문제를 해결하기 위해 다른 방법을 정말 열심히 생각 해야합니다 . 물론 마지막 수단으로 그렇게하는 것이 합리적 일 때가 있습니다.

또한 전체적인 개선을 위해 장기적으로 코드를 리팩토링하는 동안 디자인을 일시적으로 손상시켜 '나쁜 연습'을해야하는 경우가 종종 있습니다. (한 걸음 뒤로, 두 걸음 앞으로).

실제로 나는 내 코드가 향상되었습니다 발견 대규모 전염병 등의 양방향 링크를 피함으로써.


간단한 예와 양방향 링크를 설정해야 할 필요성을 혼동합니다. java.lang 소스 코드의 많은 예제 (예를 들어 내 대답에서 본 코드)에서 명확해야하므로 이것을 매개 변수로 전달한다고해서 양방향 종속성을 추가한다는 의미는 아닙니다. 이 답변은 제 의견에 대한 의견이어야합니다.
— Denys Séguret 2013

@dystroy 비추천 한 이유를 설명하는 댓글을 추가해 주셔서 감사합니다. 항상 알아두면 좋습니다. 정의에 따라 양방향 연결 this이 전달 되는 즉시 생성된다는 것을 명확히하기 위해 내 답변을 수정하겠습니다 .
— JW.

1
"정의에 따라 양방향 연결이 전달되는 즉시 생성됩니다" . 이것은 당신이 이해하지 못하는 부분을 분명히합니다. 내가주는 예를보세요. 의 인수 유형 equals이 Object 이므로 양방향 링크가 없습니다 . 이것은 매우 일반적입니다. 수신 메소드는 인수를보다 일반적인 클래스 또는 인터페이스로 정의합니다. 이러한 패턴은 자바에서 사용되는 이유 중 하나는 이고 불필요한 의존성을 피하기. 더 이상 진행하기 전에 존경할만한 자바 라이브러리에서 인수로 전달 되는 많은 경우를 살펴볼 것을 제안합니다 this.
— Denys Séguret 2013

동의하지 않는 것에 동의합시다. this가능한 한 내 코드를 전달하지 않았기 때문에 내 삶이 훨씬 쉬워 졌습니다. 다른 사람들에게 그렇게하도록 권하고 싶습니다.
— JW.

2
@JW :이 답변에 주어진 추론은 관련이 없습니다. 항상 X의 모든 값에 대해 간단 뭔가가 있다면 X를 할 수있는 좋은 생각
— 거짓말 라이언

4

예. 당신은 그것을 사용할 수 있습니다 this. 프로그래밍에서 통과하는 것은 일반적입니다 . 그러나 그것을 사용하는 것에 대한 장단점이 있습니다.하지만 그렇게하는 것은 위험하지 않습니다.


많은 부작용이 있습니다. 복잡성을 더합니다.
— JW.

많은 부작용이 있다면 자바 소스 코드에서 이와 같은 단일 증거를 찾을 수 없습니다. 소스 코드에서 @destroys 예제를 참조하세요.
— Suresh Atta 2013

2

통과 this가 정확하고 좋은 디자인을 따르는 예를 하나 더 추가하기 위해 방문자 패턴 . 방문자 디자인 패턴에서 메서드 accept(Visitor v)는 일반적으로 호출하는 방식으로 구현됩니다 v.visit(this).


1

수용 가능

Oracle JAVA 문서의 스 니펫 :

인스턴스 메서드 또는 생성자 내에서 이것은 현재 개체 (메서드 또는 생성자가 호출되는 개체)에 대한 참조입니다. 이를 사용하여 인스턴스 메서드 또는 생성자 내에서 현재 개체의 모든 멤버를 참조 할 수 있습니다.

필드와 함께 사용

this 키워드를 사용하는 가장 일반적인 이유는 필드가 메서드 또는 생성자 매개 변수에 의해 음영 처리되기 때문입니다.


2
" 현재 개체의 모든 구성원을 참조 할 수 있습니다. "- " 매개 변수 로 전달 this해도됩니까? "라는 질문에 답하지 않는 것 같습니다 .
— a CVn

2
이것은 this.some_variable지역 변수 대신 클래스 변수를 참조 하는 방법을 말합니다 . this매개 변수 로 전달하는 것과는 관련이 없습니다 .
— Jose Salvatierra 2013

0

Java의 모든 것은 값으로 전달됩니다. 그러나 객체는 절대로 메소드에 전달되지 않습니다!
자바는 객체를 메소드에 전달할 때 먼저 객체 자체의 사본이 아닌 객체에 대한 참조 사본을 만듭니다. 따라서 이것은 Java에서 제대로 사용되는 방법입니다. 그리고 가장 일반적으로 따르는 사용법.


9
이 화제의 모습.
— 데니스 Séguret

4
"자바의 모든 것은 값으로 전달됩니다." -이것은 매우 오해의 소지가있는 초기 의견입니다. 실제로 모든 객체는 참조로 전달되고 모든 기본 유형은 값으로 전달됩니다. this원시 유형에 대한 참조가 전혀 없으므로 "추가 정보"가 혼란을 야기한다고 생각합니다.
— Stewart

1
@Stewart : 그는 전체 개체가 복사된다는 것을 의미하지 않는다는 것을 즉시 분명히합니다.
— LarsH 2013

10
@Stewart 아니오, 객체는 참조로 전달 되지 않고 객체 참조 는 값으로 전달됩니다. 중요한 차이점입니다. 참조로 전달하면 객체를 참조하는 지역 변수가 있고 해당 변수를 다른 메소드에 전달하면 메소드가 내 변수가 참조하는 객체를 변경할 수 있으며 이는 확실히 무언가가 아님을 의미합니다. Java에서 할 수 있습니다. 메서드 는 참조의 자체 복사본을 통해 개체의 상태를 변경할 수 있지만 다른 것을 가리 키도록 참조 복사본을 변경할 수는 없습니다.
— Ian Roberts

2
@Stewart yoda.arachsys.com/csharp/parameters.html 은 둘 다 지원하는 C #의 컨텍스트에서 참조로 전달하는 것과 값으로 참조를 전달하는 것의 차이점을 설명하는 좋은 기사입니다.
— Ian Roberts
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.