0

I would like to create an instance of a generic type used as a function parameter. Suppose the following classes with a different representation of a point

class Point1 {
      double x, y;
      public Point1 (double x_, double y_) {x=x_; y = y_;}
}

class Point2 {
      double lat, lon;
      public Point2 (double lat_, double lon_) {lat = lat_; lon = lon_;}
}

There is a class creating an instance of the generic type based on the reflection

public class GType<T> {
    private Class<T> UType; 
    public GType(Class<T> gt) {UType = gt;}

    public T get(double p1, double p2){ 
            try             {
                    Class[] constrArg = new Class[2];
                    constrArg[0] = double.class;
                    constrArg[1] = double.class;
                    return UType.getDeclaredConstructor(constrArg).newInstance(p1, p2);
            } 

            catch (Exception e) {
                    e.printStackTrace();
                    return null;
            }
     }   
}

While

public static void main(String[] args) {
    GType<Point1> gt = new GType<>(Point1.class);
    Point1 p = gt.get(10,10);
}

works well, the following construction

    public static <Point> void test (Point point){
            GType<Point> g = new GType<>(Point.class); //Error
            point = g.get(10,10,10);
    }

    public static void main(String[] args) {
        Point1 p1;
        test (p1);
    }

leads to

Error: Cannot select from a type variable

How to to create an instance of the Point1 type inside the test() function, where Point = Point1? Thanks for your help.

Updated question:

Is there a solution with the Lambda function for a method with the unknown Point instance:

    public static <Point> void test  (List<Point> points)
    {
            GType<Point> g = new GType<>((Class)points.getClass());
            Point point = g.get(10,10);
            points.add(point);
    }
7
  • 1
    Do you know what a generic method is? What do you think the <Point> in the method declaration does? Commented Oct 3, 2016 at 17:51
  • @ Sotirios: My native language is C++, where I am frequently using templates :-) I hope that Point = Point1, but it may not be correct in Java... Commented Oct 3, 2016 at 17:55
  • 1
    You don't need reflection to instantiate a generic class. Just prefer factories (say, an instance of Supplier<T> that would return a new instance of T) over reflection. Commented Oct 3, 2016 at 17:55
  • @ Lyubomyr: May I ask you for an example? Commented Oct 3, 2016 at 17:57
  • 1
    @justik I mean something like this: gist.github.com/lyubomyr-shaydariv/… - just compare both consumers. Passing a supplier you can fetch a new object or a ready-to-use instance no matter what its consructor signature is and having strong compile-time analysis with your javac. Commented Oct 3, 2016 at 18:11

1 Answer 1

1

Java Generics are just about static type-checking. You cannot instantiate a type parameter and you cannot get .class of a type parameter.

Since you're passing in a Point instance, you can ask the instance for its class:

point.getClass();

so you can pass that to the GType constructor.

However, this is just the answer to your immediate question. Lyubomyr is right in his comment where he states a better Java idiom is passing in a factory lambda function. In your case you'd like a lambda shape like the following:

(double, double) -> Point

Since such a shape isn't provided in the standard library, you should create your own:

@FunctionalInterface
public interface PointConstructor<Point> {
   Point create(double x, double y);
}

Your GType would become

public class GType<T> {
  private PointConstructor<T> cxor; 
  public GType(PointConstructor<T> cxor) { this.cxor = cxor; }

  public T get(double p1, double p2) { 
    return cxor.create(p1, p2);
  }
}

and you call it as

GType<Point2> gt = new GType<>(Point2::new);

This both works at runtime and satisfies static type safety.

Sign up to request clarification or add additional context in comments.

11 Comments

@ Marko: To the reflection solution. You think GenericType<Point> g = new GenericType<>((Class)point.getClass())?
Yes, and you can see how you have to disable static type checking, because none is possible due to the virtual function call, resulting in dynamic dispatch that's beyond the reach of the static type system.
@ Marko: GType<Point2> pg = new GType(Point2::new) leads to Error: Incompatible parameter types in method reference
I was missing a <> on new GType(..), but everything else should be OK. See the edited code.
If you have a list of a generic Point type, the there's nothing but reflection left. If you have the point classes under your control, you can add a factory method to a common supertype, but I doubt that's available to you.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.