The keyword
static lets a method run
without any instance of the class. In other words, a static method means
"the behavior not dependent on an instance variable, so no /instance/object is required. Just the class."
The
static modifier has such a profound impact on
the behavior of a method or variable that we should fully understand of
the concept and usage of the keyword.
Let's thing about the reason for the need of
static.
- Suppose if we have a utility class with a method that always runs the same way such as Math.round() or Math.abs().
It wouldn't matter which instance of the class performed the method--it
would always behave exactly the same way. The method's behavior does
not dependent on the state (values of instance variable) of an object.
So, why do we need an object when the method will never be
instance-specific? Why not just ask the class itself to run the method?
- Assume we want to keep a running count of all instances
instantiated from a class. Where do we keep that variable? It won't work
to keep it as an instance variable within the class whose instances
we're tracking since the count will just be initialized back to a
default value with each new instance.
The answer is the
static. Variables and methods marked as
static belong to the class rather than to any particular instance. Actually, we can use a
static
method or variable without having any instances of that class at all.
We need only have the class available to be able to invoke a
static method or access a
static variable. However, if there are instances, a
static variable of a class will be shared by all instances of that class. We have only one copy.
public class Egg
{
static int counter = 0;
public Egg() {
counter++;
}
public static void main(String[] args) {
new Egg();
System.out.println("Instance counter = " + counter);
new Egg();
System.out.println("Instance counter = " + counter);
new Egg();
System.out.println("Instance counter = " + counter);
}
}
Output is:
Instance counter = 1
Instance counter = 2
Instance counter = 3
In the code, the static
counter is set to zero when the
Egg class is first loaded by the JVM, before any
Egg instances are created. Note that static variables get the default value if we don't initialize it. Every time an
Egg instance is created, the
Egg constructor runs and increments the static counter variable.
The code in the next section shows what would happen if the
count were an instance variable rather than a static variable
Static Method Can't Use Non-static (instance) Variables
public class Egg
{
int counter = 0;
public Egg() {
counter++;
}
public static void main(String[] args) {
new Egg();
System.out.println("Instance counter = " + counter);
new Egg();
System.out.println("Instance counter = " + counter);
new Egg();
System.out.println("Instance counter = " + counter);
}
}
We get the following compile error:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
Cannot make a static reference to the non-static field counter
Cannot make a static reference to the non-static field counter
Cannot make a static reference to the non-static field counter
The JVM doesn't know which
Egg object's
count we're trying to access. The problem is that the
main() is itself a
static method, and thus isn't running against any particular instance of the class, rather just on the class itself.
A
static method can't access
instance (non-static) variable, because there is no instance. Even though there are instances of the class on the heap, the
static method doesn't know anything about them.
Here is the simplest example of mistake:
public class CommonMistakes
{
int x = 10;
public static void main(String[] args) {
System.out.println("x = " + x);
}
}
The code will never compile, because we can't access a
nonstatic (instance) variable from a
static method. The compiler says "I have no idea which
CommonMistakes' object's x variable you're trying to print! What's running the
main() method? It's the class, not an instance of the class.
Static Method Can't Use Non-static Methods, Either
A
static method can't directly invoke a nonstatic method. So, the following code won't compile:
public class Egg
{
int size = 10;
public int getSize() {
return size;
}
public static void main(String[] args) {
System.out.println("size = " + getSize());
}
}
What do
nonstatic methods do?
They usually use instance variable state to affect the behavior of the method. The
getSize() method returns the instance variable,
size. Whose size?
The object should have been used to invoke the
getSize() method.
Static Final Variables
Static
final variables are
constants. A variable marked
final is saying that it can never change once initialized:
public static final double PI = 3.141592653589793;
- public
Any code can access it.
- static
We don't need an instance of the class.
- public
PI won't change.
There is no other way to declare a variable as a constant.
How do we initialize the
final static variable?
Final
- final primitive variable
We can't change its value.
- final reference variable
The reference variable cannot point to any other object on the heap.
- final method
We can't override the method.
- final class
We can't extend the class to make a new subclass.
Finally
Although
try and
catch provide a mechanism for trapping and handling exceptions, we are left with the problem of how to
clean up if an exception occurs.
Because execution transfers out of the
try block as soon as an exception is thrown, we can't put our cleanup code at the bottom of the
try block and expect it to be executed if an exception occurs.
A
finally block encloses code that is always executed at some point after the
try block, whether an exception was thrown or not. Even if there is a
return statement in the
try block, the
finally block executes right after the
return statement is encountered, and before the
return executes!
This is the place to close our files, release our network sockets, and perform any other cleanup.
If the
try block executes with no exceptions, the
finally block is executed immediately after the
try block completes. If there was an exception thrown, the
finally block executes immediately after the proper
catch block completes.
try {
}
catch (MyException e) {
e.printStackTrace();
}
finally {
// cleanup
}
- There is an optional finally block after the try block or after the catch block.
- The statements inside the finally block will always be executed except if JVM exits from the try block.
- The finally block is used to write the clean up code.
Does the finally block gets executed if we insert a return statement inside the try block of a try-catch-finally?
Yes, it will get executed.
The finally block gets executed when the try block exits. However,
even when we attempt to exit within the try block (normal exit, return,
continue, break or any exception), the finally block will still be
executed.
package com.bogotobogo;
public class finn
{
public static void main(String [] args)
{
System.out.println("start of main()");
System.out.println(WhatsUp());
System.out.println("end of main()");
}
public static String foo()
{
return "foo()";
}
public static String WhatsUp()
{
int denominator = 0;
int numerator = 1;
try {
System.out.println("start of try block");
double result = numerator/denominator;
return "return: end of try block";
}
catch (Exception e){
System.out.println("start of catch block");
System.out.println("Just got back from " + foo());
return "return: end of catch block";
}
finally {
System.out.println("finally block");
}
}
}
Output:
start of main()
start of try block
start of catch block
Just got back from foo()
finally block
end of catch block
end of main()
There are some cases in which the finally block will
NOT get executed.
- If the JVM exits in between try/catch block execution.
- If the thread which is executing try/catch block gets killed.
Finalize()
Java provides us a mechanism to run some code just before our object is deleted by the
garbage collector. This code is located in a method named
finalize() that all classes inherit from class
Object. However, any code that we put into our class's overridden
finalize() method is not guaranteed to run. The
finalize() method for any given object might run, but we can't count on it, so we should not put any critical code into our
finalize() method. Actually, overriding the
finalize() is discouraged.
And there are following things to remember:
- For any given object, finalize() will be called only once (at most) by the garbage collector.
- Calling finalize() can actually result in saving an object from deletion.
Comments
Post a Comment