I have a class meant for holding numeric values that could be changed by the user through the GUI. The GUI has a TextField (of JavaFX) where they could write the desirable value.
Since I wanted this class to be flexible I made it using generics like this:
public class ConfigurableNumericField <T extends Number> {
private T value;
//...
public void setValue(T value){
this.value = value;
}
}
And I create an object like this:
ConfigurableNumericField <Integer> foo = new ConfigurableNumericField <> ( /*...*/ );
The problem is that the TextField returns a CharacterSequence (that could be casted to String). BUT even if all classes that inherit from Number have the valueOf method, Number does not have it.
So when I try to setValue() the String from the TextField to the class itself. I get a java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number.
How can I do this?
When generics you can make things so generic that they are not meaningful anymore.
In your case you need a setValue which will take a String so you can convert it to the appropriate type. The problem with this is there is no way to do this genericly as the generic type of foo is not available at runtime.
I would have two subclasses, one for integers which uses a Long and another which uses a Double or BigDecimal. This will support most of the Number types you are likely to need.
You really can't. All of the possible approaches end up involving special cases for each number type.
The reason this may be problematic is that future / custom Number implementations may not provide this method, since it's not part of the contract.
Here are two options that comes to mind:
Use reflection to invoke the setValue method.
Use a couple of instanceof checks and casts to cover the Numbers you need to support.
Related
I am trying to add a method to an existing class BinaryTree<T> to simple add the values of all the elements in the tree. The problem is that being the class a generic one, not all the types that can be send at the time of creating a tree can be added. I mean, for example It wouldn't make any sense to try to add the values of a class people.
So my question is, how do I make a method public T addAllElements() that only allows T to be an specific kind of type, in this case, only the types that is possible to add it's value, like Integer, Float, Long, etc? I guess there have to be some kind of numerical interface or maybe some kind of declaration provided by the language to do something like that.
By the way, it seems to be a solution without having to create a child class, in case that it could help in anything, because I was asked to solve a similar problem and the instructions says that the method have to be in the same class.
Trying to be more clear, I'll ask another question , because I think that both of them have the same answer.
I found that the method sort() in java.util.Arrays class can be used by a class if the class implements the interface Comparable<T>. So if I hava a class, lets say
public class People {
implements Comparable<People>
private String name;
public int compareTo(People o) {
...
}
...
}
This class can be sorted with the sort() method from the Arrays class, but if the class dind't implement the Comparable<T> interface it couldn't. So what is making this restriction in the Arrays class definition? Is it what I need to solve the first problem I asked?
So my question is, how do I make a method publicTaddAllElements() that only allows T to be an specific kind of type, in this case, only the types that is possible to add it's value, like int, float, long, etc? I guess there have to be some kind of numerical interface or maybe some kind of declaration provided by the language to do something like that.
You're looking for Number.
So your declaration would look something like this, if the class is generic:
public BinaryTree<T extends Number> {
// ...
}
or if you want to make just the method generic:
public <T extends Number> T addAllElements() {
// ...
}
That said, for better or for worse Number does not define arithmetic operations in terms of methods. To my knowledge there is no such built-in type which does.
Do note that the types you listed are all primitives, which mean they're not compatible with generics at all. Subtypes of Number (and types that can be used with generics) will all be wrapper types: Integer, Float, Long, etc.
Your examples are related, but they're not the same.
To address the latter concern first, the reason that Arrays.sort with a specific signature requires that things be Comparable is because it needs to sort them based on that natural ordering. There is another signature that you could provide to the method which allows you to pass a custom Comparator to it, to sort on whatever other property of the class you liked.
To your main concern, you need to have an upper-bound generic, specifically one of type T extends Number. The reason for this is that Number is the parent class to all of the numeric wrapper classes, as well as BigDecimal and BigInteger.
There's two things you'd want to be sure of before you did this:
Your generic type was bound at the class level. Since we're dealing with a tree, it makes no sense to have non-homogeneous data throughout.
You did a math operation according to a specific data type (int, long, or double).
You would then declare your method(s) as such:
public int addAsInteger() {}
public double addAsDouble() {}
public long addAsLong() {}
You'd make use of Number's methods: intValue, longValue and doubleValue for your respective methods.
You wouldn't be able to simply return T since you can't guarantee what kind of Number you're getting back, or what T is specifically bound to (it can't be Number since it's an abstract class, so it is a non-inclusive upper bound).
So I have to accept a generic type T, which will be a wrapper class for one of the numeric primitives, and do some arithmetic with it. I thought this would be trivial because of autoboxing and unboxing:
T newval = val1*val2;
(Where val1 and val2 are already variables of type T with appropriate values in them.)
But it turns out that Java won't unbox values if it doesn't know the type explicitly at compile time. I also thought that I could just use the multiply method that each of the Number subclasses (that I intend to use) have within them. So I declared my class with:
public class SomeClass<T extends Number> {
// ...
}
and then:
T newval = val1.multiiply(val2);
But that doesn't work because I guess not all subclass' of Number are required (Why don't they use an interface for this?) to have that method (yet all the ones that I want to use DO.)
I've seen some similar questions but they all resulted in OP being told to just not use generics, yet I am required to use generics for the work I'm doing, otherwise the entire thing is worthless. Can anybody think of a solution that will work for me?
EDIT:
Okay so he got back to me and clarified what was meant, it's different enough that my question is no longer relevant to what i'm doing. Thanks guys.
The various arithmetic operators can only be applied to values of types that are convertible to primitive types. There is no way to express that requirement with generics. Therefore generics are not suited for this task.
For generics methods, instead provide overloads for the numeric primitive types.
For generic classes, provide subclasses that use a specific numeric type.
class NumericCalculator<T> {
public void calculate(T one, T two) {
T result = one * two; // compiler error
}
}
class LongCalculator extends NumericCalculator<Long> {
public void calculate(Long one, Long two) {
Long result = one * two; // yes
}
}
The implementation that uses the operators will have to be in the subclasses which know the actual type.
I have seen declarations, interfaces and classes that go TYPE<CLASS>
What does this do/mean?
Without evidence, I believe you're talking about Java's Generics support...
Generics allow you to abstract over types
Before Java 5 it was difficult to provide classes that were capable of supporting multiple different types of Objects without having to code for each specific situation, so it was common for people to pass Object instead.
This leads to many difficult choices to make at runtime, you'd have to do a runtime check to see if it was possible to cast a given Object to a usable type...for example
List myIntList = new LinkedList(); // 1
myIntList.add(new Integer(0)); // 2
Integer x = (Integer) myIntList.iterator().next(); // 3
Now, this is reasonably obvious, but if you were passed just a List, you'd have to check each and every element in the list for correctness...
But now, we can do this...
List<Integer> myIntList = new LinkedList<Integer>(); // 1'
myIntList.add(new Integer(0)); // 2'
Integer x = myIntList.iterator().next(); // 3'
This is a contract that basically says "This list only contains Integer type's of objects".
With generics you can construct a single class that is capable of handling multiple different data types or a family of data types (ie constraint the parameter so that it must be extended from a particular parent type).
Iterator<? extends Number> itNum;
Basically says, this will contain objects that inherit from Number, include Integer, Long, Double, Float...
Often in method and class decelerations you will see something similar to...
public class MyGenericClass<T> {...}
or
public class MyGenericClass<T extends MyBaseObject> {...}
This allows you to refer to T as if it were a concrete object type, for example...
public class MyGenericClass<T extends MyBaseObject> {
private T value;
public MyGenericClass(T value) {
this.value = value;
}
}
This allows the compiler (and JVM) to essentially "replace" the marker T with a concert type (okay, it's a little more complicated then that, but that's the magic)...
This allows to do things like...
... new MyGenericClass<MySuperObject>(new MySuperObject());
... new MyGenericClass<MySuperSuperObject>(new MySuperSuperObject());
And know that it will only ever accept the type of object I specify...
Have a read through the link in the first paragraph, I'm sure it can do more justice then I can ;)
public class Grid<E> {
That's how you define a generic class in Java.Grid is the class and E is a formal type parameter.
If you are really interested in learning about it, you will find a very good reference here - Java Generics FAQs - Frequently Asked Questions
that is generic types check it here.
Simple examples would be
List<String>
Map<Integer, String>
It's unclear what you are asking without looking at what exactly you are seeing. But it's likely you are seeing Generics in Java. Learn more about it here
The idea is basically to make stronger type-safety in Java. So, a declaration like List<Integer> intList means intList has Integers in it. And if you try to put a, say, String -- it will throw compilation error.
This thing is troubling me for a while now. I have asked questions before, but probably with a bad phrasing and an example that was too abstract. So it wasn't clear what I was actually asking. I'll try again. And please don't jump to conclusions. I expect that the question is not easy at all to answer!
why can't I have an enum with generic type parameters in Java?
The question is not about why it's not possible, syntactically. I know it's just not supported. The question is: why did the JSR people "forget" or "omit" this very useful feature? I can't imagine a compiler-related reason, why it wouldn't be feasible.
Here's what I would love to do. This is possible in Java. It's the Java 1.4 way to create typesafe enums:
// A model class for SQL data types and their mapping to Java types
public class DataType<T> implements Serializable, Comparable<DataType<T>> {
private final String name;
private final Class<T> type;
public static final DataType<Integer> INT = new DataType<Integer>("int", Integer.class);
public static final DataType<Integer> INT4 = new DataType<Integer>("int4", Integer.class);
public static final DataType<Integer> INTEGER = new DataType<Integer>("integer", Integer.class);
public static final DataType<Long> BIGINT = new DataType<Long> ("bigint", Long.class);
private DataType(String name, Class<T> type) {
this.name = name;
this.type = type;
}
// Returns T. I find this often very useful!
public T parse(String string) throws Exception {
// [...]
}
// Check this out. Advanced generics:
public T[] parseArray(String string) throws Exception {
// [...]
}
// Even more advanced:
public DataType<T[]> getArrayType() {
// [...]
}
// [ ... more methods ... ]
}
And then, you could use <T> in many other places
public class Utility {
// Generic methods...
public static <T> T doStuff(DataType<T> type) {
// [...]
}
}
But these things are not possible with an enum:
// This can't be done
public enum DataType<T> {
// Neither can this...
INT<Integer>("int", Integer.class),
INT4<Integer>("int4", Integer.class),
// [...]
}
Now, as I said. I know these things have been designed exactly that way. enum is syntactic sugar. So are generics. Actually, the compiler does all the work and transforms enums into subclasses of java.lang.Enum and generics into casts and synthetic methods.
but why can't the compiler go further and allow for generic enums??
EDIT:
This is what I would expect as compiler-generated Java code:
public class DataType<T> extends Enum<DataType<?>> {
// [...]
}
I'm going to guess a bit and say that it is because of covariance issues on the type parameter of the Enum class itself, which is defined as Enum<E extends Enum<E>>, although it is a bit much to investigate all the corner cases of that.
Besides that, a primary use case of enums is with things like EnumSet and valueOf where you have a collection of things with different generic parameters and get the value from a string, all of which would not support or worse the generic parameter on the enum itself.
I know I'm always in a world of pain when I try to get that fancy with Generics, and I imagine the language designers peeked at that abyss and decided to not go there, especially since the features were developed concurrently, which would mean even more uncertainty for the Enum side of things.
Or put another way, it would have all the problems of Class<T> in dealing with classes which themselves have generic parameters, and you would have to do a lot of casting and dealing with raw types. Not truly something that the language designers felt was worth it for the type of use case you are looking at.
EDIT: In response to the comments (and Tom - a downvote?), nested generic parameter makes all kinds of bad things happen. Enum implements Comparable. That simply would not work to compare two arbitrary elements of the enum in client code if generics were in play. Once you deal with a Generic parameter of a Generic parameter, you end up with all kinds of bounds problems and headaches. It is hard to design a class that handles it well. In the case of comparable, I could not figure out a way to make it work to compare two arbitrary members of an enum without reverting to raw types and getting a compiler warning. Could you?
Actually the above is embarrassingly wrong, as I was using the DataType in the question as my template for thinking about this, but in fact an Enum would have a subclass, so that isn't quite right.
However, I stand by the gist of my answer. Tom brought up EnumSet.complementOf and of course we still have valueOf that produces problems, and to the degree that the design of Enum could have worked, we have to realize that that is a 20/20 hindsight thing. Enum was being designed concurrently with generics and didn't have the benefit of validating all such corner cases. Especially considering that the use case for an Enum with a generic parameter is rather limited. (But then again, so is the use case for EnumSet).
I don't think it is impossible to have generified enum. If you could hack into compiler, you can have a subclass of Enum that is generic, and the class file of your generic enum wouldn't cause problems.
But in the end, enum is pretty much a syntax sugar. In C, C++, C#, enums are basically alias for int constants. Java gives it more power, but it is still supposed to represent simple items.
Somewhere people have to draw the line. Just because a class has enumerated instances, doesn't mean it must be an enum. If it is sophisticated enough in other areas, it deserves to be a regular class.
In your case, there is not much advantage to make DataType an enum. You can use enum in switch-case, that's about it, big deal. The non-enum verion of DataType works just fine.
This is how I think of it -
Regular classes have instances. You create a new instance of a class use it for some purpose and then dispose it. For example List<String> is a list of strings. I can do what ever I want to do with strings and then when I am done I can later do the same functionality with integers.
To me enumerators are not types that you create instances of. Its same thing as a singleton. So I can see why JAVA wouldn't allow generics for Enums because you really can't create a new instance of type Enum to use temporary like you do with classes. Enums are supposed to be static and only have one instance globally. To me, it wouldn't make sense to allow generics for a class that only has one instance globally.
I hope this helps.
I think that the reason why you wish to parameterize the enum with <T> boils down to being able to have different method signatures for the various constants of the enum.
In your example, the signature (type of parameters and return type) for parse would be:
for Datatype.INT: int parse(String)
for Datatype.VARCHAR: String parse(String)
and so on
So how would the compiler be able to typecheck something like:
Datatype type = ...
...
int x = type.parse("45");
???
To apply static typing and typechecking to this kind of expression, the signature of the method must be the same for all the instances. However, in the end you suggest to have different method signatures for different instances... That's why it's not possible to do it in Java.
public enum GenericEnum<T> {
SIMPLE, COMPLEX;
public T parse(String s) {
return T.parse(s);
}
}
public void doSomething() {
GenericEnum<Long> longGE = GenericEnum<Long>.SIMPLE;
GenericEnum<Integer> intGE = GenericEnum<Integer>.SIMPLE;
List<Long> longList = new LinkedList<Long>();
List<Integer> intList = new LinkedList<Integer>();
assert(longGE == intGE); // 16
assert(stringList.equals(intList)); // 17
Object x = longGE.parse("1"); // 19
}
The asserts at line 16 and 17 are both true. The generic types are not available at run time.
One of the advantages of an enum is that you can use == to compare them. The assert at line 16 will evaluate to true.
At line 19 we run into a problem though. longGE and intGE are the same object (as the assert at line 16 shows.) What will be returned by the parse("1")? The generic type information is not available at run time. So there would be no way to determine T for the parse method at run time.
Enums are basically static, they only exist once. And it doesn't make sense to apply generic typing to static types.
I hope this helps.
Note - this is not meant to be working code. It is using the syntax suggested in the original question.
I want to create a method that compares a number but can have an input that is any of the subclasses of Number.
I have looked at doing this in the following manner...
public static <T extends Number> void evaluate(T inputNumber) {
if (inputNumber >= x) {
...
}
}
I need to get the actual primative before I can perform the comparison, the Number class has methods to retrieve this for each primative but I want a clean way of selecting the correct one.
Is this possible?
Cheers
The Number API doesn't offer a clean way to get the value; you have have to use instanceof.
One solution is to "fold" the values into two types: long and double. That way, you can use this code:
if( inputNumber instanceof Float || inputNumber instanceof Double ) {
double val = inputNumber.doubleValue();
...
} else {
long val = inputNumber.longValue();
...
}
Note that this only works for the standard number types but Number is also implemented by a lot of other types (AtomicInteger, BigDecimal).
If you want to support all types, a trick is to use BigDecimal:
BigDecimal value = new BigDecimal( inputNumber.toString() );
That should always work and give you the most exact result.
Unfortunately there is no way to get the primitive type from the wrapper type without resorting to if/else blocks.
The problem is that it just wouldn't be possible to implement such a method in a generic way. Here are some seemingly possible approaches which one could expect to find in the Number class:
public abstract X getPrimitiveValue();
This would be nice, wouldn't it? But it's impossible. There is no possible X that could be an abstraction over int, float, double etc.
public abstract Class<?> getCorrespondingPrimitiveClass();
This won't help either, because there is no way to instantiate primitive classes.
So the only thing you can do that is common to all types is to use the longValue() or doubleValue() methods, but either way you are losing information if you're dealing with the wrong type.
So no: the java number hierarchy is just not suited to solve such problems in a generic way.
Methods with <T extends Number> are always trouble, since you can't really do anything on a Number (all the operators are defined for the children). You would need to either do a ton of instanceof for each child of Number and treat that case by casting to the subtype. Or (better I think - that's the way Sun does it) is to just have a method for each child type, possibly taking advantage of boxing/unboxing for operators like +,-,> etc. where that is possible (all wrappers, not for BigInteger/BigDecimal or any custom types).
If it's really just about comparing the argument to another value of the same type parameter then you could do the following (just adding in T x for simplicity)
public static <T extends Number & Comparable<? super Number>> int evaluate(T inputNumber, T x) {
if (inputNumber.compareTo(x) > 0) { ... }
}
in this case you can use an ordinary method without generics
There's always an option to work with unknown data with pattern interfaces. That's how sorts works with Comparator interface. You should create and add as method parameter functional interface Evaluator with evaluate(T number) method and determine evaluation logic out of method. You can also create some examples from helper classes, like Evaluators::IntegerEvaluator which will work for Integers and suggest them to the client.
Sry for my eng