Instance variables go on stack and objects go on heap and object references go on stack. Right? But what if an instance variable was a reference to an object? Like var c:
class clony implements Cloneable {
clony c = new clony();
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class tst2 {
public static void main(String[] args) throws CloneNotSupportedException {
clony j1 = new clony();
}
}
And if it goes on heap why it throws and stack overflow error?
Your reference c is a field of the class clony. That means the reference will be stored on the heap inside the memory region that is allocated for the clony object.
And your program throws a stack overflow exception since clony infinitely constructs itself: Inside the constructor of clony you create a new clony object and assign it to field c: Which will then do the same thing again and again.
This is because the stack is also used to keep track of method calls. Every time you call a method (the class's default constructor, in this case), certain information is added to the stack for that purpose. When you have infinite recursion (as you have with your constructor), that fills up the stack PDQ.
I think this:
clony c = new clony();
Gives you the exception.
new clony() also has clony c = new clony()
inside... and it goes to infinity.
By the way, classes should be named with capital letter at the beginning.
Related
I have read my question one more time and I think the example was not good enought to show where was my confusion. So I will show a different example.
public class Main {
public static void main(String args[]) {
Foo foo = new Foo();
foo.deleteOtherFoo();
}
}
public class Foo {
private OtherFoo otherFoo;
public Foo() {
otherFoo = new OtherFoo();
}
public void deleteOtherFoo() {
this.otherFoo = null;
}
}
public class OtherFoo {
public OtherFoo() {}
}
If I follow what I know about stack and heap, I can say:
my draw
in the frame deleteOtherFoo what do I have as parameters? because I know I can only have primitive type or reference type value. In that case I have a reference type Foo.otherFoo ? a value that contain a pointer of a pointer ?
Because when I put this.otherFoo = null, I remove the ref of otherFoo from the object foo.
code lives in an entirely different place. Code is effectively unchanging, save some crazy 'reload this class from disk again please' shenanigans (which the JVM does support but that's an entirely different can of worms).
So where does 'the method' live? Well, nowhere. The CODE of the method lives in what used to be called permgen. It's definitely not the stack, never gets garbage collected, and no matter how many Foo objects you make, the code is located in memory only once.
And that's that.. until you call the method.
When you call the method, if it's non-static, it needs 'an instance'. This is, as far as the JVM is concerned, pretty much 100% the same as a parameter: If you call foo.doThingie(a);, then both foo and a are parameters to the doThingie method. These are put on the stack, and then doThingie is executed. Once doThingie finishes execution, the stack is reset to the point before doThingie was invoked, so, 'foo' and 'a' are now gone.
In java, all non-primitives are 'references' which is just javaspeak for 'pointers'. So when I say 'foo and a are on the stack', what I really mean is 'a pointer, into the heap, pointing at the data (i.e., the fields) that represent an instance of Foo, is on the stack'.
I know that object references are created on the stack, and the objects themselves are created on the heap. In the code below, I try to fill the heap by creating a large number of Main objects, using recursion in the constructor; However, instead of an OutOfMemoryError, I get a StackOverflowError
public class Main {
public Main() {
new Main();
}
public static void main(String[] args) {
new Main();
}
}
Why does this happen?
When you create an object with new, it invokes the object's constructor. The constructor is a method. Each method invocation results in the creation of another stack frame, each of which is using a portion of your available stack space. Once you run out of stack space, you will get a StackOverflowError. An unlimited recursion will quickly exhaust the available stack space. With your code, there is a race between which will exhaust first, stack space or heap space; however, with most default limits, the stack is going to be much smaller than the heap.
To cause an OutOfMemoryError create lots of objects inside a while(true) loop, and ensure that the objects aren't collectible by the garbage collector. For example:
public class MyObject {
int[] array = new int[1024*256];
static List<MyObject> myList = new LinkedList<>();
public static void main(String[] args) throws Exception {
while(true){
myList.add(new MyObject());
}
}
}
So let's say:
public class Sample { //main() class
public static void main(String[] args) {
A a = new A();
}
}
public class A {
A aa = new A();
}
So...when I run it ...it gives : java.lang.StackOverflowError.
So, my explanation is that object a generation at line 1, furthers creates object aa generation at line 2...and then it enters a recursion .... which keeps creating object after object, until the heap memory is full.
If the objects are created on Heap...then why does it say StackOverflowError ??
Well, it's using both heap and stack. The stack space is because you're in the constructor for A, recursively. It would be simpler to see this if you put the initialization in the body of the constructor:
public class A {
A aa;
public A() {
aa = new A();
}
}
So the A constructor calls itself, then calls itself, etc. There's generally rather more heap space available than stack space, hence why you're running out of stack space first. If your class had a lot of fields, you would conceivably run out of heap space first - although usually the heap is pretty huge in modern machines.
The reason for a stack overflow is simply that the stack runs out of space before the (small) As can fill up the heap.
You have correctly recognized the recursion. So!
I'm pretty new to Java, as my post might give away.
I need to create a class (let's call it class A) which uses another class (class B) as one of its fields. Class A's constructor calls class B's constructor. So far things work fine.
But when one of A's methods tries to use one of B's methods on the object of class B, I get a NullPointerException. This is probably too confusing so I wrote this simple example which creates the Exception.
This is class B:
public class class_B {
private int y;
public class_B(int N) {
int y = N*N;
}
public int class_B_method() {
return y;
}
}
and this is class A:
public class class_A {
private class_B obj;
public class_A(int N) {
class_B obj = new class_B(N);
}
public int call_class_B_method() {
return obj.class_B_method();
}
public static void main(String[] args) {
int N =4;
class_A p = new class_A(N);
int a = p.call_class_B_method();
}
}
When I run class_A I get the exception on the line "int a = p.call_class_B_method();".
I don't understand this, since 'obj' should have been created by the constructor 'class_B' and should be available for the method 'call_class_B_method'.
thanks!
This line in the constructor of class_A
class_B obj = new class_B(N);
initializes a local variable obj, not the obj field. This local object class_B gets created, and then almost immediately discarded. Usually compilers warn you of situations like this, for two reasons - first, you have a local variable that "shadows" a field, and second, a local variable is assigned and then never used again.
Change your code to
obj = new class_B(N);
to fix the problem.
This line is wrong(because you lose the reference of the obj):
class_B obj = new class_B(N);
You should write:
obj = new class_B(N);
In the constructor of class_A you're not referencing the field obj, you're creating a new (local) variable with the same name. This is why the member never gets instantiated. You should write obj = new class_B(N) in the contructor.
There are several possible ways to mitigate such kind of errors:
Declare the field obj final, then the compiler will comlain if you don't instantiate it in the constructor. This of course only works when you don't want to change the field value later.
Always use this as identifier: this.obj = new class_B(N). This may clutter the code sometimes, so I guess this is a matter of taste.
Btw. by convention, Java class names always start with a capital letter. But this might be the case only for your example.
I have two classes as given below.
class One {
void disp() {
System.out.println("Super class disp() method");
}
void show() {
System.out.println("Super class show() method");
}
}
class Two exntends One{
void disp(){
System.out.println("Sub class disp() method");
}
}
class TestInheritance {
public static void main(String args[]) {
One o = new Two();
o.disp();
Two t = (Two) new One();
}
}
What happens in terms of memory when we convert sub class object to super class object.?
One o = new Two();
What happens in terms of memory when we convert super class object to sub class object.?
Two t = (Two) new One();
What happens in terms of memory when we convert sub class object to super class object.?
One o = new Two();
What happens is that a Two instance is created, and the reference is assigned to o.
This doesn't change the Two instance in any way. It is not "converted". It remains a Two.
What happens in terms of memory when we convert super class object to sub class object.?
Two t = (Two) new One();
What happens is that a One instance is created, and its type is tested to see if the One is a Two. Since it isn't ... a ClassCastException is thrown immediately.
(Following that, the One instance that was just allocated will be unreachable and a candidate for garbage collection ... the next time that the GC runs.)
In fact, you probably meant this:
One o = new Two();
Two t = (Two) o;
What happens in this case is that the first statement creates a Two instance and assigns its reference to o. Then in the second statement, the type of the object refered to by o is tested to see if it "is-a" Two. Since it is ... the reference is then assigned to t.
Once again, this doesn't change the Two instance in any way. It is not "converted". It remains a Two.
Can you give some detail about how the memory will be allocated.? I mean "when Two class object is created, memory will be allocated for Two's members and One's members as well (reason being One is super class for Two)" and will be referred by 't'.
That is correct
When we do "One o = new Two()", we will be able to access only One class members.
That is correct.
When we are converting like this (sub class object pointed by super class reference), what exactly happens internally..?
All that happens is that the compiler & runtime "forget" that o actually refers to a Two, and only permits you to use the reference to access the fields / methods defined by the One class.
Casting doesn't change anything its just a way of treating object of one type as object of some other (allowable) type.
First of all your 2nd condition Two t = (Two) new One(); is not possible because
subclass object can not hold the object of super class.
In case of memory JVM treat as method overriding in case of disp() method
so One o = new Two() holds the properties of super class One as well as subclass Two.
Method are belonging to method area of the particular class
anCasting doesn't do anything, it just tells the compiler that object of type A is actually of object of type B, and therefore I can call the methods of object B on it. At compile time, all the casting is erased, you just better hope that the method call to the object actually succeeds, otherwise you will get a run time error of some description.