Interpretação de questão SCJP 6.0

5 respostas
C

Pessoal, me ajudem por favor a interpretar uma questão. Fiz o exercício e não entendi nada sobre essa questão - por fim deixei pra voltar nela depois e fiz bem pois quando fui ver não sei pq motivos enfiaram uma questão do capítulo 3 no capítulo 2. Eu precisaria de conceitos do capítulo 3 antes de fazer esse exercício. Sacanagem. Enfim segue:

class A { }
 class B extends A { }
 public class ComingThru {
   static String s = "-";
   public static void main(String[] args) {
     A[] aa = new A[2];
     B[] ba = new B[2];
     sifter(aa);
     sifter(ba);
     sifter(7);
     System.out.println(s);
   }
static void sifter(A[]... a2)    { s += "1"; }
static void sifter(B[]... b1)    { s += "2"; }
static void sifter(B[] b1)       { s += "3"; }
static void sifter(Object o)     { s += "4"; }
}

What is the result?
A. -124
B. -134
C. -424
D. -434
E. -444
F. Compilation fails

D is correct. In general, overloaded var-args methods are chosen last. Remember that arrays are objects. Finally, an int can be boxed to an Integer and then “widened” to an Object.
No cap. 3 vi que metodos var-args são fracos, e vendo a resposta vi que falaram em boxing e widening.
Mas eu achei que essa sobrecarga de métodos, a preferência por fazê-los seria no caso de não haver uma correspondencia qto aos argumentos passados.
Por exemplo

fazQualquerCoisa(int x, int y);
fazQualquerCoisa(Integer x, Integer y);
fazQualquerCoisa(4,5);

Sendo assim seria escolhido o primeiro método pois há correspondência não sendo necessário fazer boxing.

Voltando ao exercício: O método a ser chamado na questão não seria este: static void sifter(B[] b1) { s += "3"; } pois espera um array e há correspondência, quando se passa sifter(aa); sifter(ba); Também estou estranhando que em um método é passado um array e no outro é passado um inteiro -sifter(7);- e estes chamam os mesmos métodos gerando 4 no print. O outro que chama tb um array por sua vez gera o 3. Me ajudem por favor porque essa questão, tá mto difícil. Qdo são simples var-args sei que são lidos método(int…x) - método recebe de 0 a alguns inteiros. Mas e nesse caso, como leio os argumentos que esse método espera - static void sifter(A[]… a2)???
Valew.

5 Respostas

GuilhermeKFreitas

1º CASO: Quando você faz a primeira chamada:

sifter(aa);

Você está passando um array do tipo A. Assim, o compilador procura alguma sobrecarga deste método que é compatível.
Como ele não encontra nenhum método que receba exatamente um array do tipo A, ele utiliza o método que recebe um Object :

static void sifter(A[] arg) {}        // esse não tem no exemplo! Se tivesse, seria o utilizado pela variável "aa"

   static void sifter(Object o) {}     // opa! Esse é o utilizado pelo "aa", visto que TODO array é um Object.

Só pra complementar, se não houvesse a sobrecarga com o método que recebe Object, na verdade quem receberia a chamada seria o do var-args de A[].

2º CASO: Ele procura uma sobrecarga para um objeto do tipo B[].
No caso do “ba”, o compilador mais uma vez verifica se existe uma sobrecarga que receba exatamente um array do tipo B:

static void sifter(A[]... a2)    { s += "1"; }            
static void sifter(B[]... b1)    { s += "2"; }
static void sifter(B[] b1)       { s += "3"; }           // opa! o método recebe exatamente B[] !
static void sifter(Object o)     { s += "4"; }

Obs: Se não houvesse aquele método, a seguinte prioridade seria essa:

1. static void sifter(Object o)     { s += "4"; }               // B[] é um array, que por sua vez é um Object !  
2. static void sifter(B[]... b1)    { s += "2"; }                // método recebe de 0 .. n objetos B[].
3. static void sifter(A[]... a2)    { s += "1"; }                    // método recebe de 0.. n objetos A[], e que pela hierarquia, tipo B é um tipo A. (B extends A)

3º CASO: o método recebe um int !
Nesse caso, há um auto-boxing acontecendo. O tipo int é automaticamente empacotado para Integer, que por sua vez, é um Object.
Sendo assim, o método chamado é:

static void sifter(Object o)     { s += "4"; }

É isso.
Não sei se consegui explicar bem… também tô estudando pro SCJP !

diegohsi

GuilhermeKFreitas:
1º CASO: Quando você faz a primeira chamada:

sifter(aa);

Você está passando um array do tipo A. Assim, o compilador procura alguma sobrecarga deste método que é compatível.
Como ele não encontra nenhum método que receba exatamente um array do tipo A, ele utiliza o método que recebe um Object :

static void sifter(A[] arg) {}        // esse não tem no exemplo! Se tivesse, seria o utilizado pela variável "aa"

   static void sifter(Object o) {}     // opa! Esse é o utilizado pelo "aa", visto que TODO array é um Object.

Só pra complementar, se não houvesse a sobrecarga com o método que recebe Object, na verdade quem receberia a chamada seria o do var-args de A[].

2º CASO: Ele procura uma sobrecarga para um objeto do tipo B[].
No caso do “ba”, o compilador mais uma vez verifica se existe uma sobrecarga que receba exatamente um array do tipo B:

static void sifter(A[]... a2)    { s += "1"; }            
static void sifter(B[]... b1)    { s += "2"; }
static void sifter(B[] b1)       { s += "3"; }           // opa! o método recebe exatamente B[] !
static void sifter(Object o)     { s += "4"; }

Obs: Se não houvesse aquele método, a seguinte prioridade seria essa:

1. static void sifter(Object o)     { s += "4"; }               // B[] é um array, que por sua vez é um Object !  
2. static void sifter(B[]... b1)    { s += "2"; }                // método recebe de 0 .. n objetos B[].
3. static void sifter(A[]... a2)    { s += "1"; }                    // método recebe de 0.. n objetos A[], e que pela hierarquia, tipo B é um tipo A. (B extends A)

3º CASO: o método recebe um int !
Nesse caso, há um auto-boxing acontecendo. O tipo int é automaticamente empacotado para Integer, que por sua vez, é um Object.
Sendo assim, o método chamado é:

static void sifter(Object o)     { s += "4"; }

É isso.
Não sei se consegui explicar bem… também tô estudando pro SCJP !


Muito bem explicado GuilhermeKFreitas , eu ja estou no capítulo 9 do livro da katy 6 e ja tinha me esquecido um pouco da ampliação, autoboxing e var…args, a sua explicação me fez relembrar. Grato!
bons estudos!!

C

Guilherme, explicou sim, bem detalhado. Eu é que quando vejo arrays fico meio confuso. Me responda uma coisa: que tipo de chamada, chamariam esses métodos

static void sifter(A[]... a2)    { s += "1"; }   
static void sifter(B[]... b1)    { s += "2"; }

Só pra eu ver se consigo entender melhor.

C

Christian_BHZ:
Guilherme, explicou sim, bem detalhado. Eu é que quando vejo arrays fico meio confuso. Me responda uma coisa: que tipo de chamada, chamariam esses métodos

static void sifter(A[]... a2)    { s += "1"; }   
static void sifter(B[]... b1)    { s += "2"; }

Só pra eu ver se consigo entender melhor.

Mais uma coisa, se não houvesse a sobrecarga com Object, ao chamar

sifter(aa);   
sifter(ba);

o que seria impresso seria “12” ???

GuilhermeKFreitas

Christian_BHZ:
Christian_BHZ:
Guilherme, explicou sim, bem detalhado. Eu é que quando vejo arrays fico meio confuso. Me responda uma coisa: que tipo de chamada, chamariam esses métodos

static void sifter(A[]... a2)    { s += "1"; }   
static void sifter(B[]... b1)    { s += "2"; }

Só pra eu ver se consigo entender melhor.

Mais uma coisa, se não houvesse a sobrecarga com Object, ao chamar

sifter(aa);   
sifter(ba);

o que seria impresso seria “12” ???

Exatamente !

Então Christian_BHZ ,

static void sifter(A[]... a2)    { s += "1"; }     
static void sifter(B[]... b1)    { s += "2"; }

Tratando-se de var-args, como eu disse anteriormente, eles são o “último recurso” do compilador. Nos casos acima, ele aceitam de 0… a N arrays de A[] e B[].

Uma coisa que eu fiz para descobrir qual método é chamado, foi listar a ordem de prioridades:

1. Quando o argumento do método é EXATAMENTE igual a referencia passada:

B[] ref = new B[2];
sifter(ref);

static void sifter(B[] b){}   // exatamente o que esperava!

2. Quando o argumento do método é uma superclasse da referência passada por parâmetro.

class A {}
class B extends A {}   


B[] ref = new B[2];

sifter(ref);


//static void sifter(B[] b ){ }      // se este não existisse..
static void sifter(A[] a ){ }      // chamaria este aqui
static void sifter(Object o ) {}    // E se não houvesse o método acima, chamaria este !

3. Se ainda não achou um método compatível, procura algum com o método var-args.

main() {
..
B[] b2 = new B[2];

B[][] bidimensional bb2 = new B[3][];

sifter(b2);
sifter(bb2);      // também usa o método do var-args.
sifter();         // também utilizaria o do var-args. Lembre: de 0..n argumentos !

}

//static void sifter(A a ){ }         
//static void sifter(B b ){ }         
//static void sifter(Object o ) {}    
static void sifter(B[]... b2 ){}     // primeiro procura o var-args EXATAMENTE do seu tipo!
static void sifter(A[]... a2 ){]     // senão, segue a hierarquia.
static void sifter(Object[]... o2) {} // este seria chamado, se os 2 acima não existissem!

Eu geralmente analiso desse modo. Não sei se consegui tirar suas dúvidas.
Uma dica que te dou é você criar seu próprios exemplos ! Copie o exercicio pro PC e vai deletando/criando os métodos … e vendo como se comporta.
Ajudou muito comigo !

Criado 15 de janeiro de 2011
Ultima resposta 17 de jan. de 2011
Respostas 5
Participantes 3