Java Generics with Static Factory methods - java

I'm trying to create a Variable class that can represent either an Integer or Double value using generics.
Below is the code that I have tried. Because of erasure I use an enum to store the intended type of the Variable and then try and use this to initialise the value to the correct type.
public class Variable<T> {
private enum Type {INTEGER, DOUBLE};
private Type type;
private T value;
public static Variable<Integer> createAsInteger() {
return new Variable<Integer>(Type.INTEGER);
}
public static Variable<Double> createAsDouble() {
return new Variable<Double>(Type.DOUBLE);
}
private Variable(Type type) {
this.type = type;
if(type == Type.INTEGER) {
value = new Integer(0);
} else {
value = new Double(0.0);
}
}
public static void main(String[] args) {
Variable.createAsInteger();
Variable.createAsDouble();
}
}
However when I compile it I get the following message...
error: incompatible types: Integer cannot be converted to T
value = new Integer(0);
and likewise for the Double.
Can anyone explain why this is happening and if there is a way round this without having to write two separate classes, one for Integer and one for Double?
Edit
Thanks for all your answers...based on them I now realise there are better ways of doing this. However I'm trying to get my head round why this approach isn't working so that I don't make the same mistake in the future.
When I define my class as public class Variable<T extends Number> as suggested, I still get the same error.

Your architecture seems to defile the concept of generics.
The simplest way would be to have an upper bound in your type parameter:
class Variable<T extends Number> {...}
Then you can have a generic factory method creating a Variable<X> based on your required class:
static <X extends Number>Variable<X> create() {
return new Variable<X>();
}
You can then invoke it as:
Variable.<Integer>create(); // returns an instance of `Variable<Integer>`
This will not limit to Integer and Double, but rather any Number.
If you have to, you can limit those choices by performing the following:
Add a parameter to your create method: create(Class<X> clazz)
Check the value of your clazz argument within the method's body:
if (!clazz.equals(Integer.class) && !clazz.equals(Double.class)) {
// TODO complain
}
Otherwise, you can ensure you use a private constructor and provide static createAs... non-generic methods such as createAsInteger etc., that would return a new Variable<Integer> etc.

The problem here is that T can be anything. What if T was for instance String, your code would amount to:
String value = new Integer(0);
You could lay out your factory methods like this:
public static Variable<Integer> createAsInteger() {
return new Variable<>(new Integer(0), Type.INTEGER);
}
Where you have a constructor like:
private Variable(T value, Type type) {
this.value = value;
this.type = type;
}

You get the error because you are typizing a method inside a generic class. You can't define some inside the T generic class.
By the way you are mistaking the design pattern.
You have to design a generic class for Variable, also the constructor must have T as argument type.
In an other class you implement the factory with the createInteger and the createDouble methods.

You can make your class inherit from Numbers and use type checking to invoke appropriate method for Integer or Double.
public class Variable<T extends Number> {
public static Variable<T extends Number> Variable<T> create(Variable<T> var){
if (var instanceOf Integer){
// Take appropriate action
}
else if (var instanceOf Double){
// Take appropriate action
}
}
}
By this, there is no peculiar need of maintaining a separate enum for Types.

Related

Java generics - assigning Object to a typed value

I have the below setup.
interface Initializable<T> {
T getValue();
void setValue(T value);
}
class BaseClass {
private final String code; // has getter and setter
///
}
class StringValue extends BaseClass implements Initializable<String> {
private final String value;
#Override
public void setValue(String value) {
this.value = value;
}
#Override
public String getValue() {
return value;
}
}
class IntValue extends BaseClass implements Initializable<Integer> {
private final Integer value;
#Override
public void setValue(Integer value) {
this.value = value;
}
#Override
public Integer getValue() {
return value;
}
}
class NotInitializable extends BaseClass {
/////
}
I have a list of BaseClass instances and I would like to set value field for Initializable instances as below. I would like to be able to do this without the Raw use. I can't seem to be able to make that work. Any help is appreciated. TIA
List<BaseClass> fields; // populated
Map<String, Object> vauleByCode; // populated
for (final BaseClass bc : fields) {
if (bc instanceof Initializable) {
// I would like to set this value of type Object to the value field in Initializable
final Object value = valueByCode.get(bc.getCode());
// I would not like to use Raw variable here (i. e without the generic ?)
Initializable<?> init = (Initializable<?>) bc;
init.setValue(value) // set value here
}
}
Your objective, I have to presume, is to detect type errors, where the value found in valueByCode doesn't match the generic type of your Initializable instance. For example, you want to make sure you don't pass a String to setValue() on an object someone references as Initializable<Integer>, because that will cause a ClassCastException at some distant time and place, at a call site that doesn't have an explicit cast. That would be a bug in this assignment, not in the caller; the assignment should have failed, not silently ignored the type mismatch.
If classes implement Initializable as shown in the question, the type parameter is not erased, and can be used at runtime to check types. That is, when you define a class like class StringValue extends BaseClass implements Initializable<String>, the String is compiled into the class, and can be used to enforce type safety at runtime.
You could use reflection (via ParameterizedType) to find the generic type parameter of the Initializable implementation, but because those implementations could vary a lot, handling all the possibilities would make that code relatively complex.
Instead, use the raw type (exactly as you said you don't want to do in the question). If there is a type mismatch, a ClassCastException will be raised when you call setValue(). This preserves generic type safety so that anyone who calls getValue() via a generic method will not encounter a ClassCastException even though they aren't downcasting the result.

Java enum method return generic type supplied in constructor?

I would like to have a generic return type for an enum method getValue(). The returned type should be the same as the one supplied in the constructor of the enum.
public enum ParameterType
{
NUMBER(int.class),
TEXT(String.class);
private Class<?> classType;
ParameterType(Class<?> _clazz)
{
classType = _clazz;
}
public <T> T getValue()
{
String a = "i am a text";
int b = 42;
return classType.cast(a);
//return classType.cast(b);
}
}
However, in this case the error is "cannot convert from capture #3 ? to T". Also, it is not possible to provide a generic "X" type on the enum itself which could be used for return types in case of classes.
How can I solve this problem?
Do forget about casting. Do redefine ‘getValue()’ for each enum constants.
You can't do this with an enum, because all values in an enum have the same type.
To do this, you have to basically build the "enum" by hand:
public final class ParameterType<T>
{
public static final ParameterType<Integer> NUMBER = new ParameterType<>(42);
public static final ParameterType<String> TEXT = new ParameterType<>("I am a text");
private ParameterType(T value) {
this.value = value;
}
public T getValue() { return value; }
}
An important point is to make the constructor private, so it can't be invoked outside the class. This makes it a bit like an enum, in that the instances you define are the only instances.

Is there any hack to know the actual concrete class of the generic of an instance at runtime? [duplicate]

This question already has answers here:
Get generic type of class at runtime
(30 answers)
Closed 7 years ago.
I'd like to find a hack to infer the actual generic instance of another instance's var in runtime, without:
Changing my needed method signature (adding the helper parameter Class<T>, the obvious way)
Having to instanceof all possible subtypes in a hardcoded way
MyInterface<? extends Number> myInterface = whateverReturnsWildcardDoubleInterface();
Class<?> type = inferInstanceType(myInterface);
assert type == Double.class;
/** This is the method that represents the code I am looking for with the conrete signature**/
public <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
return T.class; //Concrete T (can or cannot be the very Number)
}
Ideally, it should return Double when T is particular subtype Integer,Double.. and Number when T is Number
I checked reflection, several "TypeResolver"/"GenericResolver" libs (as the one in Spring or others in Github), but I cannot fin a way to hack it.
EDIT: I reached the conclusion that he only feasible way to do that would be some kind of very complex reflection through the stack trace up to the acutal line that passes the type in the very instantiation
EDIT2: I know it's stupid... but I solved it by simply adding a T getT() method to my interface, so I could return myInterface.getT().getClass()
Disclaimer: This solution is provided as a hack tailored to my understanding of your setup, i.e. one generic interface with a single type parameter, multiple classes, which are not themselves generic, directly implementing this one interface alone, and implementing no other generic interfaces, directly or indirectly.
Assuming that all of the above is true, there is a relatively straightforward way of hacking a solution: calling getClass().getGenericInterfaces() returns a Type object that provides the actual type with which your generic interface has been instantiated.
interface MyInterface<T extends Number> {
T getVal();
}
class DoubleImpl implements MyInterface<Double> {
public Double getVal() {return 42.42; }
}
...
public static void main (String[] args) throws java.lang.Exception {
MyInterface<? extends Number> x = new DoubleImpl();
Type[] ifs = x.getClass().getGenericInterfaces();
System.out.println(ifs.length);
for (Type c : ifs) {
System.out.println(c);
Type[] tps = ((ParameterizedType)c).getActualTypeArguments();
for (Object tp : tps) {
System.out.println("===="+tp); // <<== This produces class java.lang.Double
}
}
}
Demo.
As assylias pointed out, Java's erasure will make that information unavailable at runtime - and thus a need for a hack.
On the assumption that myInterface has a getter for T, as in, MyInterface.getValue():T (or the hack would be to add it) you could do something like this (ignoring the possibility that getValue() could return null):
public <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
return myInterface.getValue().getClass()
}
Below is the full implementation
public class Q34271256 {
public static interface MyInterface<T> {
T getValue();
}
public static class MyDoubleClass implements MyInterface<Double> {
private final Double value;
public MyDoubleClass(Double value) {
this.value = value;
}
#Override
public Double getValue() {
return value;
}
}
public static class MyIntegerClass implements MyInterface<Integer> {
private final Integer value;
public MyIntegerClass(Integer value) {
this.value = value;
}
#Override
public Integer getValue() {
return value;
}
}
#SuppressWarnings("unchecked")
public static <T extends Number> Class<T> inferInstanceType(MyInterface<T> myInterface){
Number value = myInterface.getValue();
if (value == null) return null;
return (Class<T>)value.getClass();
}
public static void main(String...args) {
List<MyInterface<? extends Number>> list = Arrays.asList(
new MyDoubleClass(1.1),
new MyIntegerClass(5)
);
for (MyInterface<? extends Number> myInterface : list) {
Class<?> type = inferInstanceType(myInterface);
System.out.printf("%s inferred type is %s\n",
myInterface.getClass().getName(),
type.getName());
}
}
}
And the output should look something like this:
MyDoubleClass inferred type is java.lang.Double
MyIntegerClass inferred type is java.lang.Integer

How to create Integer object within a class with Generic Integer

When I tried the following codes, I get an error:
unexpected type
required: class
found: type parameter Integer where Integer is a type-variable
class myClass <Integer>
{
public void myMethod()
{
Integer q = new Integer(5); //Not allowed
}
}
However, the following codes are allowed
class myClass
{
public void myMethod()
{
Integer q = new Integer(5); //Allowed
}
}
Can someone explain why am I not allowed to create Integer object within the class anymore when I declare the class with generic Integer ?
Que: Is it still possible and how to create Integer objects within the class in this case?
You declared Integer to be the generic type parameter, which hides the fact that the class Integer was in scope. You can do one of several things to get around this.
Choose a different name for the generic type parameter, e.g. T.
class myClass<T>
Or, fully-qualify the references to the class Integer.
java.lang.Integer q = new java.lang.Integer(5);
I think you have a wrong idea of what a parametrizable class is.
To declare a parametrizable class:
class myClass <T>
{
T myGenericVariable;
Integer i;
public void myMethod()
{
this.i = new Integer(5);
}
}
How to use it:
myClass mc = new myClass<String>();//String or whatever you want

Get "real" class of generic type

How can I get the "real" class of a generic type?
For Example:
public class MyClass<T> {
public void method(){
//something
System.out.println(T.class) //causes a compile error, I wont the class name
//something
}
}
If T = Integer
Output:
java.lang.Integer
If T = String
Output:
java.lang.String
Thanks
If you have a instance variable of type T in your class, and it happens to be set, then you could print the class of that variable.
public class Test<T> {
T var;
public static void main(String[] args) {
Test<Integer> a = new Test<Integer>();
System.out.println(a.boo());
a.setVar(new Integer(10));
System.out.println(a.boo());
}
public String boo() {
if (var == null) {
return "Don't know yet";
}
return var.getClass().getSimpleName();
}
public void setVar(T var) {
this.var = var;
}
public T getVar() {
return var;
}
}
You can't. The information is stripped from the code at compile time, a process that is known as type erasure. For more, please look here: Type Erasure
edit: sorry my bad, the information is not loaded at run time.
As others have explained, you cannot do it in that fashion but this is how it's usually achieved in java.
public class MyClass<T> {
public void method(Class<T> clazz) {
// something
System.out.println(clazz.getName());
// something
}
}
and you use it like this
new MyClass<String>().method(String.class);
In the case of your situation, you can't. However, you might be able to use Super Type Tokens for this type of thing: http://gafter.blogspot.com/2006/12/super-type-tokens.html
An example implementation of these is the TypeReference class of the Jackson json processing library.
This is advanced stuff and probably more than you wanted to know ;-)
Note that approaches relying on 'getClass()' on an instance received with a generic type will get the actual type of that object, which is not necessarily the generic type - which would be the type by which the caller knew the instance.
For example, consider the case where the caller handles an object by an interface; when passing to generic constructs, the generic type will be the interface, not the instance's actual class.
Consider the following example "Pair" class, which allows two object references to be returned through a POJO:
public class Pair<U,V>
{
public final U first;
public final V second;
public static <U,V> Pair<U,V> of (U first, V second)
{
return new Pair<U,V> (first, second);
}
protected Pair (U first, V second)
{
this.first = first;
this.second = second;
}
}
We were considering how to modify the 'Pair.of()' factory function to return a Comparable Pair derived class, if U and V were both Comparable. However, while we can tell whether 'first' and 'second' are comparable using instanceof, we don't know that 'U' and 'V' are themselves comparable.
For this to work, the exact type of Pair returned by Pair.of() must depend on the generic types, not the actual argument types.

Categories