Reputation: 7357
I have two classes:
public class Base{
public Derived becomeDerived(){
Derived d = new Derived(this);
//set this pointer pointing to d,
//this = d; doesn't work
return d;
}
}
public class Derived extends Base{
public Derived(Base b){ }
}
Is it possible to change the runtime type of current object by its method as I show in the example?
The reason why I want to do that is providing a method for concatenating objects.
I have
public abstract class Table{
}
and
public class ComplexTable extends Table{ }
which is in fact a linked-list of Table
objects.
I would like to provide a method, say Table.append(Table t)
which not only modify the current Table object, but also make it ComplexTable
's instance.
Upvotes: 1
Views: 1234
Reputation: 279
Bad idea follows
It is possible to change the type of an object, but it relies on behaviour that is not part of the JVM spec and is thus not portable. You have been warned.
There is a class sun.misc.Unsafe
that let's you read/write memory at any offset of an object. The type of an object is stored in the object's header at offset 8 on 64-bit JVMs. Thus, to change the type of the object all you need to do is to change the value at this offset. Note that the types/classes your switching between must have the same structure (reference fields on the same offsets and having the same total size). If not, the garbage collector will read non-references as references (or vice-versa) and crash you JVM.
I'm not providing working example intentionally as I'm not recommending this. Stuff like this is more suitable in C than in Java. It's really not that hard to do though, and the link I've provided together contains all information required.
Some tests I made indicates that it works on several JVMs and that the JIT is robust against these dangerous object type changes. That is no promise that it works in all systems and under all conditions.
By the way, I'm curious to hear from someone who can explain why the JIT doesn't consider the type of an object as a jit-compile-time constant, or how the JIT knows to recompile when the type of an object has changed.
Upvotes: 0
Reputation: 7695
No.
In your example, Base
wouldn't become Derived
, it would return a new Derived
object.
Base foo = new Base();
foo = foo.becomeDerived();
This is likely what's throwing you off, remember that the variable is not the object, just a reference to one. So while you can say foo
changes from Base
to Derived
, the run-time type of an object didn't change, you made a new object with a different run-time type and reassigned the variable.
Edit: More in depth example. I give the objects "names" just so it's easier to understand.
Base foo = new Base();
/* After execution:
*
* Vars: | Objects:
* foo ----+---> a Base object (Name: Joe)
*/
foo = foo.becomeDerived();
/* After execution:
*
* Vars: | Objects:
* foo ----+---> a Derived object (Name: Phil)
* | a Base object (Name: Joe)(notice nothing references it)
*/
The type of "Joe" did not change. Joe was and will always be a Base
object. This is what you're referring to by "run-time type of an object." However, the run-time type of variables change all the time! In this example, foo
starts as Base
but becomes Derived
.
Upvotes: 3
Reputation: 2033
Unlike in C++
You can not change or reassign the value of
this
.
This
was chosen to be a reserved word.So Answer is
No ,it is not possible to change the runtime type of current object
.
One more error i could find in your code is always use the Base reference variable so you can refer to objects of classes extending it.
Base b;
b=new Derived();
b=new Base();
Upvotes: 1
Reputation: 1110
You cannot set this
to d
as this
is super type of Derived d
.
But it is possible to store object of type Derived
like d
in this case into a reference of Type Base
.
You can store types of derived classes in reference of base class. But it is not changing types technically just reference holding object of derived type.
Upvotes: 1