Alguém SABE?

23 respostas
E
public  T soma1() {

return 35;

}
public  T soma2() {

return new Integer(35);

}

Porque o primeiro compila e o segundo não?
Muitos falam porque a classe Integer é final, más porque o primeiro compila?
Cade os desenvolvedores do compilador para explicar?

AHUAHUAHA

23 Respostas

LPJava

no primeiro ta acontecendo o autoboxing do java 5 por isso compila e no segundo vc eestá retornando um objeto e nao um inteiro. o autoboxing nao vai funciona ai…

bem foi o que achei…

Fernando_Generoso_da

pq o retorno do segundo exige um objeto que extends integer, e não um integer como está sendo feito…

victorwss

Olha, em teoria os dois são equivalentes.
O primeiro, com o autoboxing, o compilador transformaria em algo equivalente ao segundo.
Não vejo motivo nenhum para um compilar e outro não, vou fazer uns testes aqui.

EDIT: Para mim nenhum dos dois compilou. O compilador queria um T, mas achou um Integer. Fica mais fácil entender se o código fosse assim:

public <T extends Integer> T soma2(Class<T> c) { return new Integer(35); }Neste caso, suponha que existissem subclasses de Integer (o compilador não verifica se a classe é final), você estaria retornando a subclasse sendo que o retorno desejado poderia ser uma subclasse.

Se no seu compilador o primeiro método compila, então você achou um bug no compilador.

LPJava

victorwss:
Olha, em teoria os dois são equivalentes.
O primeiro, com o autoboxing, o compilador transformaria em algo equivalente ao segundo.
Não vejo motivo nenhum para um compilar e outro não, vou fazer uns testes aqui.

é vou testar tb, meio estranho se ele fou que nao compila… .

gilmarcand

Independente de qualquer coisa, preciso fazer a conversão para indicar o retorno correto

public  <T extends Integer> T soma2() {
			return (T) new Integer(35);
		}

O estranho é que foi permitido indicar o extends para uma classe final. não sabia que isso era possível. Vou ficar de olho para ver se alguém aparece com uma boa explicação.

Elvano

Prezados, me perdoem se eu estiver me metendo em uma briga de gente grande :slight_smile: Meu objetivo é acompanhar a discussão e aprender…

Não seria esse o caso discutido no livro Effective Java 2 ed. no capitulo sobre Generics , item 28: “Use bounded wildcards to increase API flexibility”.
http://java.sun.com/docs/books/effective/

Na página 137 do capitulo 5 (exatamente o capitulo que tá disponivel no link da Sun, acima) o autor diz:

Do not use wildcard types as return
types.
Rather than providing additional flexibility for your users, it would force
them to use wildcard types in client code.

Negritos do autor. Não é isso que acontece aqui?: public <T extends Integer> T soma2() { return new Integer(35); } ?

Nesse capítulo ele descreve alguns detalhes das especificações da linguagem e sobre o compilador, que me pareceu ter relação com o primeiro codigo nao ter funcionado, mas funcionar quando fez um cast explícito return (T) new Integer(35);

Coincidiu de eu ler esse tópico depois de assistir a um video do autor do livro referido no site http://www.parleys.com/display/PARLEYS/Home#page=Home

Saudações,
elvano.

gustavobs

Não consegui uma explicação convincente… pra mim nenhum dos 2 deveria compilar… mas o 2o compila mesmo.

A
<blockquote><div class="quote-author">estundidher:</div>public  T soma1() {

return 35;

}
public  T soma2() {

return new Integer(35);

}

Porque o primeiro compila e o segundo não?
Muitos falam porque a classe Integer é final, más porque o primeiro compila?
Cade os desenvolvedores do compilador para explicar?

AHUAHUAHA

No primeiro caso o retorno é um int primitivo e o compilador faz o autoboxing. <T extends Integer> quer dizer que o compilador vai aceitar um T ou um Integer, o compilador vê que um int não é um T e (nem pode ser convertido para um) e vai para a superclasse, que é um Integer. testa, vê que um int pode ser convertido automaticamente para um Integer (depois do Java 5) e compila.

No segundo caso o compilador percebe que o Integer 35 já deveria poder ser um T, mas isso não é possível pois Integer é final e T não pode extender Integer, isso nem compila.

Não é uma explicação, é uma narração do que, a meu ver, parece estar acontecendo, muito estranho, vou ver se acho alguma explicação.

victorwss

Qual é a versão do teu compilador?

Marcelo_FS

victorwss:

EDIT: Para mim nenhum dos dois compilou. O compilador queria um T, mas achou um Integer.

Se no seu compilador o primeiro método compila, então você achou um bug no compilador.

Aqui compilou o primeiro, mas não o segundo…

java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)

Eclipse Platform
Version: 3.4.1
Build id: M20080911-1700
victorwss
MarceloS:
victorwss:
EDIT: Para mim nenhum dos dois compilou. O compilador queria um T, mas achou um Integer. ... Se no seu compilador o primeiro método compila, então você achou um bug no compilador.

Aqui compilou o primeiro, mas não o segundo...

java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)

Eclipse Platform
Version: 3.4.1
Build id: M20080911-1700
O meu também é 1.6.0_10-b33. Estou usando o seguinte código:
public class StrangeInt {
    public &lt;T extends Integer&gt; T soma1() {
        return 35;
    }

    public &lt;T extends Integer&gt; T soma2() {
        return new Integer(35);
    }
}
e o resultado é:
StrangeInt.java:3: incompatible types
found   : int
required: T
        return 35;
               ^
StrangeInt.java:7: incompatible types
found   : java.lang.Integer
required: T
        return new Integer(35);
               ^
2 errors
Posta aí o código completo que você usou. Talvez tenha algum outro detalhe que não vimos.
T

Só mais um detalhinho.
Alguém compilou com o compilador do Eclipse ? (Estou sem o Eclipse aqui).
Ele deve dar um diagnóstico diferente.
Se ele compilar um deles, ou não compilar nenhum deles, ou compilar ambos, estamos frente a algum caso que não está claramente definido na JLS, e isso deve ser reportado tanto à Sun quanto à Eclipse, para que digam o que está correto e concordem sobre o que fazer.

victorwss

thingol:
Só mais um detalhinho.
Alguém compilou com o compilador do Eclipse ? (Estou sem o Eclipse aqui).
Ele deve dar um diagnóstico diferente.
Se ele compilar um deles, ou não compilar nenhum deles, ou compilar ambos, estamos frente a algum caso que não está claramente definido na JLS, e isso deve ser reportado tanto à Sun quanto à Eclipse, para que digam o que está correto e concordem sobre o que fazer.

Eu fiz sem o eclipse. Com o eclipse compila e roda.
Realmente “this is a compiler bug.” No compilador do eclipse.

Marcelo_FS

victorwss, usei exatamente o mesmo código que você - acabei de copiar aqui e testar de novo.

thingol, eu compilei com o eclipse. Os erros podem ser vistos na imagem em anexo.


T

Bom… acho que é o caso de submeter o tal programa ao pessoal do Eclipse e ao pessoal da Sun, para que decidam qual é o comportamento esperado. Eu simplesmente não sei, só de olhar a JLS, qual seria o resultado esperado.

victorwss

thingol:
Bom… acho que é o caso de submeter o tal programa ao pessoal do Eclipse e ao pessoal da Sun, para que decidam qual é o comportamento esperado. Eu simplesmente não sei, só de olhar a JLS, qual seria o resultado esperado.

Acredito que é o eclipse que está errado, pois o método “manualboxed” falha nos dois.

Fernando_Generoso_da

compilando via linha de comando:

public class TesteGenerics {

	public <T extends Integer> T soma1() {
		return 35;
	}

	public <T extends Integer> T soma2() {
		return new Integer(35);
	}
}
C:\tmp>javac TesteGenerics.java
TesteGenerics.java:4: incompatible types
found   : int
required: T
                return 35;
                       ^
TesteGenerics.java:8: incompatible types
found   : java.lang.Integer
required: T
                return new Integer(35);
                       ^
2 errors

Fernando

victorwss

Criei um bug report:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=264843

L

Eu vou me limitar à explicação da função soma2(), que é um erro que faz mas sentido pra mim:

public <T extends Integer> T soma2() {
	return new Integer(35);
}

Dá erro porque, quando digo , estou querendo dizer: “meu retorno é um Integer ou qualquer subclasse de Integer”. É claro que isso é só teoria, na prática, por Integer ser final, não existe uma sublasse pra ela. Mas, se fizéssemos assim:

public <T extends NumberFormat> T soma2() {
	// TODO
}

Isso seria válido:

DecimalFormat df = soma2();
ChoiceFormat cf = soma2();

E não há casting porque tipo genérico está explicitamente dizendo que o objeto pode ser convertido para qualquer subclasse de NumberFormat.

Por ser possível atribuir a uma subclasse, isso não pode compilar:

public <T extends NumberFormat> T soma2() {
	return NumberFormat.getInstance(); // não compila!
}

Porque estou, no final das contas atribuindo uma superclasse a uma possível subclasse.

Fazendo isso, compila:

public <T extends NumberFormat> T soma2() {
	return (T) NumberFormat.getInstance(); // não compila!
}

Mas há um risco de ClassCastException durante a execução.

Agora, com relação a primeria função do exemplo do cara, não entendo porque compila. Pra mim, deveria dar erro também.

victorwss

O pessoal do eclipse está rápido! Não tem nem 4 horas que reportei o bug e já tem sugestão de patch!

https://bugs.eclipse.org/bugs/attachment.cgi?id=125658

:smiley:

EDIT (várias horas depois): Os desenvolvedores do eclipse consideraram o bug corrigido e a correção já estará disponível na próxima versão.
EDIT 2: Mas o bug foi reaberto porque o patch foi demonstrado ser incompleto.

Marcelo_FS

O pessoal lá é rápido… :stuck_out_tongue:

E

Então é isso ai pessoal, até que comprovem o contrário, é um bug mesmo, foi o que pensei, hehe.

Abraço e bora ajudar o java a crescer mais.

A

http://www.coderanch.com/t/431803/Programmer-Certification-SCJP/certification/possible-compile#1918551

Criado 12 de fevereiro de 2009
Ultima resposta 19 de fev. de 2009
Respostas 23
Participantes 11