자바에서 허용되는 메소드 호출에서 '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.