field programação - Por que Java tem campos transitórios?





logica de (11)


Antes de compreender a palavra-chave transient , é preciso entender o conceito de serialização. Se o leitor souber sobre serialização, pule o primeiro ponto.

O que é serialização?

Serialização é o processo de tornar o estado do objeto persistente. Isso significa que o estado do objeto é convertido em um fluxo de bytes e armazenado em um arquivo. Da mesma forma, podemos usar a desserialização para recuperar o estado do objeto dos bytes. Esse é um dos conceitos importantes na programação Java, porque a serialização é usada principalmente na programação de rede. Os objetos que precisam ser transmitidos pela rede precisam ser convertidos em bytes. Para esse propósito, cada classe ou interface deve implementar a interface Serializable . É uma interface de marcador sem nenhum método.

Agora, qual é a palavra-chave transient e sua finalidade?

Por padrão, todas as variáveis ​​do objeto são convertidas em um estado persistente. Em alguns casos, você pode querer evitar a persistência de algumas variáveis, porque você não tem a necessidade de persistir essas variáveis. Então você pode declarar essas variáveis ​​como transient . Se a variável for declarada como transient , ela não será persistida. Esse é o objetivo principal da palavra-chave transient .

Eu quero explicar os dois pontos acima com o seguinte exemplo:

package javabeat.samples;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class NameStore implements Serializable{
    private String firstName;
    private transient String middleName;
    private String lastName;

    public NameStore (String fName, String mName, String lName){
        this.firstName = fName;
        this.middleName = mName;
        this.lastName = lName;
    }

    public String toString(){
        StringBuffer sb = new StringBuffer(40);
        sb.append("First Name : ");
        sb.append(this.firstName);
        sb.append("Middle Name : ");
        sb.append(this.middleName);
        sb.append("Last Name : ");
        sb.append(this.lastName);
        return sb.toString();
    }
}

public class TransientExample{
    public static void main(String args[]) throws Exception {
        NameStore nameStore = new NameStore("Steve", "Middle","Jobs");
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("nameStore"));
        // writing to object
        o.writeObject(nameStore);
        o.close();

        // reading from object
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("nameStore"));
        NameStore nameStore1 = (NameStore)in.readObject();
        System.out.println(nameStore1);
    }
}

E a saída será a seguinte:

First Name : Steve
Middle Name : null
Last Name : Jobs

O nome do meio é declarado como transient , portanto, ele não será armazenado no armazenamento persistente.

Source

Por que Java tem campos transitórios ?




Uma variável transient é uma variável que pode não ser serializada.

Um exemplo de quando isso pode ser útil que vem à mente é, variáveis ​​que fazem sentido apenas no contexto de uma instância de objeto específica e que se tornam inválidas depois de serializar e desserializar o objeto. Nesse caso, é útil que essas variáveis ​​se tornem null para que você possa reinicializá-las com dados úteis, quando necessário.




A palavra-chave transient em Java é usada para indicar que um campo não deve fazer parte do processo de serialização (que significa salvado, como em um arquivo).

Da especificação da linguagem Java, Java SE 7 Edition , Seção 8.3.1.3. Campos transient :

Variáveis ​​podem ser marcadas como transient para indicar que elas não fazem parte do estado persistente de um objeto.

Por exemplo, você pode ter campos que são derivados de outros campos e devem ser feitos apenas de forma programática, em vez de persistir o estado por meio de serialização.

Aqui está uma classe GalleryImage que contém uma imagem e uma miniatura derivada da imagem:

class GalleryImage implements Serializable
{
    private Image image;
    private transient Image thumbnailImage;

    private void generateThumbnail()
    {
        // Generate thumbnail.
    }

    private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException
    {
        inputStream.defaultReadObject();
        generateThumbnail();
    }    
}

Neste exemplo, o thumbnailImage é uma imagem em miniatura que é gerada chamando o método generateThumbnail .

O campo thumbnailImage é marcado como transient , portanto, somente a image original é serializada em vez de persistir tanto a imagem original quanto a imagem em miniatura. Isso significa que menos armazenamento seria necessário para salvar o objeto serializado. (Claro, isso pode ou não ser desejável dependendo dos requisitos do sistema - isso é apenas um exemplo).

No momento da desserialização, o método readObject é chamado para executar quaisquer operações necessárias para restaurar o estado do objeto de volta ao estado no qual a serialização ocorreu. Aqui, a miniatura precisa ser gerada, então o método readObject é substituído para que a miniatura seja gerada chamando o método generateThumbnail .

Para obter informações adicionais, o artigo Descobrir os segredos da API de serialização Java (que estava originalmente disponível na Sun Developer Network) possui uma seção que discute o uso e apresenta um cenário em que a palavra-chave transient é usada para evitar a serialização de determinados campos.




Sistemas de serialização diferentes do java nativo também podem usar este modificador. O Hibernate, por exemplo, não persistirá nos campos marcados com @Transient ou com o modificador transitório . Terracota também respeita este modificador.

Eu acredito que o significado figurativo do modificador é "este campo é apenas para uso em memória. Não persista ou mova-o para fora desta VM em particular de qualquer forma. Não é portátil". ou seja, você não pode confiar em seu valor em outro espaço de memória da VM. Muito parecido com volatile significa que você não pode confiar em certas semânticas de memória e thread.




Antes de responder a esta questão, devo explicar-lhe a SERIALIZAÇÃO , porque se você entender o que significa serialização no computador da ciência, você pode entender facilmente essa palavra-chave.

Serialização Quando um objeto é transferido através da rede / salvo em mídia física (arquivo, ...), o objeto deve ser "serializado". Serialização converte a série de objetos de status de byte. Esses bytes são enviados na rede / salvos e o objeto é recriado a partir desses bytes.
Exemplo

public class Foo implements Serializable 
{
 private String attr1;
 private String attr2;
 ...
}

Agora, se você quer fazer não transferir / salvar campo deste objeto SO , você pode usar a palavra-chave transient

private transient attr2;

Example




Porque nem todas as variáveis ​​são de natureza serializável




Para permitir que você defina variáveis ​​que não deseja serializar.

Em um objeto, você pode ter informações que não deseja serializar / persistir (talvez uma referência a um objeto pai de fábrica), ou talvez não faça sentido serializar. Marcá-las como 'transitórias' significa que o mecanismo de serialização ignorará esses campos.




de acordo com o significado transitório do google == duração apenas por um curto período de tempo; impermanente.

Agora, se quiser fazer algo transitório em java use palavras-chave temporárias.

Q: onde usar transiente?

R: Geralmente, em java, podemos salvar dados em arquivos, adquirindo-os em variáveis ​​e gravando essas variáveis ​​em arquivos. Esse processo é conhecido como Serialização. Agora, se quisermos evitar que os dados variáveis ​​sejam gravados no arquivo, faríamos essa variável como transitória.

transitório int resultado = 10;

Nota: as variáveis ​​transitórias não podem ser locais.




É necessário quando você não deseja compartilhar alguns dados confidenciais que acompanham a serialização.




Simplificando, a palavra-chave java transiente protege os campos da serialização serializada como partes do contador de campos não transientes.

Neste trecho de código, nossa classe abstrata BaseJob implementa a interface Serializable, nós nos estendemos do BaseJob, mas não precisamos serializar as fontes de dados locais e remotas; serialize apenas os campos organizationName e isSynced.

public abstract class BaseJob implements Serializable{
   public void ShouldRetryRun(){}
}

public class SyncOrganizationJob extends BaseJob {

   public String organizationName;
   public Boolean isSynced

   @Inject transient RemoteDataSource remoteDataSource;
   @Inject transient LocalDaoSource localDataSource;

   public SyncOrganizationJob(String organizationName) {
     super(new 
         Params(BACKGROUND).groupBy(GROUP).requireNetwork().persist());

      this.organizationName = organizationName;
      this.isSynced=isSynced;

   }
}



Abaixo, haverá um caso não óbvio em que o Java vaza, além do caso padrão de ouvintes esquecidos, referências estáticas, chaves modificáveis ​​ou falsas em hashmaps ou apenas encadeamentos presos sem qualquer chance de encerrar seu ciclo de vida.

  • File.deleteOnExit() - sempre vaza a string, se a string é uma substring, o vazamento é ainda pior (o char subjacente [] também é vazado) - na substring Java 7 também copia o char[] , então o último não se aplica ; @ Daniel, não há necessidade de votos, no entanto.

Vou me concentrar em tópicos para mostrar o perigo de threads não gerenciados, principalmente, não quero nem tocar em swing.

  • Runtime.addShutdownHook e não remove ... e, em seguida, mesmo com removeShutdownHook devido a um bug na classe ThreadGroup sobre threads não iniciados, pode não ser coletado, efetivamente vazar o ThreadGroup. O JGroup tem o vazamento no GossipRouter.

  • Criando, mas não iniciando, um Thread entra na mesma categoria acima.

  • A criação de um encadeamento herda o ContextClassLoader e o AccessControlContext , além do ThreadGroup e de qualquer InheritedThreadLocal , todas essas referências são possíveis vazamentos, juntamente com as classes inteiras carregadas pelo carregador de classes e todas as referências estáticas e ja-ja. O efeito é especialmente visível em toda a estrutura do jucExecutor que possui uma interface super simples de ThreadFactory , mas a maioria dos desenvolvedores não tem nenhum indício do perigo espreitando. Além disso, muitas bibliotecas iniciam threads sob solicitação (muitas bibliotecas populares do setor).

  • Caches ThreadLocal ; esses são maus em muitos casos. Tenho certeza que todos já viram um monte de caches simples baseados em ThreadLocal, bem, a má notícia: se o thread continuar indo mais do que o esperado na vida do contexto ClassLoader, é um pequeno vazamento. Não use caches ThreadLocal, a menos que seja realmente necessário.

  • Chamando ThreadGroup.destroy() quando o ThreadGroup não tem threads em si, mas ainda mantém Thread Threads filho. Um vazamento incorreto que impedirá que o ThreadGroup seja removido de seu pai, mas todos os filhos se tornarão impossíveis de enumerar.

  • Usando o WeakHashMap e o valor (in) faz referência direta à chave. Este é um difícil encontrar sem um despejo de pilha. Isso se aplica a todos os Weak/SoftReference estendidos que podem manter uma referência rígida ao objeto protegido.

  • Usando java.net.URL com o protocolo HTTP (S) e carregando o recurso de (!). Este é especial, o KeepAliveCache cria um novo thread no ThreadGroup do sistema que vaza o classloader de contexto do thread atual. O encadeamento é criado na primeira solicitação quando não existe um encadeamento ativo, portanto você pode ter sorte ou simplesmente vazar. O vazamento já foi corrigido no Java 7 e o código que cria o encadeamento remove corretamente o carregador de classes de contexto. Existem poucos mais casos ( como ImageFetcher , também corrigido ) de criar encadeamentos semelhantes.

  • Usando InflaterInputStream passando new java.util.zip.Inflater() no construtor ( PNGImageDecoder por exemplo) e não chamando end() do inflator. Bem, se você passar no construtor com apenas new , não tem chance ... E sim, chamar close() no fluxo não fecha o inflador se ele for passado manualmente como parâmetro construtor. Isso não é um vazamento verdadeiro, já que seria liberado pelo finalizador ... quando achar necessário. Até aquele momento, ele come tão mal a memória nativa que pode fazer com que o Linux oom_killer mate o processo com impunidade. A questão principal é que a finalização em Java é muito pouco confiável e o G1 piorou até 7.0.2. Moral da história: libere recursos nativos assim que puder; o finalizador é muito pobre.

  • O mesmo caso com java.util.zip.Deflater . Este é muito pior já que o Deflater está com fome de memória em Java, ou seja, sempre usa 15 bits (max) e 8 níveis de memória (9 é no máximo) alocando centenas de KB de memória nativa. Felizmente, o Deflater não é amplamente utilizado e, até onde Deflater , o JDK não contém erros de uso. Sempre chame end() se você criar manualmente um Deflater ou Inflater . A melhor parte dos dois últimos: você não pode encontrá-los através de ferramentas de perfil normal disponíveis.

(Eu posso adicionar mais alguns desperdícios de tempo que eu encontrei em cima do pedido.)

Boa sorte e fique seguro; vazamentos são maus!





java field transient