java: Class.isInstance vs Class.isAssignableFrom

232

Vamos clazzser alguns Classe objser alguns Object.

É

clazz.isAssignableFrom(obj.getClass())

sempre o mesmo que

clazz.isInstance(obj)

?

Se não, quais são as diferenças?

Albert
fonte
26
se obj == null, o segundo retorna false, o primeiro não. ;)
Peter Lawrey
21
@ PeterLawrey, o primeiro lançará um NullPointerExceptionif obj == null.
precisa saber é o seguinte
Encontrei algumas respostas com amostras de hrere: mytechnotes.biz/2012/07/…
Paramesh Korrakuti
4
Para os leitores: você está prestes a entrar em um buraco negro profundo, escuro, do qual nunca escapará. As diferenças são infinitas. Desistir agora, enquanto você ainda pode: stackoverflow.com/q/496928/1599699
Andrew
@ParameshKorrakuti o nome de domínio está mudando para tshikatshikaaa.blogspot.com/2012/07/…
Jérôme Verstrynge

Respostas:

222

clazz.isAssignableFrom(Foo.class)será verdadeiro sempre que a classe representada pelo clazzobjeto for uma superclasse ou superinterface de Foo.

clazz.isInstance(obj)será verdadeiro sempre que o objeto objfor uma instância da classe clazz.

Isso é:

clazz.isAssignableFrom(obj.getClass()) == clazz.isInstance(obj)

é sempre verdade desde que clazze objseja nula.

uckelman
fonte
3
esta falha o caso em que o Foo é o mesmo que clazz - no caso em que ele retorna verdadeira: Pauls resposta superior considerados abaixo corrige este
ruibarbo
3
Concordo que quando clazz é um Foo, então clazz.isAssignableFrom (Foo.class) é verdadeiro. Onde eu disse o contrário?
Uckelman
5
@ Gili Não foi isso que uckelman disse. Por favor, leia novamente a resposta dele.
Puce
2
Byte b = 3; Comparable.class.isAssignableFrom(b.getClass()) == Comparable.class.isInstance(b)); -> também é verdade para interfaces.
Puce
1
Tecnicidade: Se objfor, nullentão clazz.isAssignableFrom(obj.getClass()) == clazz.isInstance(obj)lançará um NullPointerExceptione não retornará true.
Andrew Macheret
196

Ambas as respostas estão no estádio, mas também não é uma resposta completa.

MyClass.class.isInstance(obj)é para verificar uma instância. Retorna true quando o parâmetro obj é não nulo e pode ser convertido para MyClasssem gerar a ClassCastException. Em outras palavras, obj é uma instância de MyClassou suas subclasses.

MyClass.class.isAssignableFrom(Other.class)retornará true se MyClassfor o mesmo que, ou uma superclasse ou superinterface de Other,. Otherpode ser uma classe ou uma interface. Responde true se Otherpode ser convertido em a MyClass.

Um pequeno código para demonstrar:

public class NewMain
{
    public static void main(String[] args)
    {
        NewMain nm = new NewMain();
        nm.doit();
    }

    class A { }

    class B extends A { }

    public void doit()
    {
        A myA = new A();
        B myB = new B();
        A[] aArr = new A[0];
        B[] bArr = new B[0];

        System.out.println("b instanceof a: " + (myB instanceof A)); // true
        System.out.println("b isInstance a: " + A.class.isInstance(myB)); //true
        System.out.println("a isInstance b: " + B.class.isInstance(myA)); //false
        System.out.println("b isAssignableFrom a: " + A.class.isAssignableFrom(B.class)); //true
        System.out.println("a isAssignableFrom b: " + B.class.isAssignableFrom(A.class)); //false
        System.out.println("bArr isInstance A: " + A.class.isInstance(bArr)); //false
        System.out.println("bArr isInstance aArr: " + aArr.getClass().isInstance(bArr)); //true
        System.out.println("bArr isAssignableFrom aArr: " + aArr.getClass().isAssignableFrom(bArr.getClass())); //true
    }
}
Paulo
fonte
10
Por que no seu exemplo "b isAssignableFrom a:" mas o código é A.class.isAssignableFrom(B.class)? I confuso com a saída :)
Roman Truba
4
ummm ... em todos os seus exemplos "instanceOf" retorna true se "isAssignableFrom" retorna true ... Eu não vejo a diferença dessa maneira.
desenvolvedor android
2
Tenha cuidado para que o texto impresso não corresponda ao código e possa ser confuso ... Exemplo: "System.out.println (" b isAssignableFrom a: "+ A.class.isAssignableFrom (B.class));"
Polster
21
@Paul A resposta, como está, não é útil, porque o leitor fica se perguntando "qual é a diferença entre um objeto ser uma instância de uma subclasse de uma classe e o tipo de objeto ser conversível na classe?" Certamente, você pode ver que deixou o leitor com tantas perguntas depois de ler sua resposta quanto ele ao chegar a esta página. Uma resposta melhor explicaria a diferença (ou a falta dela). Se não houver diferença, a resposta deve declarar diretamente: "não há diferença prática".
Aleksandr Dubinsky
2
Mais importante, o leitor fica se perguntando o que diabos usar para seus propósitos. De acordo com os comentários na pergunta, isAssignableFrom()lança a NullPointerExceptionse o objeto for nulo, enquanto isInstance()apenas retorna false. Essa é a verdadeira resposta.
18717 Andrew Andrew
6

Eu acho que o resultado para esses dois sempre deve ser o mesmo. A diferença é que você precisa de uma instância da classe para usar, isInstancemas apenas o Classobjeto a ser usado isAssignableFrom.

ColinD
fonte
Isso não é 100% verdade. Comparable.class.isAssignableFrom(Byte.class) == truemas Byte.class.isInstance(Comparable.class) == false. Em outras palavras, isInstance()não é simétrico para interfaces, apenas para subclasses.
Gili
6
@ Gili: Você entendeu um pouco errado. Byte.class.isInstance(Comparable.class)é falso porque um Classobjeto não é uma instância de Byte. A comparação correta para Comparable.class.isAssignableFrom(Byte.class)é Comparable.class.isInstance((byte) 1), o que é verdade.
ColinD 28/02
1
Discordo. Se você procurar o Javadoc Byte, descobrirá que ele se estende Numbere é uma classe. (byte) 1não é equivalente a Byte. O primeiro é um primitivo. Este último é uma classe.
Gili
2
@ Gil: Autoboxing lança primitivo bytepara Byteporque o tipo de parâmetro isInstanceé Object.
ColinD 28/02
2
OK. Meu argumento original era que as ligações não eram exatamente simétricas entre si, mas, depois de reler sua resposta, você nunca fez essa afirmação.
Gili
6

Por uma questão de brevidade, podemos entender essas duas APIs, como abaixo:

  1. X.class.isAssignableFrom(Y.class)

Se Xe Ysão da mesma classe, ou Xé Ysuperclasse ou super interface, retorne true, caso contrário, false.

  1. X.class.isInstance(y)

Say yé uma instância da classe Y, se Xe Ysão da mesma classe, ou Xé Ysuperclasse ou super interface, retorna true, caso contrário, false.

Ensolarado
fonte