Alterando o Java padrão no linux Ubuntu

Uma coisa que acho muito incômoda no ubuntu é o fato de, sempre que um nova distribuição Java é instalada o Java padrão do sistema é alterado, isso acontece as vezes sem mesmo que a gente perceba, quando você quer o sun-java instalado por padrão é quase impossível não instalar um outro aplicativo que adicione como dependência outro java (muitas vezes o open-jdk) e esse novo passa a assumir o papel do java padrão.

Para resolver isso um truque muito simples pelo terminal resolve o problema:

sudo update-alternatives --config java

Alterando o Java padrão do Ubuntu

Entendendo orientação a objetos, parte 3

Estou de volta para continuar a série de artigos sobre POO. A partir de agora, começaremos a ver conceitos um pouco mais avançados. Gostaria de lembrar também, que algumas linguagens orientadas a objetos tem certas diferenças em sintaxe. Aqui vou me restringir à linguagem Java fazendo comentários com C++.

Em seqüência ao último capítulo, vamos continuar a entender a herança em POO. Como foi visto anteriormente herança é a propriedade de uma classe herdar informações (ex.: atributos e métodos) de uma outra.

Em alguns casos, uma classe pode herdar informações de uma ou mais classes simultaneamente. Vamos supor que tenhamos as classes Destruidor e Defensor com uma terceira classe Robo herdando das duas anteriores, neste exemplo nosso robô assumirá as características de Destruidor e Defensor ao mesmo tempo, herdando as características de duas classes. Esta capacidade de herdar várias classes, chama-se herança múltipla.

public class Destruidor {
 
    public Destruidor() {
    }
 
    public void atacar() {
        System.out.println("Atirar com fuzil.");
    }
 
}
 
public class Defensor {
 
    public Defensor() {
    }
 
    public void defender() {
        System.out.println("Defender-se com escudo.");
    }
 
}
 
/* Este código não compila!!! Apenas para fim didático */
public class Robo extends Defensor, Destruidor {
 
    public Robo() {
    }
 
    public static void main(String[] args) {
        Robo robo = new Robo();
        robo.atacar();
        robo.defender();
    }
 
}

Na linguagem C++ temos a possibilidade de herdar várias classes apenas especificando na declaração da classe, já na linguagem java não é possível fazer com que uma classe herde (estenda) mais de uma classe, então temos que contornar o problema utilizando outras técnicas em Java, vamos entender o porquê desta restrição.

De volta ao exemplo da classe sobre robôs, desta vez vamos supor que tenhamos as seguintes classes: Prototipo, Destruidor e AutoDestruidor, vamos analisar como seria o código utilizando a classe Robo para herdar as características das anteriores:

public class Prototipo {
 
    public Prototipo() {
    }
 
    public void atacar() {
        System.out.println("Atirar de pistola.");
    }
 
}
 
public class Destruidor {
 
    public Destruidor() {
    }
 
    public void atacar() {
        System.out.println("Atirar com fuzil.");
    }
 
}
 
public class AutoDestruidor {
 
    public AutoDestruidor() {
    }
 
    public void atacar() {
        System.out.println("Robô bomba, explodir!");
    }
}
 
/* Este código não compila!!! Apenas para fim didático */
public class Robo extends Destruidor, AutoDestruidor {
 
    public Robo() {
    }
 
    public static void main(String[] args) {
        Robo robo = new Robo();
        robo.atacar();
    }
 
}

E agora? Se eu mandar o robô atacar, ele atira de pistola, de fuzil ou ele se detona? Esse é o conhecido problema do diamante (desenhe a modelagem UML dessas classes e entenderá o porquê deste nome). O problema do diamante é o motivo especial pelo qual a linguagem Java não trabalha diretamente com herança múltipla. O que poderíamos fazer para contornar este problema? Utilizar interfaces, desta forma sempre teremos apenas uma implementação para cada método.

Agora que sabemos como funciona herança, podemos conhecer o terceiro e último modificador de encapsulamento, o protected, que assume private ou public de acordo com a classe a qual está sendo acessada, com ele especificamos que um atributo (ou método) é definido como private para subclasses (classes filhas herdadas) e as classes do mesmo pacote, enquanto fica definida como public para as demais classes.

O modificador final serve para indicar que é proibido modificações posteriores. Pode ser usado em classe, método e atributos, uma classe com o modificador final não poderá ser herdada por nenhuma outra classe, nem um método poderá ser sobrescrito tampouco poderá um atributo ter seu valor modificado depois de uma atribuição inicial.

Já o modificador static define que o atributo (ou método) será de acesso da classe e não do objeto. Qual a diferença disso? Se um método pertence ao objeto, ele somente poderá ser acessado após haver uma instância alocada da classe, se temos dois objetos, carroA e carroB, da classe Carro a qual possui um método correr, se fizermos uma chamada para o método correr no objeto carroA e no carroB, teremos duas chamadas do método correr ocorrendo em posições de memória diferentes onde seu resultado vai depender das variáveis particulares de carroA e carroB. Caso o modificador static fosse adicionado ao método correr, não seria necessário alocar nenhuma instância de Carro para que pudéssemos fazer uma chamada ao método correr, este método poderia ser chamado diretamente da classe Carro.

Também podemos utilizar o modificador static em atributos, isto seria propício para termos uma variável a qual todos os objetos pudessem conhecer o seu valor, tal fato ocorre devido a utilização do modificador static, ao invés de serem alocados n atributos para n objetos, é alocado apenas 1 atributo para n objetos, onde todos os objetos têm acesso ao mesmo atributo.

public class Carro {
 
    private String modelo;
    private static int numero;
 
    public Carro(String modelo) {
        this.modelo = modelo;
    }
 
    public void correr() {
        System.out.println(String.format("Estou correndo de %s. Fui o %dº a sair.", modelo, ++numero));
    }
 
    public static void frear() {
        System.out.println("Pisar no freio.");
    }
 
    public String getModelo() {
        return modelo;
    }
 
    public int getNumero() {
        return numero;
    }
 
    public static void main(String[] args) {
        Carro carroA = new Carro("Ferrari");
        Carro carroB = new Carro("Porsche");
 
        carroA.correr();
        carroB.correr();
 
        Carro.frear();
    }
 
}

Execução da classe Carro.java:

Estou correndo de Ferrari. Fui o 1º a sair.
Estou correndo de Porsche. Fui o 2º a sair.
Pisar no freio.