Reputation: 7709
I've seen this code approach in a lot of API's ant always wondered what was the real purpose of it. If we have a class with a simple signature, let's say:
public class MyClass {...}
And inside this class we have a variable of type Object, with a getter and a setter for this variable. the difference is the getter method makes use of Generics. So our class looks like this:
public class MyClass {
private Object myVariable;
public void setMyVariable(Object myVariable) {
this.myVariable = myVariable;
}
public <T> T getMyVariable() {
return (T)myVariable;
}
}
So when we call the getter method, we can do it like this:
myClassInstance.setMyVariable(new Vehicle());
Vehicle v = myClassInstance.<Vehicle>getMyVariable();
This sure works fine because when setting the variable, we created a instance of the same type. But we can also do it like this:
myClassInstance.setMyVariable(new Airplane());
Vehicle v = myClassInstance.<Vehicle>getMyVariable();
Now we're going to see an error when executing the app, because Airplane cannot be cast as Vehicle.
So looks like the use of generics in this method makes easier to make a class cast when using it. But is it the only function of this approach? Or there is another advantages?
Upvotes: 1
Views: 99
Reputation: 14541
This is wildly unsafe and just there to make client's life easier (Edit: By the way, your compiler / IDE should also add a warning. This is not an error for backwards compatibility reasons). You don't even need myClassInstance.<Vehicle>getMyVariable()
, you can just myClassInstance.getMyVariable()
(as long as you store it into a variable of type Vehicle or return it from a method that returns Vehicle. In both cases, the type is inferred).
A safer approach is to pull the type parameter into the class, which can then ensure that any MyClass<Vehicle>
only holds Vehicles at compile time.
Upvotes: 4
Reputation: 141
This strikes me as inherently unsafe as I could quite happily do
AnyClass thing = myClassInstance.getMyVariable();
With thing
being absolutely anything with no type checking and no warnings in the client code (there will be a warning in the myClassInstance
code) giving rise to ClassCastException
s at runtime.
Better to parameterize the class I'd say.
public class MyClass<T> {
private T myVariable;
public void setMyVariable(T myVariable) {
this.myVariable = myVariable;
}
public T getMyVariable() {
return myVariable;
}
}
The Java type inference system should enforce type safety now and prevent any runtime exceptions.
Upvotes: 2
Reputation: 9152
The "advantage" to this is to allow the user to perform a cast, without having to write the cast. In most situations, there's no need to qualify the type when calling your method. The following would be equivalent:
Foo myValue = myClassInstance.getMyVariable();
Foo myValue = myClassInstance.<Foo>getMyVariable();
However, when compiling your class, there is an "unchecked cast" warning from Java, which is a sign that you're doing something dangerous or wrong. And you probably are.
Your class lets the user do incorrect casts, possibly creating all sorts of weird bugs in their code, without getting any warnings themselves when compiling their own code. For example, he following code will show no warnings when compiling, and when run, no runtime errors (yet!)
List<Integer> myIntList = new ArrayList<Integer>();
myClassInstance.setMyVariable(myList);
List<String> myStringList = myClassInstance.getMyVariable();
myIntList.add(3);
myStringList.add("hi");
However, what happens when your later code assumes you know the type of the items in this list? If you had done the casts explicitly, you'd get a compile-time error:
List<String> myStringList = (List<Integer>) myIntList; // error: inconvertible types
So, a second "advantage" of this is that you can use it to write, compile, and run Java code more broken and buggy than the Java compiler would normally allow you to.
Upvotes: 2