-1

How can I use the cast method of a generics vector. What I thought of, is patterns like (Vector<T>).class.cast(getDates()); or (Vector<a_typeClass>).class.cast(getDates()); but they are not working. A workarround is to cycle trough all elements. But there has to be a way to use cast for a generics Vector.

(Yes, I have to use Vector, because I'm extending an API)

Edit: This is only a small part of a much more complex code. The cast will never fail because of types checking: if (Date.class.isAssignableFrom(a_typeClass)). I also left out the null check in the sample. Eclipse is raising an error Type mismatch: cannot convert from Vector<Date> to Vector<T> because it is not recognizing the type check pattern.

Edit: In the samples I used isAssignableFrom the other way. Was before Date.class.isAssignableFrom(a_typeClass) is now a_typeClass.equals(Date.class). But still I have to use the (Vector<T>) cast, if I don't use it, compile error Type mismatch: cannot convert from Vector<Date> to Vector<T>will be raised. Thanks to davmac and JB Nizet.

Sample:

public class VectorCast {

    @SuppressWarnings("unchecked")
    public <T> Vector<T> getVector1(Class<T> a_typeClass) {
        Vector<T> returnValues = new Vector<>();
        if (a_typeClass.equals(Date.class)) {
            returnValues = (Vector<T>) getDates();

            // Not working
            // return (Vector<T>).class.cast(getDates());
            // return (Vector<a_typeClass>).class.cast(getDates());
        }

        return returnValues;
    }

    public Vector<Date> getDates() {
        // Just dummy Values
        return new Vector<Date>(Arrays.asList(new Date(0), new Date()));
    }

    public static void main(String[] args) {
        VectorCast vectorCast = new VectorCast();
        System.out.println(vectorCast.getVector1(Date.class));
    }
}

Work around Sample:

public <T> Vector<T> getVector2(Class<T> a_typeClass) {
    Vector<T> returnValues = new Vector<>();

    if (a_typeClass.equals(Date.class)) {
        for (Date date : getDates()) {
            returnValues.add(a_typeClass.cast(date));
        }
    }

    return returnValues;
}
notes-jj
  • 1,437
  • 1
  • 20
  • 33
  • So, you have a Vector, and you would like to transform it into a Vector, is that right? What should happen if one of the Foos is not a Bar? – JB Nizet Jul 02 '16 at 14:13
  • They are always the right type. I check with user want's Vector: `if (Date.class.isAssignableFrom(a_typeClass))` and `public Vector getDates()` always returns a `Vector` – notes-jj Jul 02 '16 at 14:19
  • That's what you're doing, and you're asking a question because what you're doing doesn't work. What I'm asking is: what do you **want** to do. What should the code do if one of the Foos is not a Bar? – JB Nizet Jul 02 '16 at 14:20
  • I want to do `return (Vector).class.cast(getDates());` – notes-jj Jul 02 '16 at 14:23
  • Yes, but that isn't valid Java code. So only you know what that can possibly mean. – JB Nizet Jul 02 '16 at 14:25
  • If what you want to do is take a Vector and make it a Vector, without making a new vector, then that is not safe at all, even if all elements are instances of Bar. So you should NOT do that. See http://stackoverflow.com/questions/2745265/is-listdog-a-subclass-of-listanimal-why-arent-javas-generics-implicitly-p – JB Nizet Jul 02 '16 at 14:32
  • @JBNizet I'm sorry that my question seams to be so difficult to understand. I'm checking for types, look at my code. I want to cast an object, that is a Vector to a Vector. But with using generics, it get's complicated and I don't understand why con can do a `String.class.cast(` for all kind of classes but not for a type Class like Vector, ArrayList and so on. – notes-jj Jul 02 '16 at 14:56
  • I can't deduce anything from your code, since it's not valid code. I can only guess what you want. Why don't you answer to my simple, direct questions? 1. So, you have a Vector, and you would like to transform it into a Vector, is that right? Just answer yes or no. 2. If yes, do you want to make a copy of that vector? Yes or no. 3. If yes, what should the copy do if one of the foos is not a bar? 4. If no to the second question, and you simply want Vector to become Vector, then this is unsafe. because a Vector is NOT a Vector, even if Foo is a Bar. See the linked q – JB Nizet Jul 02 '16 at 15:05
  • @JBNizet: The samples are valid code. Copy the code to a java file and run it. 1. NO - I want to cast a Vector to a Vector 2. NO 3. They are all Vector 4. They are all Vector – notes-jj Jul 02 '16 at 15:14
  • Then all you need is `Vector a = ...; Vector b = a;`. No need to cast anything. So, my guess is that it's not what you want. Let's try once again. What problem, at a higher level than "cast a Vector to a Vector", are you trying to solve? – JB Nizet Jul 02 '16 at 15:20
  • @JBNizet Then please run my first sample and try to leave the cast away ` (Vector)` and java will raise an error: `Type mismatch: cannot convert from Vector to Vector` T will be Date, what is check in the if one line before. – notes-jj Jul 02 '16 at 15:37
  • 1
    You are not casting `Vector` to `Vector` - you are casting `Vector` to `Vector`. The question is, what's wrong with what you have now? – davmac Jul 02 '16 at 15:49
  • Agreed with davmac. Your code is completely unsafe, but it compiles and runs. So, what's the probem? – JB Nizet Jul 02 '16 at 15:53
  • There is nothing wrong. But I don't understand that the "type save" casting patterns are not working with `isAssignableFrom` and why typed Classes don't have a class object. – notes-jj Jul 02 '16 at 15:56
  • @JBNizet Could you please run the code or stop commenting. It's not my fault that you don't understand the type checking that is going on. – notes-jj Jul 02 '16 at 15:58
  • 1
    Yes, it's your fault, actually. If you just have said: here's some code, it compiles and runs fine, but I don't understand why I need a cast, then it would have been much faster. And BTW, I understand the type checking. You are the one that doesn't understand it. – JB Nizet Jul 02 '16 at 16:01
  • @notes-jj JB Nizet is correct. Try: `VectorCast vectorCast = new VectorCast(); Vector – davmac Jul 02 '16 at 16:10
  • @davmac There was an error in the isAssignableFrom statment. It's corrected now, but I still need the cast. – notes-jj Jul 02 '16 at 16:46

2 Answers2

0

So, if I understand correctly, you want your method to return an existing Vector<Date>, but as a Vector<T> if the class passed as argument is Date.class, or an empty vector if the class passed as argument is not Date.class. That's quite a strange requirement, but anyway.

You check, at runtime, that a_typeClass is assignable to Date. But the compiler has no clue about that. T is still another type than Date, and Vector<T> is still another type than Vector<Date>. So you need a cast to make it happy.

But even then, your check is incorrect. To be safe, a_typeClass should be equal to Date.class. I could call your method with java.sql.Timestamp.class as argument, and your method would happily return the Vector<Date> as a Vector<Timestamp>. So, callers would expect the Vector to contain Timestamp instances, and the first get() call they would make on the returned Vector would fail with a ClassCastException.

So, what you can do is check that a_typeClass is equal to Date.class, and leave the cast there, which is absolutely necessary for the code to compile, and will always be unchecked, and thus emit a warning.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Your are right about the type checking. I changed it in my Question. If I call `getVector1(Date.class)`. Then `a_typeClass = Date.class`, T will be of type `Date` and the method return value will be of type `Vector`. If I check `a_typeClass.equals(Date.class)` than the return type has to be `Vector`, but I still need the cast. – notes-jj Jul 02 '16 at 17:22
0

You can't really, because class literals are for raw classes only. You would have to do something like:

        Class<Vector<T>> c = (Class<Vector<T>>)(Object) Vector.class;
        return c.cast(getDates());

This is no clearer or better in any way than the cast you have now.

The essence of the problem is that the compile-time type checking of Java does not take control flow into account. The code pattern you have is unusual in Java (perhaps for this reason). Consider refactoring to avoid behaving differently based on a manual type check.

davmac
  • 20,150
  • 1
  • 40
  • 68
  • Your solution is working, but it still needs `@SuppressWarnings("unchecked")` because of `Type safety: Unchecked cast from Object to Class>` – notes-jj Jul 02 '16 at 17:25
  • That's right. There's no way around this with your current design. Consider using a different code pattern. – davmac Jul 02 '16 at 17:47