Pergunta

Tanto quanto eu entendi o "bloco de inicialização estática" é usado para definir valores de campo estático se ele não pode ser feito em uma linha.

Mas eu não entendo por que precisamos de um bloco especial para isso. Por exemplo, podemos declarar um campo como estático (sem uma atribuição de valor). E em seguida, escrever várias linhas de código que gerar e atribuir um valor para o campo estático acima declarado.

Por que precisamos estas linhas em um bloco especial como: static {...}?

Foi útil?

Solução

O bloco não-estático:

{
    // Do Something...
}

é chamado sempre uma instância da classe é construído. O bloco estático só é chamado uma vez , quando a própria classe é inicializado, não importa quantos objetos desse tipo que você criar.

Exemplo:

public class Test {

    static{
        System.out.println("Static");
    }

    {
        System.out.println("Non-static block");
    }

    public static void main(String[] args) {
        Test t = new Test();
        Test t2 = new Test();
    }
}

Esta impressões:

Static
Non-static block
Non-static block

Outras dicas

Se eles não estavam em um bloco de inicialização estática, onde seriam eles? Como você declarar uma variável que só era para ser local para fins de inicialização, e distingui-lo de um campo? Por exemplo, como é que você quiser escrever:

public class Foo {
    private static final int widgets;

    static {
        int first = Widgets.getFirstCount();
        int second = Widgets.getSecondCount();
        // Imagine more complex logic here which really used first/second
        widgets = first + second;
    }
}

Se first e second não estavam em um bloco, eles parecem com campos. Se eles estavam em um bloco sem static na frente dele, que contaria como um bloco de inicialização de instância em vez de um bloco de inicialização estática, por isso seria executado uma vez por instância construída em vez de uma vez no total.

Agora, neste caso particular, você poderia usar um método estático em vez disso:

public class Foo {
    private static final int widgets = getWidgets();

    static int getWidgets() {
        int first = Widgets.getFirstCount();
        int second = Widgets.getSecondCount();
        // Imagine more complex logic here which really used first/second
        return first + second;
    }
}

... mas isso não funciona quando existem múltiplas variáveis ??que deseja atribuir dentro do mesmo bloco, ou nenhum (por exemplo, se você quiser apenas para registrar alguma coisa - ou talvez inicializar uma biblioteca nativa).

Aqui está um exemplo:

  private static final HashMap<String, String> MAP = new HashMap<String, String>();
  static {
    MAP.put("banana", "honey");
    MAP.put("peanut butter", "jelly");
    MAP.put("rice", "beans");
  }

O código na "estática" seção (s) será executado em tempo de carregamento de classe, antes de quaisquer instâncias da classe são construídos (e antes de quaisquer métodos estáticos são chamados de outros lugares). Dessa forma, você pode ter certeza de que os recursos de classe estão todos prontos para usar.

Também é possível ter non-static initializer blocos. Aqueles ato como extensões para o conjunto de métodos construtores definidos para a classe. Eles são parecidos com estática initializer blocos, exceto a palavra-chave "estático" está parado.

Também é útil quando você realmente não quer atribuir o valor a nada, como carregar alguma classe apenas uma vez durante a execução.

por exemplo.

static {
    try {
        Class.forName("com.example.jdbc.Driver");
    } catch (ClassNotFoundException e) {
        throw new ExceptionInInitializerError("Cannot load JDBC driver.", e);
    }
}

Ei, há um outro benefício, você pode usá-lo para lidar com exceções. Imagine que getStuff() aqui gera uma Exception que realmente pertence a um bloco catch:

private static Object stuff = getStuff(); // Won't compile: unhandled exception.

, em seguida, um inicializador static é útil aqui. Você pode tratar a exceção lá.

Outro exemplo é para fazer coisas depois que não pode ser feito durante a atribuição de:

private static Properties config = new Properties();

static {
    try { 
        config.load(Thread.currentThread().getClassLoader().getResourceAsStream("config.properties");
    } catch (IOException e) {
        throw new ExceptionInInitializerError("Cannot load properties file.", e);
    }
}

Para voltar ao exemplo driver JDBC, qualquer driver JDBC decente em si também faz uso do static initializer a registar-se no DriverManager. Veja também este e esta resposta .

Eu diria static block é apenas açúcar sintático. Não há nada que você poderia fazer com bloco static e não com qualquer outra coisa.

Para voltar a usar alguns exemplos postado aqui.

Este pedaço de código pode ser re-escrita sem usar static initialiser.

Método # 1: Com static

private static final HashMap<String, String> MAP;
static {
    MAP.put("banana", "honey");
    MAP.put("peanut butter", "jelly");
    MAP.put("rice", "beans");
  }

Método # 2: Sem static

private static final HashMap<String, String> MAP = getMap();
private static HashMap<String, String> getMap()
{
    HashMap<String, String> ret = new HashMap<>();
    ret.put("banana", "honey");
    ret.put("peanut butter", "jelly");
    ret.put("rice", "beans");
    return ret;
}

Existem algumas razões reais que é necessário para existir:

  1. inicializar membros static final cuja inicialização pode lançar uma exceção
  2. inicializar membros static final com valores calculados

As pessoas tendem a usar blocos static {} como uma maneira conveniente de inicializar as coisas que a classe depende dentro do tempo de execução, bem - como a garantia de que determinada classe é carregada (por exemplo, drivers JDBC). Isso pode ser feito de outras maneiras; no entanto, as duas coisas que eu mencionei acima só pode ser feito com uma construção como o bloco static {}.

Você pode executar pedaços de código uma vez para uma classe antes de um objeto é construído nos blocos estáticos.

por exemplo.

class A {
  static int var1 = 6;
  static int var2 = 9;
  static int var3;
  static long var4;

  static Date date1;
  static Date date2;

  static {
    date1 = new Date();

    for(int cnt = 0; cnt < var2; cnt++){
      var3 += var1;
    }

    System.out.println("End first static init: " + new Date());
  }
}

É um equívoco comum pensar que um bloco estático só tem acesso a campos estáticos. Por isso eu gostaria de mostrar abaixo pedaço de código que eu muitas vezes usar em projectos da vida real (copiado parcialmente a partir outra resposta num contexto um pouco diferente):

public enum Language { 
  ENGLISH("eng", "en", "en_GB", "en_US"),   
  GERMAN("de", "ge"),   
  CROATIAN("hr", "cro"),   
  RUSSIAN("ru"),
  BELGIAN("be",";-)");

  static final private Map<String,Language> ALIAS_MAP = new HashMap<String,Language>(); 
  static { 
    for (Language l:Language.values()) { 
      // ignoring the case by normalizing to uppercase
      ALIAS_MAP.put(l.name().toUpperCase(),l); 
      for (String alias:l.aliases) ALIAS_MAP.put(alias.toUpperCase(),l); 
    } 
  } 

  static public boolean has(String value) { 
    // ignoring the case by normalizing to uppercase
    return ALIAS_MAP.containsKey(value.toUpper()); 
  } 

  static public Language fromString(String value) { 
    if (value == null) throw new NullPointerException("alias null"); 
    Language l = ALIAS_MAP.get(value); 
    if (l == null) throw new IllegalArgumentException("Not an alias: "+value); 
    return l; 
  } 

  private List<String> aliases; 
  private Language(String... aliases) { 
    this.aliases = Arrays.asList(aliases); 
  } 
} 

Aqui o inicializador é usado para manter um índice (ALIAS_MAP), para mapear um conjunto de aliases volta para o tipo enum originais. Pretende-se como uma extensão para o método interno valueOf fornecida pelo próprio Enum.

Como você pode ver, a estática initializer acessa mesmo o private campo aliases. É importante compreender que o bloco static já tem acesso às instâncias de valor Enum (por exemplo ENGLISH). Isso ocorre porque a ordem de inicialização e execução no caso de tipos Enum , como se os campos static private foram inicializados com casos antes dos blocos static foram chamados:

  1. As constantes Enum que são campos estáticos implícitas. Isso requer o construtor e instância blocos Enum e inicialização de instância de ocorrer primeiro também.
  2. bloco static e inicialização de campos estáticos em ordem de ocorrência.

Esta inicialização fora-de-ordem (construtor antes do bloco static) é importante para nota. Isso também acontece quando inicializar campos estáticos com as instâncias semelhante a um Singleton (simplificações feitas):

public class Foo {
  static { System.out.println("Static Block 1"); }
  public static final Foo FOO = new Foo();
  static { System.out.println("Static Block 2"); }
  public Foo() { System.out.println("Constructor"); }
  static public void main(String p[]) {
    System.out.println("In Main");
    new Foo();
  }
}

O que vemos é o seguinte resultado:

Static Block 1
Constructor
Static Block 2
In Main
Constructor

claro é que a inicialização estática realmente pode acontecer antes o construtor, e mesmo depois:

Simplesmente acessando Foo no método principal, faz com que a classe a ser carregado e a inicialização estática para começar. Mas como parte da estática inicialização voltamos a chamar os construtores para os campos estáticos, após o qual voltará a tocar inicialização estática, e completa o construtor chamado de dentro do método principal. Em vez disso situação complexa para a qual espero que em condições normais de codificação que não teria que lidar com eles.

Para obter mais informações sobre este ver o livro " Effective Java "

Se suas variáveis ??estáticas precisam ser definidas em tempo de execução, em seguida, um bloco static {...} é muito útil.

Por exemplo, se você precisa definir o membro estático para um valor que é armazenado em um arquivo de configuração ou banco de dados.

Também é útil quando você quer adicionar valores a um membro Map estática como você não pode adicionar esses valores na declaração membro inicial.

Então você tem um campo estático (é também chamado de "variável de classe", porque pertence à classe, em vez da uma instância da classe, em outras palavras ele é associado com a classe do que com qualquer objeto) e você quer inicialize-o. Então, se você não quiser criar uma instância dessa classe e você quer manipular este campo estático, você pode fazê-lo de três formas:

1- Apenas inicialize-o quando você declarar a variável:

static int x = 3;

2 Tenha um bloco estático inicializar:

static int x;

static {
 x=3;
}

3 Tenha um método de classe (método estático) que acessa a variável de classe e inicializa-lo: esta é a alternativa para o bloco estático acima; você pode escrever um método estático privado:

public static int x=initializeX();

private static int initializeX(){
 return 3;
}

Agora, por que você usa bloco de Inicialização estática em vez de métodos estáticos?

É realmente até que você precisa em seu programa. Mas você tem que saber que bloco de inicialização estática é chamado uma vez e a única vantagem do método de classe é que eles podem ser reutilizados mais tarde, se você precisa reinicializar a variável de classe.

Vamos dizer que você tem um conjunto complexo em seu programa. Você inicializa-la (usando para circuito por exemplo) e, em seguida, os valores desta matriz irá mudar ao longo do programa, mas, em seguida, em algum momento você quer reinicializar-lo (voltar ao valor inicial). Neste caso, você pode chamar o método estático privado. No caso de você não precisa em seu programa para reinicializar os valores, você pode simplesmente usar o bloco estático e sem necessidade de um método estático uma vez você não vai usá-lo mais tarde no programa.

Nota: os blocos estáticos são chamados na ordem em que aparecem no código.

Exemplo 1:

class A{
 public static int a =f();

// this is a static method
 private static int f(){
  return 3;
 }

// this is a static block
 static {
  a=5;
 }

 public static void main(String args[]) {
// As I mentioned, you do not need to create an instance of the class to use the class variable
  System.out.print(A.a); // this will print 5
 }

}

Exemplo 2:

class A{
 static {
  a=5;
 }
 public static int a =f();

 private static int f(){
  return 3;
 }

 public static void main(String args[]) {
  System.out.print(A.a); // this will print 3
 }

}

Como suplementar, como @Pointy disse

O código na "estática" seção (s) será executado na carga horária tempo, antes de todas as instâncias de classe são construídos (e antes quaisquer métodos estáticos são chamados de outros lugares).

É suposto adicionar System.loadLibrary("I_am_native_library") em bloco estático.

static{
    System.loadLibrary("I_am_a_library");
}

Ele vai garantir nenhum método nativo ser chamado antes da biblioteca relacionado é carregado na memória.

De acordo com o loadLibrary da oracle :

Se este método é chamado mais de uma vez com o mesmo nome da biblioteca, o segundo e subseqüentes chamadas são ignorados.

Então, inesperadamente, colocando System.loadLibrary não é usado para a biblioteca evitar ser carregado multi-vezes.

Você primeiro precisa entender que suas classes de aplicação em si são instanciado a objetos java.class.Class durante a execução. Isto é, quando os blocos estáticos são ran. Então você pode realmente fazer isso:

public class Main {

    private static int myInt;

    static {
        myInt = 1;
        System.out.println("myInt is 1");
    }

    //  needed only to run this class
    public static void main(String[] args) {
    }

}

e que iria imprimir "myInt é 1" para console. Nota que eu não tenha instanciado qualquer classe.

static int B,H;
static boolean flag = true;
static{
    Scanner scan = new Scanner(System.in);
    B = scan.nextInt();
    scan.nextLine();
    H = scan.nextInt();

    if(B < 0 || H < 0){
        flag = false;
        System.out.println("java.lang.Exception: Breadth and height must be positive");
    } 
}

bloco estático é usado para qualquer tecnologia para inicializar membro de dados estáticos em forma dinâmica, ou podemos dizer que para a inicialização dinâmica do bloco estático membro de dados estáticos está sendo used..Because para membro não dados estáticos inicialização temos construtor mas nós não têm qualquer lugar onde podemos membro de dados dinamicamente initialize estática

Eg:-class Solution{
         // static int x=10;
           static int x;
       static{
        try{
          x=System.out.println();
          }
         catch(Exception e){}
        }
       }

     class Solution1{
      public static void main(String a[]){
      System.out.println(Solution.x);
        }
        }

Agora meu static int x irá inicializar dinamicamente ..Bcoz quando compilador irá para Solution.x ele irá carregar Solution Classe e carga bloco estático no carregamento de classe time..So podemos capaz de dinamicamente initialize que membro de dados estáticos ..

}

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top