How do I instantiate a generic type?

KubbyDev :

I'm making some maths classes for a project in Java. I have a Vector3 class, but I will also need Vector4 and Vector2, but obviously I don't want to copy paste my code 3 times.

So what I did is a Vector class that will be the mother class of all vectors. I could just have the Vector class with no child, but I prefer having these child classes because I can add specific things on them, like euler angles operations in Vector3 and also I want to use Vector4 as a mother class for Quaternion. Anyways, here is my simplified Vector class:

public class Vector {

    public double[] values;

    public Vector(double[] values) {
        this.values = values;
    }

    public int getLength() { 
        return values.length; 
    }

    public static <T extends Vector> T multiply(T vector, double k) {

        double[] values = new double[vector.getLength()];
        for(int i = 0; i < values.length; i++)
            values[i] = k* vector.values[i];
        return new T(values);
    }
}
public class Vector3 extends Vector {
    public Vector3(double[] values) {
        super(values);
    }
}

The problem is that the compiler won't let me instantiate a T: "Type parameter T cannot be instantiated directly". But I need this T because I need the returned vector to be the same type as the sent one.

If I do new Vector2(4,2).multiply(42), I need to get a Vector2 and not a Vector. I could also make a multiply method in Vector2 that calls the Vector multiply and then copies the values in a Vector2 but 1. it's awful, 2. that would imply a lot of copy paste between the child vectors, 3. I need performance, so that's not ideal.

I know I can use reflection to solve the problem, but these methods are performance critical so I have to keep it as simple as possible.

I also thought about altering the vector in parameter so I don't have to instantiate a new one, but that's a really bad idea because it can cause weird behavior.

Any help is appreciated.

Izruo :

If it is performance critical you might actually think about having the multiply method altering the state of the vector instead of creating a new one. In my opinion, it is not weird, as long as it is a deterministic and documented behavior.

For an immutable vector class, however, you need to clone the vector.

public class Vector implements Cloneable {
    // not a good idea to make it public, if you don't want any changes here
    private double[] values;

    public static <T extends Vector> T multiply(T vector, double k) {
        Vector temp = vector.clone();
        for(int i = 0; i < temp.values.length; i++)
            temp.values[i] = k * temp.values[i];
        // the clone method guarantees that 'temp' is of type T,
        // but since it is not generic, the compiler cannot check it
        @SuppressWarnings("unchecked") 
        T result = (T)temp;
        return result;
    }

    protected Vector clone() {
        try {
            Vector vector = (Vector)super.clone();
            vector.values = Arrays.copyOf(values, values.length);
            return vector;
        } catch (final CloneNotSupportedException exc) {
            // this is a weird design choice of `Object.clone()`, too,
            // but back then, we did not have annotations or anything equivalent
            throw new AssertionError("we forgot to implement java.lang.Cloneable", exc);
        }
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=139414&siteId=1