Reputation: 23814
I have the following example:
class bounds
{
private StringBuilder str = new StringBuilder();
public <Type> void add (Type value)
{
add_specific (value);
str.append (String.format("%n"));
}
private <Type extends Number> void add_specific (Type value)
{
str.append (value);
}
public String toString () { return str.toString(); }
public static void main (String[] args)
{
bounds test = new bounds();
test.add (new Integer (42));
System.out.print (test.toString());
}
}
When I try to compile it I get the following error:
bounds.java:7: error: method add_specific in class bounds cannot be applied to given types; add_specific (value); ^ required: Type#1 found: Type#2 reason: inferred type does not conform to declared bound(s) inferred: Type#2 bound(s): Number where Type#1,Type#2 are type-variables: Type#1 extends Number declared in method add_specific(Type#1) Type#2 extends Object declared in method add(Type#2) 1 error
This looks to me as if the original type of the argument passed to the add
method gets lost in the body of add
. How can I preserve the type so that the correct add_specific
method can be chosen?
Update
I have simplified my example, because I thought it would be easier to understand. But it seems to me that most people do not understand the reason why it contains a generic and a specific function. So I paste a more advanced example. Maybe this makes the reasons more obvious:
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
class bounds
{
private StringBuilder str = new StringBuilder();
public <Type> void add (Type value)
{
add_specific (value);
str.append (String.format("%n"));
}
private <Type extends Number> void add_specific (Type value)
{
str.append (value);
}
private void add_specific (String value)
{
str.append ('"');
for (int i = 0; i < value.length(); i++) {
char ch = value.charAt(i);
switch (ch) {
case '\\': str.append ("\\\\"); break;
case '"': str.append ("\\\""); break;
default: str.append (ch);
}
}
str.append ('"');
}
private static DateFormat iso8601
= new SimpleDateFormat("'\"'yyyy-MM-dd'T'HH:mm:ssZ'\"'");
private void add_specific (Date date)
{
str.append (iso8601.format(date));
}
public String toString ()
{
return str.toString();
}
public static void main (String[] args)
{
bounds test = new bounds();
test.add (new Integer (42));
test.add ("42");
test.add (new Date());
System.out.print (test.toString());
}
}
I have a generic function called add
. This generic function does something generic and calls a specific function to do something specific. The problem is, that the type to select the specific function gets lost in the generic function. And the question is how to fix this? How do I have to write the generic function so that it is still possible to select the right specific function in the body of the generic function?
Upvotes: 0
Views: 136
Reputation: 5930
Get rid of the add and add_specific methods, and just overload the add method. Beware, however, that the choice of which method to make is done statically at compile time, NOT dynamically at runtime.
Like Jon said, what you are trying to do won't work. If you want all client code to look the same, then do something like this; although in Effective Java, Bloch suggests you avoid this kind of confusing API.
class Bounds {
private StringBuilder str = new StringBuilder();
private void appendNewline() {
str.append (String.format("%n"));
}
public void add (Number value) {
str.append (value);
appendNewline();
}
public void add (String value) {
str.append ('"');
for (int i = 0; i < value.length(); i++) {
char ch = value.charAt(i);
switch (ch) {
case '\\': str.append ("\\\\"); break;
case '"': str.append ("\\\""); break;
default: str.append (ch);
}
}
str.append ('"');
appendNewline();
}
private static DateFormat iso8601
= new SimpleDateFormat("'\"'yyyy-MM-dd'T'HH:mm:ssZ'\"'");
public void add (Date date) {
str.append (iso8601.format(date));
appendNewline();
}
public String toString () {
return str.toString(); }
public static void main (String[] args) {
bounds test = new bounds();
test.add (new Integer (42));
test.add ("42");
test.add (new Date());
System.out.print (test.toString()); }
}
Upvotes: 0
Reputation: 1500155
This looks to me as if the original type of the argument passed to the add method gets lost in the body of
add
.
Well, type erasure means that Type
won't be known at execution time, but that's not the immediate reason you're getting a compile-time error. You can call add
with any type - whereas you can only call add_specific
with a type which is compatible with Number
. So for example, consider:
// TODO: Fix your naming to meet Java naming conventions
bounds b = new bounds();
b.<String>add("foo");
How would you expect that to call add_specific
? String
doesn't extend Number
.
(As an aside, it's also a really bad idea to name a type parameter Type
- it's too easy to confuse it with java.lang.reflect.Type
.)
Options:
extends Number
bound to Type
in add
Type
in add_specific
EDIT: Okay, so it sounds like you'd only given us half the picture - you're expecting overload resolution to be performed at execution time based on Type
. That's not going to work, for two reasons:
Class<Type>
.Upvotes: 3
Reputation: 1785
the compiler is screaming because reference value
in your add
method is not necessarily a Number
to solve this :
change add
method to :
public <Type extends Number> void add (Type value)
{
}
or add :
public <Type> void add (Type value)
{
if (value instanceof Number){
add_specific ((Number)value);
str.append (String.format("%n"));
}
}
Upvotes: 0
Reputation: 88707
The problem is this part:
public <Type> void add (Type value)
{
add_specific (value);
...
}
add_specific
requires the value to be of a type that extends Number
but add
doesn't require/ensure that. Hence the error.
To fix it, you'd need to change add
to use <Type extends Number>
, but I doubt that's what you want. It seems like a design error to me: add_specific
should call the more generic looking add
and not the other way round.
Btw, as John Skeet already said, please adhere to the coding conventions, which will make it easer to spot bugs and read your code.
Upvotes: 1