Let's say I've a java base class:
class base {
public Class<? extends base> type;
// ...
}
type
stores the classtype of classes which inherit from base
There's another class which stores base
objects in a container, it also has a get
method which returns objects stored in that container:
class container {
private Vector<base> v;
//...
public <something here> get(int i){
base b=v.get(i);
return b.type.cast(b);
}
How do I implement such a function(container.get
), which casts the object to it's correct type before returning it?
It would be nice to be able to program in a cascading style:
JSONObject o;
//...
o.get("nestedObject").get("array").get(3);
You may be misunderstanding what a "cast" is in Java. Except for casts that involve primitive types (such as casting an int
to a float
), casts don't change objects at all.
One of your instance variables is
private Vector<Base> v;
(Please use the Java convention and start class names with upper-case letters. I've changed base
to Base
to set a good example.)
The objects that you put in this vector can be of type Base
or any subclass of Base
. The type of the object is fixed when the object is constructed. Suppose Base
has three subclasses, Child1
, Child2
, and Child3
. Those objects can be construted with new Child1(...)
, new Child2(...)
, new Child3(...)
. As soon as you say new Child1(...)
, you have an object whose type is Child1
, and you can't do anything to change that. But since a Child1
is a Base
, you can use your Child1
anywhere you can use a Base
, such as putting it into your vector v
.
Casting just causes the compiler to look at a variable differently. Suppose you say
Base x = v.get(i);
x
(if not null) will be a Base
or some object of a subclass. The type of x
will be whatever you used to construct the object. Now if you say
Child1 y = (Child1)x;
If x
is a Child1
, y
will be a reference to the same object as x
. But the compiler will know that y
is a Child1
, and you can access new methods that are defined in a Child1
. (If x
isn't a Child1
, you get an exception.) But it's important to note that a cast does not create a new object and it does not change the type of anything. It just tells the compiler to look at a variable or expression in a different way.
Given this, you cannot gain anything by trying to write a method that returns a "variable" type. You may as well just write
public Base get(int i){
return v.get(i);
}
The object that it returns could be a Base
, Child1
, Child2
, etc.; it will be the same type as the object was when you put it into the vector. When you call get
, if you are expecting the result to be a Child1
, you can say
Child1 child = (Child1)container.get(n);
which will throw an exception if the object isn't a child1
. Or you can use instanceof
to check yourself:
Base child = container.get(n);
if (child instanceof Child1) {
...
}
If this isn't good enough, you'll need to explain more clearly what you want to accomplish and why this won't work.
MORE: After reading your edit, that says you want to do something like this:
JSONObject o;
//...
o.get("nestedObject").get("array").get(3);
You don't need any casting to accomplish this. What you need is an abstract JSONValue
base type that represents any kind of value that can be returned from a JSON parser. The subclasses would be things like "object", "array", and whatever scalar types you need (integer, string, etc.). get
would return JSONValue
. In actuality, it will return an object of one of the other types, but all the compiler needs to know is that it returns JSONValue
.
Now a JSONValue
will need two get
methods, one that takes a String
and one that takes an int
or Integer
. These will be polymorphic methods. Say v
is a JSONValue
and you say v.get("array")
: the method it actually calls may be different based on the actual type of v
. So if v
is your "object" type, it will call the method you've defined for the object type; if v
is an integer type, it will call the method defined for the integer type, and so on. What you want is for the get
method that takes a String
to look up the field for the JSON "object" type, and throw an exception for everything else. Similarly, for the get
method that takes an integer parameter, the method for the JSON "array" type will look up a list or something, and the method for every other subclass of JSONValue
will throw an exception. No "casting" is needed for this. Casting is a compile-time concept. At all points, the compiler will know only that it's working with a JSONValue
. But at run time, the object's actual type is used to determine which method to call, so the compiler doesn't need to know anything more.
This is a basic concept that all Java programmers need to know (also Javascript, Python, and pretty much every other language these days, although polymorphism is handled differently in interpreted languages like Javascript and Python). The tutorial https://docs.oracle.com/javase/tutorial/java/IandI/index.html covers this and related concepts. There may be better Java tutorials on "polymorphism" out there also.