If this is the case then would it be right to say that it is not
stored in memory?
No. The object is definitely still stored in memory. If it has no declaration, it can still have a reference pointing to it from within another object, which is the case here since you initialized the object within a setter method for object primaryStage
.
If you were to instantiate it without any reference to it at all and just wrote:
new Scene(grid, 300, 275);
it would be still be stored in memory but likely would be short-lived as it would be unreachable and would likely be garbage collected eventually because there is nothing referencing (pointing to) it.
Anytime you instantiate an object, it will be stored on the heap memory space whether it has a declaration or not. Heap memory is the area of memory that is allocated for storing objects. Stack memory is the area in memory allocated for storing local variables.
In your example, you initialized Scene
within a primaryStage
setter method, meaning that primaryStage
now has a reference pointing to Scene
thus preventing it from being cleaned up by the garbage collector. Therefore, Scene
will remain in memory for at least as long as primaryStage
does.
Objects have a lifecycle - meaning that they exist in memory as long as the JVM is able to reach them. For the life of an object to continue, there must be a reference variable that can point to it. If there is no reference variable pointing to that object, that object becomes eligible for garbage collection, which is a process by which the JVM has determined that this object is no longer useful and will likely remove that object from memory in order to clear space for storing new objects.
For a more in-depth understanding about memory management, check out the Oracle docs on this subject and you will be able to understand the differences between stack and heap memory as well as some of the different types of garbage collection built in the JVM.
https://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/geninfo/diagnos/garbage_collect.html
Why would we want to do this?
A common case would be to invoke methods that require object references you don't already have. There will be times where you would want to call a non-static method but have no pre-existing instances to invoke it with. Below is an example:
class Orange {
void printOrange(){
System.out.print("Oranges are my favorite fruit.");
}
}
class OrangeJuice extends Orange {
public static void main(String[] args) {
// some other useful code for OrangeJuice
new Orange().printOrange();
}
}
In this example, the output would be:
Oranges are my favorite fruit.
We didn't need to create a reference variable in order to simply invoke a print method, so why waste time and memory doing so if this is the only way in which you wish to use class Orange? In this case, you are able to invoke printOrange()
while:
- not using any space in stack memory for creating a reference variable
- using heap space efficiently by reducing the lifetime of the
Orange
object you initialized for merely invoking printOrange()
- made your code simpler by not creating an irrelevant declaration. You're keeping it as simplified as possible, which is good for organization's sake, understandability, and build time
Another reason to instantiate without a declaration, and this is typically the case for programs that handle copious amounts of data, would be to prevent a stack overflow, which is when the stack space has caused a crash from its storage space being overused due to local variables maxing out on the stack storage.
Objects can only be declared/created at runtime. Just because it compiles and runs with no exception errors doesn't mean it can't eventually crash. When declaring objects on a large scale and not allowing them to be garbage collected, this can result in your program crashing from overusing memory.
By making as few declarations as possible (without affecting the functionality of your program), you reduce the likelihood of this happening, since reference variables are stored in stack memory. Of course this is a problem usually associated with larger programs or programs that process large streams of data.
How is it that we can pass this Scene
object to the setScene
method
successfully but not save the Scene
object?
The compiler was designed to understand the need for memory management. You don't need to make an explicit declaration in order to make use of an object. Declarations cost memory and build time.
In this case, You did "save" the object. By initializing Scene
within the setter method setScene
for object primaryStage
, you created a pointer to that Scene
's space in memory. It now lives there and can be referenced through the primaryStage
object.
When invoking a non-static method that is meant to produce an output that refrains from having any object-oriented outcome, the compiler simply needs the object as a stepping stone to produce that outcome. It allows you to put an instantiation in place of where a reference variable would normally be used to invoke the method in order to allow more efficient use of code.
By instantiating an object without a declaration, in your particular case, you are basically saying "I want to invoke the setScene
method and I know that I need a Scene
object to build off of in order to do that. I'm going to instantiate a Scene
object strictly for that purpose and make my code more simple."