2

(Note: I have searched multiple questions on SO in this similar domain, but I never encountered an answer specific to my idea).

Consider if I have a class or enum Foo where each instance has a Class<?> type field:

public enum Foo {
    A (Integer.class), B (Double.class), C (String.class);

    public final Class<?> type;

    Foo(Class<?> type) {
        this.type = type;
    }
}

Then I have a generic class Bar<V>:

public class Bar<V> {

    private V value;

    // default constructor
    public Bar() {}

    // getter
    public V getValue(){
        return value;
    }

    // setter
    public void setValue(V value){
        this.value = value;
    }
}

Is it possible to instantiate an instance of Bar with the type from the Class<?> type field of a given Foo without knowing the specific type of Foo.type? For instance, I would call this in either a static method, or some kind of factory method.

Edit:

To specify the function of Bar: Bar wraps around a value with a simple getter/setter, and has a consistent interface, but an unknown type. The benefit of my idea would be to create instances of Bar based off of an instance of Foo. For instance, use value of Foo.A.type (which is Integer.class) to instantiate a Bar<Integer> without knowing ahead of time that Foo.A.type has a value of Integer.class.

aaroncarsonart
  • 832
  • 7
  • 23

1 Answers1

1

Given the constructor in the Bar class, in order to instantiate a new Bar<V> object, you need an object of type V.

So, your problem translates into instantiating an object of type Class<V>. More specifically, assuming an existing Foo object and a getType() method in the Foo class, you would do something like:

Foo foo = ... // Existing Foo object
Class<V> type = foo.getType();
V value = instantiate(type); // TODO: Implement instatiate()
Bar<V> bar = new Bar(value);

The trick then is the implementation of the instantiate() method. If Class<V> has a no-args constructor, then you can just call

V value = type.newInstance();

Not all classes have a default constructor, though, so there is no generic solution for all cases.

PNS
  • 17,431
  • 26
  • 86
  • 131
  • The problem is just that `type` in `Foo` is declared as `Class>` and therefore requires a cast to `Class` which brings up a warning due to unchecked casting. Next, you should also add a diamond operator to the instantiation of `new Bar<>(value)`. You can also refactor the casting to the enum itself like `@SuppressWarnings("unchecked") public Class getType() { return (Class)type; }` and then just use somthing like `Class type = Foo.C.getType();` but the compiler will also accept `Class type = Foo.B.getType();` and then fail on runtime. – Roman Vottner Jun 02 '15 at 22:37
  • I apologize, my constructor example was misleading. The point isn't to initialize the value, but to create a new instance of Bar without explicitly knowing the type and instead using the type from Foo. I have edited my example. – aaroncarsonart Jun 02 '15 at 22:42
  • You need to be more specific about the usage of V, then. Is it a return value of any of the methods of the Bar class? Is it the type of any of its variables? – PNS Jun 02 '15 at 22:47
  • I wrote more explanation of the usage of `V`. `Bar` is a wrapper class, the point is to use instances of `Foo` to instantiate `Bar` where `V` is the same class as `Foo.A.type` or `Foo.B.type`, etc. Also, to do this without hardcoding in the class. (i.e., I don't know the type of `Foo.A` beforehand, but I know what it is via the `type` field. – aaroncarsonart Jun 02 '15 at 23:56
  • Instead of just doing `Bar = new Bar<>();`, I want to somehow pass the class referenced by a `type` field of an instance of `Foo` to the Bar I create. – aaroncarsonart Jun 02 '15 at 23:58
  • @AaronCarson if in a factory type pattern, the calling code will be passing a concrete `type` (either of `Integer`, `Double` or `String`)? Right? If so then to me it sounds like you may need to write yet another piece of code which compares the passed type (from the factory client) with the enum types in `Foo`. – Nirmal Jun 03 '15 at 02:54
  • @user3320018 Are you suggesting something like a switch case on`type` where I explicitly state each type (that feels convoluted to me)? I can't figure out an elegant solution. – aaroncarsonart Jun 03 '15 at 03:38
  • @AaronCarson I agree and I want to say that I keep hitting the wall when I think that client code is to provide one of the **concrete type** and then we want to use an (apparently?) **known type** from `Foo` to wrap it into a `Bar` instance. – Nirmal Jun 03 '15 at 03:44
  • I sm trying to design a factory method where I can pass in a `Foo` and get a `Bar` (Foo may have additional data associated). `Foo` will also be used as a key in a map. – aaroncarsonart Jun 03 '15 at 05:03