sábado, 28 de agosto de 2010

Resumo SCJP - Parte IV


CONVERSÃO DE VARIÁVEIS DE REFERENCIA:
                                            
class Game{
}
class TopGear extends Game{
}
public class Rascunho{
      public static void main(String[] args) {
            TopGear b = (TopGear) new Game();
      }
}
Dessa forma, o código consegue ser compilado, mas lança um warning.
Outro motivo de compilar, é por estar todas na mesma árvore de herança, pois um TopGear não pode ser um Jogo!!!
Outra atenção que devemos ter é: o que deve ser convertido é o OBJETO não o TIPO DELE.

class Game{
}
class TopGear extends Game{
}
public class Rascunho{
      public static void main(String[] args) {
            Game game = new TopGear();
            Game gm = (TopGear)game;
            //compila porque game é um objeto do tipo TopGear
      }
}

Se o tipo do objeto não fazer parte da arvore de herança NÃO É COMPILADO.

Quando tempo fazer algo impossível, uma conversão meio cabulosa, uma exceção é lançada:
TopGear game = new Game();
Outra erro de compilação:
class Pais{
      public void pib(){
            System.out.println("PIB");
      }
}
class Brasil extends Pais{
      public void populacao(){
            System.out.println("populacao");
      }
}

class MinasGerais extends Brasil{
      public void comida(){
            System.out.println("comida");
      }
}

class BH{
      public void  bairro(){
            System.out.println("Bairro");
      }
}

class Localizacao extends BH{
      public void local(){
            System.out.println("local");
      }
}

public class Rascunho{
      public static void main(String[] args) {
            BH bh = new Localizacao();
            bh.local();
      }
}
Aí não temos o metodo local() na classe BH. Por isso o código não é compilado, devemos converter para que nosso código seja compilado.

((Localizacao)bh).local();
Dessa forma, o nosso código compila.



INTERFACE

 - É um contrato que fazemos, onde todos os métodos assinados na interface deverão ser implementados.
 - Fornecer implementação concreta para todos os métodos abstratos;
 - Seguir regras de sobrecarga;
 - Manter assinatura e mesmo tipo de retorno.

Se a classe que tiver implementando uma interface for ABSTRATA, ela não tem obrigação de implementar nenhum método.
Uma classe pode implementar 2 ou mais interfaces.

O que não devemos esquecer:

- Uma interface jamais vai implementar outra.
- Uma interface jamais vai implementar uma classe.
- Interface não extends class
interface veiculo{
      void velocidade();
}
interface fabricante{
      void modelo();
}
class fusca implements veiculo, fabricante{
      public void velocidade() {
      }
      public void modelo() {
      }
}

Neste exemplo a classe fusca implementa as duas interfaces, tem que implementar os metodos das respectivas. Caso um deixe de ser implementado o codigo não é compilado.

Como falamos anteriormente, se a classe for abstrata ela não necessita implementar todos os métodos.

interface veiculo{
      void velocidade();
}
interface fabricante{
      void modelo();
}
abstract class fusca implements veiculo, fabricante{
      public void velocidade() {
      }
}

Uma observação que merece ser frisada é que, quando duas interfaces forem implementadas pela mesma classe, as interfaces definitivamente não poderá ter métodos com mesmo nome.

Interfaces não possuem construtores.


TIPOS DE RETORNO:

Void: não retorna nada
public void velocidade() {}

Retorno de Objetos: em um método que tenha um tipo de Objeto como retorno, ela pode retornar qualquer tipo (desde que esteja dentro da arvore de herança)
public Animal velocidade() {
      return Cavalo(); 
}
// a classe deve extends a Animal

CONSTRUTORES:
Serve para inicializar o estado das variáveis de instância. Toda classe possui um (ou mais) construtores.
Construtores não possuem tipo de retorno.
Uma atenção que devemos tomar é: VOID é um tipo de retorno, e um construtor não deve ter um retorno.


abstract class fusca implements veiculo, fabricante{
      public void velocidade() {
      }
      public fusca(){}
}

O código abaixo não compila, pois o construtor da superclasse necessita de um parametro.

class PaisFabricacao{
      private String nomePais;
     
      public PaisFabricacao(String nome) {
            this.nomePais = nome;
      }
}

abstract class fusca extends PaisFabricacao implements veiculo, fabricante{
      public void velocidade() {
      }
      public fusca(){}
}

Como herdamos a classe PaisFabricacao, e o construtor dessa necessita de um parametro, devemos instacia-la passando um paramentro no construtor.

ESTÁTICOS – STATIC
Garante que haverá apenas uma referencia a determinada variável na memoria.

Satic, nos permite acessar diretamente, sem a necessitedade de instanciar o objeto.

class PaisFabricacao{
      private String nomePais;
      public static String fabricaoEmSerie = "FABRICACAO_EM_SERIE";
      public PaisFabricacao() {
      }
     
      public PaisFabricacao(String nome) {
            this.nomePais = nome;
      }
}

abstract class fusca extends PaisFabricacao implements veiculo, fabricante{
      public void velocidade() {
      }
      public fusca(){}
      public static void main(String[] args) {
            String emSerie = PaisFabricacao.fabricaoEmSerie;
            //como é public e static, não nessecitamos de instanciar um objeto
           
      }
}
O mesmo é aplicado para métodos.


COESÃO E ACOPLAMENTO.

COESÃO: Quando uma classe é bem definida e focada. Quando uma classe tem um único objetivo e função. Devemos sempre tentar com uma alta COESÃO.

class VendaCliente{
      public void efetuaVenda(){}
      public void calculaTotal(){}
}

ACOPLAMENTO:
Quando uma classe tem dependencia com outras. Devemos tentar ao máximo diminuir o acoplamento.

No exemplo abaixo, nada sei sobre o cliente, apenas consumo o seus serviços.

class Cliente{
      void verificaCredito(){}
}

class VendaCliente{
      private static Cliente cliente;
      public void efetuaVenda(){}
      public void calculaTotal(){}
      public static void main(String[] args) {
            cliente.verificaCredito();
      }
}

Uma classe não deve saber quase nada da outra, assim garantimos um baixo acoplamento.

Bom, por hoje é só, no próximo resumo entraremos no terceito capitulo do livro da kathy Sierra.

Espero ter ajudado.....

quarta-feira, 25 de agosto de 2010

Resumo SCJP - Parte III


2  -  FUNDAMENTOS

HERANÇA
Promove a reutilização de códigos, deixando códigos mais claros e evita a duplicação do código. Ganhamos muita produtividade em sistemas “grandes”, quando temos que realizar algum tipo de manutenção em um determinado código.

class Game{
      public void inicio(){
            System.out.println("Inicio");
      }
}

class TopGear extends Game{
      public void fim(){
            System.out.println("Fim");
      }
}

public class Rascunho{
      public static void main(String[] args) {
            TopGear jogo = new TopGear();
            jogo.inicio(); //metodo da classe Game
            jogo.fim(); //metodo da classe TopGear
      }
}
 Um bom exemplo de herança foi citado acima, a classe TopGear herdou o método inicio da classe Game.

RELACIONAMENTO  É-UM:

Este conceito é baseado na herança de classes ou implementações de interfaces.
Segue alguns exemplos:
Belina  É-UM Veiculo(Belina  é um tipo de veiculo – pode até não parecer verdade, mas é J )
Cachorro É-UM Animal.

Em java isso ficaria assim:
class Game{
      public void inicio(){
            System.out.println("Inicio");
      }
}

class TopGear extends Game{
      public void fim(){
            System.out.println("Fim");
      }
}

public class Rascunho{
      public static void main(String[] args) {
            Game jogo = new TopGear();
 // TOPGEAR É UM JOGO -> ISSO COMPILA
            TopGear jogo = new Game();
 // GAME NÃO É UM TOPGEAR -> ISSO NÃO COMPILA
// o máximo que poderíamos fazer, é converter game para   // topgear, mas não seria o nosso caso
      }
POLIMORFISMO:
Como o próprio nome já bastante intuitivo, muitas formas.
Sabemos que vários animais correm, mas também sabemos que correm de maneira de diferentes.
Uma classe pode herdar métodos da classe mãe e pode implementar os métodos marcados com abstract.

class Game{
      public void start(){
            System.out.println("Start game");
      }
}

class TopGear extends Game{
      public void start(){
            System.out.println("Inicio Lento");
      }
}

class NeedForSpeed extends Game{
      public void start(){
            System.out.println("Incio rápido");
      }
}

Polimorfismo em Interface: não faz parte da hierarquia de classe ou seja, uma classe não pode extends a uma interface mas pode implementá-la;

Métodos subscritos:
Acontece quando herdo um método da classe mãe, e altero o comportamento dele na classe filha.
Um ponto importante a ser destacado, é que métodos abstratos  não podem ser sobrecarregados.
abstract class Game{
      public void start(){
            System.out.println("Start game");
      }
     
      public abstract void nada();
}

class TopGear extends Game{
      public void start(){
            System.out.println("Inicio Lento");
      }
     
      public void nada(){
            //tenho que implementar
      }
}
 
Só é possível referenciar objetos do tipo que a super classe conheça.

class Game{
      public void start(){
            System.out.println("Start game");
      }
}

class TopGear extends Game{
      public void start(){
            System.out.println("Inicio Lento");
      }
}

public class Rascunho{
      public static void main(String[] args) {
            Game a = new Game();
            Game b = new TopGear();
            a.start();
            b.start();
      }
}
No caso acima, como a variável “a” é do tipo Game e o objeto do tipo Game, a.start() irá imprimir “Start Game”, e a variável “b” é do tipo TopGear() porém  o objeto é TopGear, irá imprimir “Início Lento”.

Outra informação que vale muito a pena salientar: Se na classe TopGear tivesse o ‘public void velocidade(){}’ e se o objeto B tentasse acessá-lo, um erro de compilação iria acontecer, pois a classe Pai, não possui este método.

class Game{
      public void start(){
            System.out.println("Start game");
      }
}

class TopGear extends Game{
      public void start(){
            System.out.println("Inicio Lento");
      }
     
      public void velocidade(){
            System.out.println("100km/h");
      }
}

public class Rascunho{
      public static void main(String[] args) {
            Game a = new Game();
            Game b = new TopGear();
            a.start();
            b.start();
           
            b.velocidade(); // classe pai não tem este método..
// ERRO COMPILAÇÃO
      }
}

Regras Importantes a serem seguidas:
- Ao herdar um método, jamais posso diminuir a sua visibilidade;
- Tipo de retorno deve ser o mesmo;
- Lista de argumentos deve ser igual, se não vira sobrecarga;
- Métodos staticos não podem ser subscritos.
- Método subscrito pode ou não lançar uma execeção mais restritiva que a da superclasse.
class Game{
      public void start(){
            System.out.println("Start game");
      }
}

class TopGear extends Game{
      public void start() throws Exception{//Erro de compilação
            System.out.println("Inicio Lento");
      }

}
O mesmo vale para métodos Static.

Quando se tem exceções menos restritivas,  o código compila.
class Game{
      public void start(){
            System.out.println("Start game");
      }
}

class TopGear extends Game{
      public void start() throws RuntimeException{
            System.out.println("Inicio Lento");
      }

}
 
MÉTODOS SOBRECARREGADOS.
Usar o mesmo nome de um método várias em uma mesma classe, alterando apenas os argumentos.
Métodos sobrecarregados podem:
-  alterar o tipo de retorno
-  alterar o modificador de acesso (private, protected)
-  ser sobrecarregado na mesma classe ou subclasse

Game b = new TopGear();
//Game: referencia
//TopGear: tipo do objeto


Um exemplo que pode confudir é este:
class Game{
      public void start(){
            System.out.println("Start game");
      }
}

class TopGear extends Game{
      public void start(int a){
            System.out.println("Inicio Lento");
      }

}

public class Rascunho{
      public static void main(String[] args) {
            Game b = new TopGear();
            b.start();
//vai executar o metodo da referencia, pois o do tipo foi sobrecarregado
      }
}
Neste caso acima, ele so chama o método do tipo, se criarmos um objeto com a referencia TopGear.

Outro exemplo que confunde bastante:
class Game{
      public void cor(){
            System.out.println("branco");
      }
      public void cor(String str){
            System.out.println("Preto");
      }
}

class TopGear extends Game{
      public void cor(){
            System.out.println("Azul");
      }
      public void cor(String str){
            System.out.println("vermelho");
      }
}

public class Rascunho{
      public static void main(String[] args) {
            Game b = new Game();
            Game c = new TopGear();
            Game d = new TopGear();
           
Linha 1           b.cor(); //branco
Linha 2           c.cor();// azul
Linha 3           d.cor("cor");// vermelho
      }
}
Na linha 2, ele chama o metodo da subclasse, pois o método sobrecarregado foi subscrito, ele chama a cor() do Objeto não da referência.

Metodo cor foi sobrecarregado na superclass
Metodo cor foi subscrito na subclasse.

Bom, por hoje é só. Amanhã volto com mais novidades no meu resumão. :-)