24 Mar
Em Java, existe um bloco de código que é executado no momento em que o ClassLoader pega a sua classe e carrega ela. Isso ocorre antes de existir uma instância da sua classe.
public class Teste {
public static void main(String []args){
System.out.println("Antes de criar a variável");
A a;
System.out.println("Depois de criar a variável");
//Vamos criar 10 instâncias de A
for (int i = 0; i < 10; i++)
a = new A();
System.out.println("Depois de criar a instância");
}
}
class A {
static {
System.out.println("Bloco Estático");
}
A(){
System.out.println("Construtor");
}
}
se você rodar esse código, a saída será:
Antes de criar a variável
Depois de criar a variável
Bloco Estático
Construtor
Construtor
Construtor
Construtor
Construtor
Construtor
Construtor
Construtor
Construtor
Construtor
Depois de criar a instância
Notem que o ClassLoader coloca a sua classe na memória apenas uma vez, independente de quantas classes você instancia (ok. Eu já ouvi histórias de magos que conseguem fazer a VM executar o bloco estático várias vezes sem trocar o ClassLoader, mas não faço idéia de como fazer isso.).
E Antes que os mais rigorosos gritem comigo, nada garante que a variável vai ser alocada entre as duas primeiras chamadas ao println. A VM pode simplesmente criar a variável antes das chamadas.
Posts Relacionados:
17 Mar
Uma peculiaridade estranha do switch do java é que ele não funciona para o tipo long.
O switch funciona apenas para byte, short, char e int.
public class Teste {
public static void main(String []args){
long l = 10;
switch (l){
case 10: System.out.println("Isso não compila");
}
}
}
O código acima não compila. Isso acontece porque o switch espera um int (porque isso acontece já é outra história) e um long não pode ser convertido para int sem um cast, por causa da possível perda de precisão (afinal cabe muito mais coisa dentro de um long do que dentro de um int).
Todos os outros tipos podem ser promovidos para int sem nenhum problema (pois no int cabe mais do que em um byte, short ou char).
Em Java, T caber em O significa min(O) < min(T) e max(O) > max(T). Isso também vale para float e double, o que nos leva a montar a seguinte sequência de promoção automática:
char -> int
byte -> short -> int -> long -> float -> double
O que parece estranho é o long usar 64 bits enquanto que o float usa só 32. Mas como obedecem à regra acima, a promoção é feita do mesmo jeito.
Posts Relacionados:
10 Mar
Java possui um bloco de código que é executado antes dos contrutores da sua classe, mas depois que sua classe já está carregada para a memória.
public class Teste {
public static void main(String []args){
A a;
//Vamos criar 3 instâncias de A
for (int i = 0; i < 3; i++)
a = new A();
System.out.println("Depois de criar a instância");
}
}
class A {
static {
System.out.println("Bloco Estático");
}
{
System.out.println("Pré Contrutor");
}
A(){
this(0);
System.out.println("Construtor sem parâmetro");
}
A(int i){
System.out.println("construtor com parâmetros");
}
}
Rodando esse código estranho, a saída é a seguinte:
Bloco Estático
Pré Contrutor
construtor com parâmetros
Construtor sem parâmetro
Pré Contrutor
construtor com parâmetros
Construtor sem parâmetro
Pré Contrutor
construtor com parâmetros
Construtor sem parâmetro
Depois de criar a instância
Notem que o pré construtor só é executado uma vez para cada instância que você cria, independente se você chama vários construtores.
Mas a parte mais assustadora é que você pode ter vários pré construtores, e eles são executados na ordem em que aparecem na sua classe (quero ver alguém falar bem de Java agora ;) )
public class Teste {
public static void main(String []args){
A a = new A();
}
}
class A {
{
System.out.println("Pré Construtor de Cima");
}
A(){
System.out.println("Construtor");
}
{
System.out.println("Pré Contrutor de Baixo");
}
}
A saída é:
Pré Construtor de Cima
Pré Contrutor de Baixo
Construtor
Bem feio, não?
Posts Relacionados:
3 Mar
O que acontece quando uma classe sua implementa duas interfaces que tem um método com o mesmo nome? Compila!
interface A {
void x();
}
interface B {
void x();
}
class C implements A, B {
public void x() {
}
}
E quando sua classe herda um método que tem o mesmo nome do método de uma interface que ela implementa? Também compila!
class A {
void x(){
}
}
interface B {
void x();
}
class C extends A implements B {
public void x() {
}
}
Notem que A não precisa implementar B.
E quando você faz herança múltipla de interfaces? Mais uma que compila.
interface A {
void x();
}
interface B {
void x();
}
interface C extends A,B {
}
Essas aqui eu só acreditei na hora em que o compilador simplesmente não reclamou. Se um dia antes de eu fazer esses testes me perguntassem o que acontecia, eu falaria sem medo nenhum que não compilava. Mas compila.
Posts Relacionados: