When a user defined class (A) has an Object of another user defined class (B) as one of it's data members, then:
In Java: Actually, only a reference to that instance of B is the data member of A, not the instance of B itself.
In C++: The entire instance of B is the data member. No pointers or anything. Just the whole solid instance of B itself unless it's dynamically instantiated in which case, a pointer is the data member.
Is my deduction correct or incorrect? I'm not sure myself if this is 100% correct.
Now, I'm really intrigued by this whole thing. Can you take it one step further and tell me something I missed? I mean, what is the significance of this difference? Does it mean, that the class A in Java occupies less space than the same class A implementation in C++?
Yes, you are basically correct. The Java class
class C{
D dRef; // needs to be assigned a valid object reference.
}
The dRef is assigned a newed object reference.
Will be constructed similar to the c++ class
class C2
{
D* dPointer; // needs to be assigned a valid pointer value.
};
The dPointer can be assigned a newed object pointer value.
While the c++ class
class C3
{
D dValue;
};
Will contain the entire layout size of D, created when a C3 is created.
The c++ version will likely in both scenarios occupy less space than the java version. For the java version to be usable, e.g. cObject.dRef.dMethod() a D object needs to be created, new D(). There will be overhead for both the C object as well as the instance. Garbage collection bookkeeping for instance.
The c++ variants needs only to store the pointer value in C2 (along with a new D). For C3, C3 can be the same size as D.
Related
Lets say I have a class A.java,
When I will execute a constructor method of A, it will create a memory space for xyz Object.
A xyz = new A();
The reference to memory may be something like,
[xyz] ---> '0x34524'
Thats basics of OOP. Simple enough!
Now,
What happens if a class is inheriting from different parent classes? How many object space will be created in memory?
Lets say we have,
and then we create an object of class D.java,
D omg = new D();
Here as we know that D's object will call construct of C.java and so on until A.java. Does this mean that in memory we are having 4 different memory reference, because we are instantiating all of the four objects (one directly and another 3 indirectly)?
[omg] ---> '0x34525'
[C] ---> '0x34526'
[B] ---> '0x34527'
[A] ---> '0x34528'
Note :
This isn't homework question, this is just a curiosity question.
I am aware of the fact that if we have a instance variable inside an A.java then we will not create only object A but we will be creating other internal object whenever we hit new keyword.
First, a tid bit... calling the constructor of an object does not allocate it. In bytecode, the initialization new Object() is expressed as something to the effect of...
new java/lang/Object
invokespecial java/lang/Object <init>()V
The new instruction takes care of allocating the space and acquiring a reference to the yet uninitialized object, while the invokespecial handles calling the constructor itself (which is internally compiled to a void method named <init>, hence the descriptor <init>()V).
Moving on, internals of object allocation and representation on the heap are entirely JVM specific. However, as far as I know, there is only one allocated object per allocated object, no matter its number of super classes. The object itself in memory has space for the instance fields of both its own class and its super classes. It must also have space for a virtual method table, in order to do virtual dispatch when performing virtual method calls (e.g. via invokevirtual) for the object.
Internally, the Oracle HotSpot JVM manages things called oops, or ordinary object pointers. You can read more about the HotSpot memory layout here. Feel free to browse the HotSpot source repository.
JVM allocates memory for only one object (here D)
memory allocation and initialization happens bottom(here D) to top(Object)
initialization/calling constructors happens Top(Object) to Bottom(here D)
reference :
http://www.artima.com/designtechniques/initialization.html
I have not read this anywhere but its my experience.
When you call new D(), the constructor chain begins, it first creates an java.lang.Object and then extends it to an A, I mean after creating the Object (which is root of all objects), A is initialized on it, by adding memory for A's members, including fields and methods (which are a pointer to some code!). And then it extends to B and so on.
In the process of extension if a method is overriden, the method pointer in the object will point to new code.
It will be only one reference to D.
I am trying to understand how inheritance is realized inside JVM. It seems to me, that if we have the following code:
class A {
int aa;
}
class B extends A{
int bb;
}
....
B b=new B();
Inside the JVM three objects will be created:
object of B (with field int bb),
object of A (with field int aa)
object of Object.
Of course the programmers see only one object of class B. Am I right? Or is only one object created inside JVM?
What I think:
The new returns the reference to B. Why I think so is (for example) that if we override some method from A in B we can always get it using super. Besides in default constructor B the first line will be call to default constructor A in which we can call the constructor on certain object ONLY IF this object exists. Therefore a separate A object exists?
At first, the spec says that the internal structure of objects is not specified, so in theory, a JVM could internally create more than one object, where B contains only fields new to B, and a link to an A object, which contains the fields of A.
It also says something about the Oracle JVM implementation: A class instance contains three pointers. One to a method table, one to some space in heap where the data of the instances fields is, and one the Class object that instance belongs to.
You can conclude from that, that there is only one instance per object created, namely the instance of B. The method table for this instance contains all methods from B, A and Object, as well as the heap space contains all data from fields from B, A (and Object).
Here only one object will create. it is B object. But B object has state and behaviors of A object. As super type of every class is Object class, B object has Object's state and behavior too. Thanks
Classes represent a type of objects, but only instances create real objects. So only one object is created and it corresponds the result merge of class B with class A.
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.
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.
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.
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();
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.
After searching a lot, at least this question helped me to understand the difference of using copy constructor and assignment operatorMy question is about this line instance has to be destroyed and re-initialized if it has internal dynamic memory If I initialize an instance like
Object copyObj = null; and then then assign copyObj = realObj then still this overhead (destruction and re-initialization) remains?If not, then Now in this scenario, why should I use Copy Constructor instead of direct assigning the object
The concept of using a copy constructor by overriding the = simply does not exist in Java. You can't override operators. The concept of a copy constructor in Java works like this:
public class MyType {
private String myField;
public MyType(MyType source) {
this.myField = source.myField;
}
}
A copy constructor is a constructor that takes a parameter of the same type and copies all it's values. It is used to get a new object with the same state.
MyType original = new MyType();
MyType copy = new MyType(original);
// After here orginal == copy will be false and original.equals(copy) should be true
MyType referenceCopy = original
// After here orginal == referenceCopy will be true and original.equals(referenceCopy) will also be true
The = operator does the same: Assigning an object to a variable. It produces no overhead. The thing that can differ in runtime is the constructor call.
A Copy constructor allows you to keep two references; one to the "old" object, one to the "new". These objects are independent ( or should be depending upon how deep you allow the copy to be )
If you do a reassignment, you only have a reference to the "new" object. The "old" object will no longer be accessible ( assuming there are no other references to it ) and will be eligible for garbage collection.
It comes down to what it is your trying to achieve. If you want an exact copy of the object, and you want this object to have an independent life of its own, use a copy constructor. If you just want a new object and don't care about the old one, reassign the variable.
PS - I have to admit, I didn't read the question you linked to ..
First some basics about copy construction and copy assignment in C++ and Java
C++ and Java are two very different beasts due to object semantics in C++ and Reference semantics in Java. What I mean by this is:
SomeClass obj = expr;
In C++ this line denotes a new object that gets initialized with expr. In Java, this line creates not a new object but a new reference to an object, and that reference refers to what ever the expression gives. Java references can be null, meaning "no object". C++ objects are, so there is no "no object"-object ;-) Java references are very much like C++ pointers. The only thing that can make the distinction difficult is that while C++ has pointers and objects and dereferences pointers with ->, in Java everything is a reference (except int and a few other basic types), and accessing objects through references uses ., wich easily can be confused with access to "direct" objects in C++. "Everything is a reference" means, that any object (except int & Co.) is conceptually created on the heap.
Having said that, let's have a look at assignments and copies in both languages.
Copy construction means the same in both languages, you essentially create a new object that is a copy of another. Copy constructor definition is similar:
SomeClass(SomeClass obj) { /* ... */ } //Java
SomeClass(SomeClass const& obj) { /* ... */ } //C++
The difference is only that C++ explicitly has to declare the parameter as a reference, while in Java everything is a reference anyways. Writing the first line in C++ would define a constructor that takes it's argument by copy, i.e. the compiler would have to create a copy already, using the copy constructor, for which it has to create a copy,... - not a good idea.
Using copy construction in the two languages will look like this:
SomeClass newObj = new SomeClass(oldObj); //Java
SomeClass newObj = oldObj; //C++ object
SomeClass* ptrNewObj = new SomeClass(oldObj); //C++ pointer
When you look at the first and third line, they look essentially the same. This is because they are essentially the same, since Java references are essentially like pointers in C++. Both expressions create a new object that can outlive the function scope it is created in. The second line creates a plain C++ object on the stack, wich does not exist in Java. In C++, copies are also created implicitly by the compiler eg. when an object is passed to a function that accepts its parameter by value instead of by reference.
Defining copy assignment: In C++, you can define operator= wich (normally) assigns the values of an object to an already existing object, discarding the old values of the object you assign to. If you don't define it yourself, the compiler will do it's best to generate one for you, doing a plain elementwise copy of the objects' elements. In Java, you cannot overload operators, so you will have to define a method, called e.g. assign:
void assign(SomeObject other) {/* ... */} //Java
SomeObject& operator=(SomeObject const& other) {/* ... */} //C++
Note thet here again we explicitly declare the parameter as reference in C++ but not in Java.
Using copy assignment:
objA = objB; //C++ copy assignment
objA = objB; //Java ref assignment
ptrObjA = ptrObjB; //C++ pointer assignment
objA.assign(objB); //Java
objB.change();
Here the first two lines look exactly the same but could not be more different. Remember that in C++, objA and objB deonte the objects themselves, while in Java they are only references. So in C++ this is copy assignment on objects, meaning you finish with two objects that have the same content. After changing objB you will have objA with the value that objB had before the assignment, while objB has changed.
In Java (line 2) that assignment is an assignment of references, meaning after that the two references objA and objB refer to the very same object, while the object previously referred ba objA is not referred to any more and so it will be garbage collected. Calling objB.change() will change the single object both references point to and accessing it through the reference objA will reveal these changes.
Again it's (nearly) the same with C++ pointers. You see you cannot distinguish the syntax of object and pointer assignment, it's all determined by the types that get assigned. The difference with C++ is that it has no garbace collector and you end up with a memory leak because the object ptrObjA pointed to can not be deleted any more.
About your question:
Consider a C++ class:
class X {
int* pi;
unsigned count;
public:
X(X const&);
X& operator= (X const&);
~X();
};
Suppose each X object allocates it's own dynamic array of ints, the pointer to it gets stored in pi. Since C++ has no garbage collection, the X objects have to care themselves for their allocated memory, i.e. they have to destroy it manually:
X::~X() { delete[] pi; }
A copy constructor will copy the dynamic array of the original, so the two do not conflict while using the same array. This is called deep copy and is used equally in Java and C++:
X::X(X const& other) : pi(NULL), count(0) {
pi = new int[other.count]; //allocates own memory
count = other.count;
std::copy(other.pi, other.pi+count, pi); //copies the contents of the array
}
Now to the qoute in your question:
Consider two objects x1 and x2 and the assignment x1 = x2. If you leave everythign to the compiler, it will generate an assignment operator like this:
X& X::operator=(X const& other) {
pi = other.pi;
count = other.count;
}
In the first line x1.pi gets the pointer value of x2.pi. Like I explained in the section about copy assignment, this will lead to both pointers pointing to the same array, and the array previously owned by x1 will be lost in space, meaning you have a leak and odd behavior when both objects work on their shared array.
The correct implementation would be:
X& X::operator=(X const& other) {
delete[] pi; //1
pi = new int[other.count]; //allocates own memory
count = other.count;
std::copy(other.pi, other.pi+count, pi); //copies the contents of the array
}
Here you see what the quote says: First, the object is "cleaed up", i.e. the memory is freed, essentially doing what the destructor does ("instance has to be destroyed").
Then, the deep copy is performed, doing what the copy constructor does ("...and re-initialized").
This is called the "Rule of Three": If you have to write your own copy constructor (because the generated one does not what you want it to do), you will mostly have to write your own destructor and assignment operator as well. Since C++11 it has become the "Rule of Five", because you have move assignment and move construction that have to be considered as well.
Lets say I have a class A.java,
When I will execute a constructor method of A, it will create a memory space for xyz Object.
A xyz = new A();
The reference to memory may be something like,
[xyz] ---> '0x34524'
Thats basics of OOP. Simple enough!
Now,
What happens if a class is inheriting from different parent classes? How many object space will be created in memory?
Lets say we have,
and then we create an object of class D.java,
D omg = new D();
Here as we know that D's object will call construct of C.java and so on until A.java. Does this mean that in memory we are having 4 different memory reference, because we are instantiating all of the four objects (one directly and another 3 indirectly)?
[omg] ---> '0x34525'
[C] ---> '0x34526'
[B] ---> '0x34527'
[A] ---> '0x34528'
Note :
This isn't homework question, this is just a curiosity question.
I am aware of the fact that if we have a instance variable inside an A.java then we will not create only object A but we will be creating other internal object whenever we hit new keyword.
First, a tid bit... calling the constructor of an object does not allocate it. In bytecode, the initialization new Object() is expressed as something to the effect of...
new java/lang/Object
invokespecial java/lang/Object <init>()V
The new instruction takes care of allocating the space and acquiring a reference to the yet uninitialized object, while the invokespecial handles calling the constructor itself (which is internally compiled to a void method named <init>, hence the descriptor <init>()V).
Moving on, internals of object allocation and representation on the heap are entirely JVM specific. However, as far as I know, there is only one allocated object per allocated object, no matter its number of super classes. The object itself in memory has space for the instance fields of both its own class and its super classes. It must also have space for a virtual method table, in order to do virtual dispatch when performing virtual method calls (e.g. via invokevirtual) for the object.
Internally, the Oracle HotSpot JVM manages things called oops, or ordinary object pointers. You can read more about the HotSpot memory layout here. Feel free to browse the HotSpot source repository.
JVM allocates memory for only one object (here D)
memory allocation and initialization happens bottom(here D) to top(Object)
initialization/calling constructors happens Top(Object) to Bottom(here D)
reference :
http://www.artima.com/designtechniques/initialization.html
I have not read this anywhere but its my experience.
When you call new D(), the constructor chain begins, it first creates an java.lang.Object and then extends it to an A, I mean after creating the Object (which is root of all objects), A is initialized on it, by adding memory for A's members, including fields and methods (which are a pointer to some code!). And then it extends to B and so on.
In the process of extension if a method is overriden, the method pointer in the object will point to new code.
It will be only one reference to D.