Alguém SABE?

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 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…

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

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.

[quote=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.[/quote]

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

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.

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:[quote] 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.[/quote]
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.

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

[quote=estundidher]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[/quote]

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.

Qual é a versão do teu compilador?

[quote=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.[/quote]

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

[quote=MarceloS][quote=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.[/quote]

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

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

Eclipse Platform
Version: 3.4.1
Build id: M20080911-1700
[/code][/quote]

O meu também é 1.6.0_10-b33.
Estou usando o seguinte código:[code]public class StrangeInt {
public <T extends Integer> T soma1() {
return 35;
}

public &lt;T extends Integer&gt; T soma2() {
    return new Integer(35);
}

}[/code]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.

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.

[quote=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.
[/quote]
Eu fiz sem o eclipse. Com o eclipse compila e roda.
Realmente “this is a compiler bug.” No compilador do eclipse.

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.


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.

[quote=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.
[/quote]

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

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

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

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.