“This” pode ser nulo em Java?

109

Vi esta linha em um método de classe e minha primeira reação foi ridicularizar o desenvolvedor que a escreveu. Mas então, achei que deveria ter certeza de que estava certo primeiro.

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

Essa linha será avaliada como falsa?

Bryce Fischer
fonte
104
Sempre ridicularize primeiro e questione depois. É mais fácil se desculpar do que recuperar uma oportunidade de ouro de derrubar alguém em uma enxurrada de enxofre.
Joel Etherton
5
+1 para o termo "enxofre".
Marty Pitt
13
Você sabe o que é engraçado? Isso pode acontecer no C # devido a um bug do compilador!
Blindy
1
@Blindy dará +1 para amostra de código.
Nathan Feger
6
bem em C # pode ser nulo. Em alguns casos extremos. Tive o mesmo impulso: ridicularizar o otário, mas depois me acalmei. Dê uma olhada aqui: stackoverflow.com/questions/2464097/…
Andrei Rînea

Respostas:

88

Não, não pode. Se você estiver usando this, então você está na instância, então thisnão é nulo.

O JLS diz:

Quando usada como expressão primária, a palavra-chave this denota um valor que é uma referência ao objeto para o qual o método de instância foi invocado (§15.12) ou ao objeto que está sendo construído.

Se você invocou um método de um objeto, então o objeto existe ou você teria um NullPointerExceptionantes (ou é um método estático, mas você não pode usar thisnele).


Recursos :

Colin Hebert
fonte
4
Não sei muito sobre Java, mas em C ++ o thisde um método de instância pode ser NULL. Portanto, não estou muito convencido de que essa seja uma razão suficiente em Java.
kennytm
4
a exceção de ponteiro nulo em algo como foo.bar()seria lançada quando foodescobrisse que era null. isso acontece antes de entrar no método, mas a história real é que não há método para tentar chamar.
Claudiu
5
@KennyTM: é suficiente em Java. Se você está usando a thispalavra-chave e ela compila, ela não é nula quando você a observa. Mas, como outros dizem, isso não impede um NPE ao tentar invocar o método, por exemplo, Mas isso está completamente fora de seu controle como um método e uma verificação de nulo dentro do método não vai mudar nada.
Mark Peters
5
@Kenny: Não sem um comportamento indefinido , embora se você souber os detalhes de sua implementação, poderá usá-lo.
4
Eu não subscreveria esta resposta definitiva, mesmo que faça todo o sentido. Eu tenho relatórios de falha para um aplicativo Android onde this == null quando um método de instância é chamado logo depois que a variável está sendo null-ified de outro thread. A chamada real ocorre mesmo se a variável for nula e trava ao tentar ler um membro da instância :)
Adrian Crețu
63

É como se perguntar "Estou vivo?" thisnunca pode ser nulo

fanfarrão
fonte
44
estou vivo ?! Deus, eu não sei mais
Claudiu
Você está fazendo parecer que this != nullera evidente. Não é - em C ++, por exemplo, thispode muito bem ser NULL, para um método não virtual.
Niki
1
@nikie Em certo sentido, é evidente. Mesmo em C ++, qualquer programa em que isso aconteça tem um comportamento indefinido. Isso também pode acontecer para funções virtuais no GCC: ideone.com/W7RmU .
Johannes Schaub - litb
8
@John: Você é. Parte da tortura é que você não pode confirmar.
@ JohannesSchaub-litb Não é verdade que o comportamento de um programa c ++ com uma referência nula para isso seja indefinido. É definido desde que você não cancele a referência
Rune FS
9

Não , nunca , a própria palavra-chave 'this' representa a instância atual viva (objeto) daquela classe dentro do escopo daquela classe, com a qual você pode acessar todos os seus campos e membros (incluindo construtores) e os visíveis de sua classe pai.

E, o mais interessante, tente configurá-lo:

this = null;

Pense nisso? Como pode ser possível, não seria como cortar o galho em que você está sentado. Como a palavra-chave 'this' está disponível no escopo da classe, assim que você disser this = null; em qualquer lugar da classe, você basicamente está pedindo à JVM para liberar a memória atribuída a esse objeto no meio de alguma operação que a JVM simplesmente não pode permitir que aconteça, pois precisa retornar com segurança após terminar essa operação.

Além disso, a tentativa this = null;resultará em erro do compilador. A razão é muito simples, uma palavra-chave em Java (ou qualquer linguagem) nunca pode receber um valor, ou seja, uma palavra-chave nunca pode ser o valor esquerdo de uma operação de atribuição.

Outros exemplos, você não pode dizer:

true = new Boolean(true);
true = false;
sactiw
fonte
Boa explicação amigo.
Pankaj Sharma de
@PankajSharma Obrigado :)
sactiw
Eu encontrei isso porque queria ver se eu poderia usar this = null. Minha instância foi no android, onde eu queria remover uma visualização e definir o objeto que manipulava a visualização como nulo. Então eu queria usar um método remove()que removeria a visão real e então o objeto-manipulador se tornaria inútil, então eu queria anulá-lo.
Yokich
Não tenho certeza se concordo com suas afirmações. (pelo menos a parte do meio; a parte do valor está bem ... embora eu tenha quase certeza de que existem linguagens quebradas que permitem que você atribua, por exemplo, verdadeiro = falso (e mesmo as linguagens que eu não chamaria de quebradas podem permitir isso com Reflexão ou truques semelhantes)). De qualquer forma, se eu tivesse algum objeto foo e fizesse (ignorando que é ilegal) foo.this = null, foo ainda apontaria para a memória e a JVM não iria coletá-lo como lixo.
Foon
@Foon bem a questão fala precisamente sobre a linguagem Java, além disso, não encontrei nenhuma linguagem em que definir this = null seja permitido. Ou seja, se essas línguas existem, eu duvido muito que "isso" em tais línguas tenha o mesmo contexto e ideologia.
sactiw
7

Se você compilar com -target 1.3ou anterior, então um externo this pode ser null. Ou pelo menos costumava ...

Tom Hawtin - tackline
fonte
2
Acho que por meio da reflexão podemos definir o this externo como null. poderia ser uma piada de Outer.this.member
1º de
3

Não. Para chamar um método de uma instância de uma classe, a instância deve existir. A instância é passada implicitamente como um parâmetro para o método, referenciado por this. Se thisfosse null, não teria havido instância para chamar um método.

Claudiu
fonte
3

Não é suficiente que a linguagem o imponha. A VM precisa aplicá-lo. A menos que a VM aplique isso, você pode escrever um compilador que não aplique a verificação de nulo antes de chamar o método escrito em Java. Os opcodes para uma chamada de método de instância incluem o carregamento deste ref na pilha, consulte: http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787 . Substituir isso por um ref nulo realmente resultaria no teste sendo falso

Rune FS
fonte
3

Em métodos de classe estática, thisnão é definido, pois thisestá associado a instâncias e não a classes. Acredito que seria um erro do compilador tentar usar a thispalavra-chave em contexto estático.

burkestar
fonte
2

Um normal thisnunca pode estar nullno código Java 1 real e seu exemplo usa um normal this. Veja outras respostas para mais detalhes.

Um qualificado nunca this deve ser null, mas é possível quebrar isso. Considere o seguinte:

public class Outer {
   public Outer() {}

   public class Inner {
       public Inner() {}

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

Quando queremos criar uma instância de Inner, precisamos fazer isso:

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
}

O resultado é:

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

mostrando que nossa tentativa de criar um Innercom uma nullreferência a Outerele falhou.

Na verdade, se você ficar dentro do envelope "Pure Java", não poderá quebrar isso.

No entanto, cada Innerinstância possui um finalcampo sintético oculto (chamado "this$0") que contém a referência ao Outer. Se você for realmente complicado, é possível usar meios "não puros" para atribuir nullao campo.

  • Você poderia usar Unsafepara fazer isso.
  • Você pode usar código nativo (por exemplo, JNI) para fazer isso.
  • Você pode fazer isso usando reflexão.

De qualquer maneira, o resultado final é que a Outer.thisexpressão será avaliada como null2 .

Em suma, é possível para um qualificado thisser null. Mas é impossível se o seu programa seguir as regras do "Pure Java".


1 - Eu desconsidero truques como "escrever" os bytecodes manualmente e passá-los como Java real, ajustar os bytecodes usando BCEL ou similar, ou pular para o código nativo e mexer nos registros salvos. IMO, isso NÃO é Java. Hipoteticamente, essas coisas também podem acontecer como resultado de um bug da JVM ... mas não me lembro de ter visto todos os relatórios de bug.

2 - Na verdade, o JLS não informa qual será o comportamento, podendo ser dependente de implementação ... entre outras coisas.

Stephen C
fonte
1

Quando você invoca um método na nullreferência, o NullPointerExceptionserá lançado do Java VM. Isso ocorre por especificação, portanto, se o seu Java VM estiver estritamente de acordo com a especificação, thisnunca o será null.

tia
fonte
1

Se o método for estático, não haverá nenhum this. Se o método for virtual, então thisnão pode ser nulo, porque para chamar o método, o tempo de execução precisará referenciar a vtable usando o thisponteiro. Se o método não for virtual , sim, é possível que thisseja nulo.

C # e C ++ permitem métodos não virtuais, mas em Java todos os métodos não estáticos são virtuais, portanto thisnunca serão nulos.

John Henckel
fonte
0

tl; dr, "this" só pode ser chamado de um método não estático e todos nós sabemos que um método não estático é chamado de algum tipo de objeto que não pode ser nulo.

Adão
fonte