Classes glorificadas na linguagem Java

96

Algumas classes na API Java padrão são tratadas de maneira ligeiramente diferente de outras classes. Estou falando sobre aquelas classes que não poderiam ser implementadas sem suporte especial do compilador e / ou JVM.

As que eu proponho imediatamente são:

  • Object (obviamente) pois ele, entre outras coisas, não tem uma superclasse.
  • String já que o idioma tem suporte especial para o operador +.
  • Thread uma vez que tem este método start () mágico, apesar do fato de que não há nenhuma instrução bytecode que "bifurque" a execução.

Suponho que todas as classes como essas são de uma forma ou de outra mencionadas no JLS. Corrija-me se eu estiver errado.

De qualquer forma, que outras classes existem? Existe alguma lista completa de "classes glorificadas" na linguagem Java?

aioobe
fonte
2
Os genéricos quase cabem, mas não totalmente. Eles são implementados usando um truque do compilador, mas não são isolados em uma classe.
Bill the Lizard
2
Eles são todos tipos de reverência. ;-)
starblue
1
"Thread.start" é mágico? Certamente é apenas algum código nativo chamado para fazer isso?
jcoder
Esse pensamento também me atingiu. Talvez o JNI sozinho seja suficiente para implementar a classe Thread. Suponho que se eu tentasse fazer isso, usaria alguma API de thread no nível do sistema operacional, bifurcaria a execução na implementação do método start (), executaria o método run () no thread bifurcada e retornaria. Mas então meu segmento de sistema operacional continuaria em execução. Isso funcionaria perfeitamente junto com os encadeamentos criados pela JVM? e honrar o modelo de memória JLS e assim por diante?
aioobe
2
De acordo com as especificações, a única maneira de criar um thread é a partir da classe Thread ( java.sun.com/docs/books/jvms/second_edition/html/… ). Claro, ele depende de alguma comunicação de nível ingênuo com a JVM, mas se você fizesse seu próprio JNI, poderia iniciar um encadeamento, mas não faria a JVM entender o que você está fazendo (bloqueios, modelo de memória, etc. ) Thread é privilegiado porque a especificação atribui a ele um privilégio especial - a única maneira de iniciar um thread.
Yishai

Respostas:

35

Existem muitas respostas diferentes, então pensei que seria útil coletar todas (e adicionar algumas):

Aulas

  • Classes de AutoBoxing - o compilador só permite classes específicas
  • Classe - tem seus próprios literais (int.class por exemplo). Eu também adicionaria sua tipagem genérica sem criar novas instâncias.
  • String - com seu operador + sobrecarregado e o suporte de literais
  • Enum - a única classe que pode ser usada em uma instrução switch (em breve, um privilégio a ser concedido a String também). Ele faz outras coisas também (criação automática de método estático, manipulação de serialização, etc.), mas isso poderia teoricamente ser realizado com código - é apenas um monte de boilerplate, e algumas das restrições não podem ser aplicadas em subclasses (por exemplo, regras especiais de subclasse), mas o que você nunca poderia realizar sem o status privilegiado de um enum é incluí-lo em uma instrução switch.
  • Object - a raiz de todos os objetos (e eu adicionaria seus métodos de clone e finalização não são algo que você possa implementar)
  • Referências : WeakReference, SoftReference, PhantomReference
  • Thread - a linguagem não fornece uma instrução específica para iniciar um thread, em vez disso, ela a aplica magicamente ao método start ().
  • Throwable - a raiz de todas as classes que podem trabalhar com throw, throws e catch, bem como a compreensão do compilador de Exception vs. RuntimeException e Error.
  • NullPointerException e outras exceções, como ArrayIndexOutOfBounds, que podem ser lançadas por outras instruções de bytecode além de athrow.

Interfaces

  • Iterable - a única interface que pode ser usada em um loop for aprimorado

As menções honrosas vão para:

  • java.lang.reflect. Array - criar um novo array conforme definido por um objeto Class não seria possível.
  • Anotações Eles são um recurso de linguagem especial que se comporta como uma interface em tempo de execução. Você certamente não poderia definir outra interface de Annotation, assim como não pode definir uma substituição para Object. No entanto, você poderia implementar todas as suas funcionalidades e apenas ter outra maneira de recuperá-los (e um monte de clichês) em vez de reflexão. Na verdade, havia muitas implementações baseadas em XML e em tag javadoc antes que as anotações fossem introduzidas.
  • ClassLoader - certamente tem um relacionamento privilegiado com a JVM, pois não há uma forma de linguagem para carregar uma classe, embora haja uma forma de bytecode, então é como Array nesse aspecto. Ele também tem o privilégio especial de ser chamado de volta pela JVM, embora isso seja um detalhe de implementação.
  • Serializável - você pode implementar a funcionalidade por meio de reflexão, mas ela tem sua própria palavra-chave privilegiada e você gastaria muito tempo se familiarizando com o SecurityManager em alguns cenários.

Nota: Eu deixei de fora da lista coisas que fornecem JNI (como IO) porque você sempre poderia implementar sua própria chamada JNI se quisesse. No entanto, as chamadas nativas que interagem com a JVM de maneira privilegiada são diferentes.

Arrays são discutíveis - eles herdam Object, têm uma hierarquia compreendida (Object [] é um supertipo de String []), mas são um recurso de linguagem, não uma classe definida por si só.

Yishai
fonte
@Donal, é verdade, eu estava pensando em anotações em tempo de execução, mas as anotações de nível de origem eram de fato feitas dessa forma (xdoclet mais notavelmente, ou mesmo no núcleo de java com @deprecated)
Yishai
Eu tenho lutado para abrir caminho através de um emaranhado de código que foi originalmente escrito com processamento xdoclet e depois convertido em anotações. Oh, como eu prefiro anotações a isso (embora, com encantamentos de maven adequados, o efeito líquido seja o mesmo).
Donal Fellows de
@ KK_07k11A0585, Coleções são uma API padrão que pode ser construída por qualquer pessoa de uma maneira diferente (na verdade, existem implementações alternativas que são voltadas para primitivos, bem como um projeto muito famoso do Google que os aprimora). A única coisa especial que eles obtêm é Iterable, que é mencionado na resposta. Eles são o pão com manteiga da programação java, com certeza, mas são apenas classes regulares, sem privilégios especiais.
Yishai,
@Yishai Ao desenvolver qualquer aplicativo, o principal aspecto que assume importância é o GERENCIAMENTO DE DADOS. Todos nós podemos realizar uma tarefa de diferentes maneiras, mas a forma otimizada é aquela que ocupa menos memória e faz menos uso de referências desnecessárias. Ao usar Coleções, podemos classificar, pesquisar e comparar uma grande quantidade de dados, o que fornece algoritmos predefinidos como Pesquisa Binária, Classificação por Mesclagem, etc. Ele também nos fornece Comparador e Interfaces Comparáveis ​​para personalizar nossas técnicas. A classe de coleções pode não ser a melhor classe em java, mas é, sem dúvida, uma classe de qualidades glorificadas.
KK_07k11A0585
1
Sobre o quê SecurityManager? Ou qualquer coisa relacionada à reflexão ou serialização?
Antimônio
19

Class, claro. Ele tem seus próprios literais (uma distinção com a qual ele compartilha String, BTW) e é o ponto de partida de toda aquela magia de reflexão.

Michael Borgwardt
fonte
Ah, bom ponto. Então, qual é um exemplo de literal de classe? Você está se referindo a MyClass.class?
aioobe
4
@aioobe: exatamente. Observe que você também tem int.class, char.class, etc.
Michael Borgwardt
12
  1. Enum. Você não tem permissão para criar uma subclasse, mas o compilador pode.
  2. Muitas coisas em java.util.concurrent podem ser implementadas sem suporte JVM, mas seriam muito menos eficientes.
Darron
fonte
1
Você pode criar uma subclasse anônima de enums (que é a base da implementação do padrão de visitante para valores de enums). Mas sim, você não pode criar uma subclasse completa de enum ;-)
Thierry
11

Todas as classes de Número têm um pouco de magia na forma de Autoboxing .

Bill the Lizard
fonte
Você quer dizer as classes que envolvem primitivas - o que também inclui Boolean e Character; mas exclui BigInteger.
emory
1
@emory: Certo, apenas as classes de wrapper primitivas. Infelizmente, isso exclui BigInteger.
Bill the Lizard
10

Como as classes importantes foram mencionadas, mencionarei algumas interfaces:

A Iterableinterface (desde 1.5) - permite que um objeto participe de um loop foreach:

Iterable<Foo> iterable = ...;
for (Foo foo : iterable) {

}

A Serializableinterface tem um significado muito especial, diferente de uma interface padrão. Você pode definir métodos que serão levados em consideração mesmo que não estejam definidos na interface (como readResolve()). A transientpalavra-chave é o elemento de linguagem que afeta o comportamento dos Serializableimplementadores.

Bozho
fonte
É verdade, eles são interfaces, portanto, não requerem nenhuma implementação "especial" para ver. (Semelhante a Throwable.)
aioobe
Serializable realmente requer implementação especial. É uma interface que você espera ter dois métodos (esqueci os nomes ... eu poderia pesquisar no Google ...), mas eles não são obrigatórios ou definidos no esquema de interface padrão.
corsiKa
@glowcoder: no entanto, uma vez poderia argumentar que toda a especialidade de Serializable não é relevante para a linguagem Java, apenas para a implementação de ObjectOutputStream e ObjectInputStream.
Michael Borgwardt de
5
@Michael Borgwardt tem - a transientpalavra
Bozho
1
Acho que não - Comparablenão participa de nada interno. Você poderia escrever facilmente NewComparablee novo NewArrays.sort(..)com a mesma funcionalidade
Bozho
6
  1. Throwable , RuntimeException, Error AssertionError
  2. Referências WeakReference, SoftReference, PhantomReference
  3. Enum
  4. Anotação
emory
fonte
Boa lista. +1, a anotação é uma interface e não tem implementação.
aioobe
1
As anotações são tratadas de maneira diferente pelo compilador em relação às interfaces normais. Semelhante ao enum, todos eles estendem Annotation, e o compilador faz isso automaticamente. Do JavaDoc de Annotation: A interface comum estendida por todos os tipos de anotação. Observe que uma interface que estende manualmente esta não define um tipo de anotação. Observe também que essa interface não define por si só um tipo de anotação. Portanto, você não pode criar uma anotação usando sintaxe normal, eles precisaram mudar o compilador para adicioná-los.
Andrei Fierbinteanu
6

Array Java como em int[].class

Alexander Pogrebnyak
fonte
Ah, que bom! a [Iclasse;) não é uma classe de API.
aioobe
2

Não tenho certeza sobre isso. Mas não consigo pensar em uma maneira de implementar manualmente os objetos IO.

demotics2002
fonte
Você está certo, eles não podem ser implementados em Java puro. Eles precisam ser implementados por meio de JNI (assim como qualquer outra classe que precisa fazer chamadas de sistema). Além disso, no entanto, eles não precisam de suporte especial do compilador ou jvm.
aioobe
2

Existe alguma magia na Systemclasse.

System.arraycopy é um gancho para o código nativo

public static native void arraycopy(Object array1, int start1, 
  Object array2, int start2, int length);

mas...

/**
 * Private version of the arraycopy method used by the jit
 * for reference arraycopies
 */
private static void arraycopy(Object[] A1, int offset1,
  Object[] A2, int offset2, int length) {
   ...
}
eljenso
fonte
1
Ei, o que você quer dizer com sua segunda parte da resposta?
Pacerier
1

Bem, já que o tratamento especial de assert foi mencionado. Aqui estão mais alguns tipos de exceção que têm tratamento especial pelo jvm:

  • Null Pointer Exception
  • ArithmeticException.
  • StackOverflowException
  • Todos os tipos de OutOfMemoryErrors
  • ...

As exceções não são especiais, mas o jvm as usa em casos especiais, portanto, você não pode implementá-las sem escrever seu próprio jvm. Tenho certeza de que existem mais exceções especiais por aí.

Josefx
fonte
0

A maioria dessas classes não é realmente implementada com a ajuda 'especial' do compilador ou JVM. O objeto registra alguns nativos que vasculham as estruturas internas da JVM, mas você também pode fazer isso para suas próprias classes. (Eu admito que isso está sujeito à semântica, "chama um nativo definido na JVM" pode ser considerado um suporte especial da JVM.)

O que / é / especial é o comportamento das instruções 'novas' e 'lançadas' sobre como inicializam essas estruturas internas.

No entanto, as anotações e os números são bastante assustadores.

milimoose
fonte
4
aioobe refere-se a classes que você não pode implementar sozinho, pois elas possuem suporte especial. Você não pode criar sua própria classe Object como raiz do sistema de tipos sem herdar o formulário java.lang.Object. O objeto tem suporte especial do compilador e do jvm para garantir que seja uma classe raiz. Chamadas nativas não são suficientes para contornar isso.
Josefx