Java에서 "this"가 null 일 수 있습니까?


109

클래스 메서드에서이 줄을 봤고 첫 번째 반응은이 코드를 작성한 개발자를 조롱하는 것이 었습니다.하지만 저는 먼저 제가 옳은지 확인해야한다고 생각했습니다.

public void dataViewActivated(DataViewEvent e) {
    if (this != null)
        // Do some work
}

그 라인이 거짓으로 평가 될까요?


104
항상 먼저 조롱하고 나중에 질문하십시오. 유황에 휩싸여 누군가를 무너 뜨릴 절호의 기회를 되 찾는 것보다 사과하는 것이 더 쉽습니다.
Joel Etherton

5
"유황의 흐름"이라는 용어에 +1.
Marty Pitt

13
재미있는 게 뭔지 알아? 이것은 컴파일러 버그로 인해 C #에서 발생할 수 있습니다!
Blindy

1
@Blindy는 코드 샘플에 +1을 제공합니다.
Nathan Feger

6
C #에서는 null이 될 수 있습니다. 일부 가장자리의 경우. 나는 같은 충동을 가지고 있었다 : 멍청이를 조롱했지만 나는 진정했다. 여기 보라 : stackoverflow.com/questions/2464097/...
안드레이 Rînea

답변:


88

아니요. 을 사용 this하는 경우 인스턴스에 있으므로 thisnull이 아닙니다.

JLS는 말한다 :

기본 식으로 사용되는 경우 this 키워드는 인스턴스 메서드가 호출 된 개체 (§15.12) 또는 생성중인 개체에 대한 참조 인 값을 나타냅니다.

객체에서 메소드를 호출하면 객체가 존재하거나 이전이있을 것입니다 NullPointerException(또는 정적 메소드이지만 사용할 수 없습니다 this).


자원 :


4
Java에 대해서는 잘 모르지만 C ++에서는 this인스턴스 메서드의 값이 NULL 일 수 있습니다. 그래서 나는 이것이 자바에서 충분한 이유라고 확신하지 못합니다.
kennytm

4
다음과 같은 null 포인터 예외는가 발견 foo.bar()될 때 발생 foo합니다 null. 메서드를 입력하기 전에 발생하지만 실제 이야기는 호출을 시도 할 메서드가 없다는 것입니다.
Claudiu

5
@KennyTM : Java로는 충분합니다. this키워드를 사용하고 컴파일하면 관찰 할 때 null이 아닙니다. 그러나 다른 사람들이 메소드를 호출하려고 할 때 NPE를 방지하지 않는다고 말합니다. 예를 들어, 이는 메소드로서의 제어를 완전히 벗어 났으며 메소드 내의 null 검사는 아무것도 변경하지 않습니다.
Mark Peters

5
@Kenny : 정의되지 않은 동작 없이는 아니지만 구현의 세부 사항을 알고 있으면 사용할 수 있습니다.

4
나는 그것이 완전히 말이 되더라도이 결정적인 대답을 구독하지 않을 것입니다. 변수가 다른 스레드에서 null로 변경된 직후 인스턴스 메서드가 호출 될 때이 == null 인 Android 앱에 대한 충돌 보고서가 있습니다. 실제 호출은 변수가 null의 경우에도 통과하고,이 인스턴스 멤버 :) 읽으려고 할 때 충돌
아드리안 Creţu

63

마치 "내가 살아 있나?"라고 스스로에게 묻는 것과 같습니다. thisnull 일 수 없습니다.


44
나는 내가 살아?! 하나님 이여 나는 더 이상 모른다
Claudiu

당신은 this != null자명 한 것처럼 들리게 만들고 있습니다 . 그렇지 않다 - C ++에서, 예를 들어, this잘 될 수 NULL아닌 가상위한 방법.
Niki

1
@nikie 어떤 의미에서 그것은 자명합니다. C ++에서도 이런 일이 발생하는 모든 프로그램에는 정의되지 않은 동작이 있습니다. GCC의 가상 기능인 ideone.com/W7RmU 에서도 발생할 수 있습니다 .
Johannes Schaub-litb

8
@John : 그렇습니다. 고문의 일부는 당신이 그것을 확인할 수 없다는 것입니다.

@ JohannesSchaub-litb null ref가있는 C ++ 프로그램의 동작이 정의되지 않은 것은 사실이 아닙니다. 이것을 역 참조하지 않는 한 정의됩니다
Rune FS

9

아니 절대 , 키워드 'this'자체는 해당 클래스의 범위 내에서 해당 클래스의 현재 살아있는 인스턴스 (객체)를 나타내며,이를 사용하여 모든 필드와 멤버 (생성자 포함) 및 부모 클래스의 보이는 항목에 액세스 할 수 있습니다.

그리고 더 흥미롭게도 설정해보세요.

this = null;

그것에 대해 생각해? 당신이 앉아있는 가지를 자르는 것과 같지 않을까요? 키워드 'this'는 클래스 범위 내에서 사용할 수 있으므로 this = null이라고 말하자마자 사용할 수 있습니다. 클래스 내 어느 곳에서나 기본적으로 JVM이 해당 작업을 마친 후 안전하게 돌아와야하기 때문에 JVM이 발생하도록 허용 할 수없는 일부 작업 중간에 해당 객체에 할당 된 메모리를 해제하도록 JVM에 요청합니다.

또한 시도 this = null;하면 컴파일러 오류가 발생합니다. 이유는 매우 간단합니다. Java (또는 모든 언어)의 키워드에는 값을 할당 할 수 없습니다. 즉, 키워드는 할당 작업의 왼쪽 값이 될 수 없습니다.

다른 예는 다음과 같이 말할 수 없습니다.

true = new Boolean(true);
true = false;

좋은 설명 친구.
Pankaj Sharma

@PankajSharma 감사 :)
sactiw

을 사용할 수 있는지보고 싶었 기 때문에 이것을 찾았습니다 this = null. 내 인스턴스는 Android에 있었고 뷰를 제거하고 뷰를 처리하는 객체를 null로 설정했습니다. 그런 다음 remove()실제 뷰를 제거 하는 방법을 사용 하고 핸들러 객체가 쓸모 없게 렌더링되기를 원했기 때문에 null을 원했습니다.
Yokich

내가 당신의 주장에 동의하는지 잘 모르겠습니다. (적어도 중간 부분; lvalue 부분은 괜찮습니다 ... 실제로는 예를 들어 true = false를 할당 할 수있는 깨진 언어가 있다고 확신합니다 (그리고 broken이라고 부르지 않는 언어조차도 반성 또는 유사한 속임수)). 어쨌든, 내가 어떤 객체 foo를 가지고 있고 (불법이라는 것을 무시하고) foo.this = null, foo는 여전히 메모리를 가리 키므로 JVM은 그것을 가비지 수집하지 않을 것입니다.
Foon

@Foon 잘 질문은 Java 언어에 대해 정확하게 이야기하고 있으며 this = null 설정이 허용되는 언어를 발견하지 못했습니다. 즉, 그런 언어가 존재한다면 그런 언어의 '이것'이 같은 맥락과 이데올로기를 가질 것이라고 매우 의심합니다.
sactiw

7

-target 1.3또는 이전 버전으로 컴파일하는 경우 외부 thisnull. 아니면 적어도 예전에는 ...


2
반사를 통해 외부 this를 null로 설정할 수 있다고 생각합니다. 참조에서 null 포인터 예외가 발생했을 때 누군가에게 만우절 농담이 될 수 있습니다.Outer.this.member
평판이 좋지 않습니다.

3

아니요. 클래스 인스턴스의 메서드를 호출하려면 인스턴스가 있어야합니다. 인스턴스는에서 참조하는 메서드에 매개 변수로 암시 적으로 전달됩니다 this. 만약이 thisnull다음의 메소드를 호출 할 인스턴스가 없었을 것입니다.


3

언어가 그것을 강요하는 것만으로는 충분하지 않습니다. VM은이를 시행해야합니다. VM이이를 강제하지 않는 한 Java로 작성된 메소드를 호출하기 전에 널 검사를 강제하지 않는 컴파일러를 작성할 수 있습니다. 인스턴스 메소드 호출을위한 opcode에는 스택에이 참조를로드하는 것이 포함됩니다. http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787을 참조하십시오 . 이것을 null ref로 대체하면 실제로 테스트가 거짓이됩니다.


3

정적 클래스 메서드에서는 클래스 this가 아닌 this인스턴스와 연결되어 있으므로 정의 되지 않습니다. this정적 컨텍스트에서 키워드 를 사용하려고 시도하면 컴파일러 오류가 발생할 것이라고 생각합니다 .


2

정상 thisnull실제 Java 코드 1에 있을 수 없으며 예제에서는 정상을 사용합니다 this. 자세한 내용은 다른 답변을 참조하십시오.

A는 자격을 this 해야 결코 null하지만,이 휴식 할 수 있습니다. 다음을 고려하세요:

public class Outer {
   public Outer() {}

   public class Inner {
       public Inner() {}

       public String toString() {
           return "outer is " + Outer.this;  // Qualified this!!
       }
   }
}

의 인스턴스를 만들려면 다음 Inner을 수행해야합니다.

public static void main(String[] args) {
    Outer outer = new Outer();
    Inner inner = outer.new Inner();
    System.out.println(inner);

    outer = null;
    inner = outer.new Inner();  // FAIL ... throws an NPE
}

출력은 다음과 같습니다.

outer is Outer@2a139a55
Exception in thread "main" java.lang.NullPointerException
        at Outer.main(Outer.java:19)

우리의 시도가를 만들 것을 보여 Inner로모그래퍼 null의가 참조 Outer실패했습니다.

사실, "Pure Java"엔벨로프 안에 집착하면 이것을 깨뜨릴 수 없습니다.

그러나 각 Inner인스턴스 에는에 대한 참조를 포함 하는 숨겨진 final합성 필드 (라고 함 "this$0")가 있습니다 Outer. 정말 까다 롭다면 "순수하지 않은"방법 null을 사용하여 필드 에 할당 할 수 있습니다.

  • 당신은 사용할 수 있습니다 Unsafe 은 그것을 .
  • 이를 위해 네이티브 코드 (예 : JNI)를 사용할 수 있습니다.
  • 반사를 사용하여 할 수 있습니다.

어느 쪽이든, 최종 결과는 Outer.this표현식이 2로 평가된다는 것입니다.null 입니다.

즉, 그것은 가능한 자격을 갖춘가 thisnull. 그러나 프로그램이 "Pure Java"규칙을 따르는 경우 불가능 합니다.


1-손으로 바이트 코드를 "작성"하고 실제 Java로 전달하거나 BCEL 등을 사용하여 바이트 코드를 조정하거나 원시 코드로 이동하여 저장된 레지스터를 처리하는 등의 트릭을 할인합니다. IMO는 Java가 아닙니다. 가상적으로 이러한 일이 JVM 버그의 결과로 발생할 수도 있습니다.하지만 모든 버그보고를 기억하지는 않습니다.

2-실제로 JLS는 동작이 무엇인지 말하지 않으며 구현에 따라 달라질 수 있습니다.


1

null참조에서 메소드를 호출하면 NullPointerExceptionJava VM에서이 메소드 가 발생합니다. 자바 VM이 엄격하게 사양을 준수하는지, 그래서 이것은 사양입니다 this수 없을 것입니다 null.


1

메서드가 정적이면 this. 메서드가 가상 this이면 null 일 수 없습니다. 메서드를 호출하려면 런타임에서 this포인터를 사용하여 vtable을 참조해야하기 때문입니다 . 메서드가 가상아니면 예, thisnull 일 수 있습니다.

C # 및 C ++는 비가 상 메서드를 허용하지만 Java에서는 모든 비 정적 메서드가 가상이므로 thisnull이 될 수 없습니다.


0

tl; dr, "this"는 비 정적 메서드에서만 호출 할 수 있으며 우리 모두는 비 정적 메서드가 null이 될 수없는 일종의 객체에서 호출된다는 것을 알고 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.