Question: Can You Override Static Methods in Java?
Question: Can You Override Static Methods in Java?
Answer: Well... the answer is NO if you think from the perspective of how an overriden method should
behave in Java. But, you don't get any compiler error if you try to override a static method. That means,
if you try to override, Java doesn't stop you doing that; but you certainly don't get the same effect as
you get for non-static methods. Overriding in Java simply means that the particular method would be
called based on the run time type of the object and not on the compile time type of it (which is the case
with overriden static methods). Okay... any guesses for the reason why do they behave strangely?
Because they are class methods and hence access to them is always resolved during compile time only
using the compile time type information. Accessing them using object references is just an extra liberty
given by the designers of Java and we should certainly not think of stopping that practice only when they
restrict it :-)
Example: let's try to see what happens if we try overriding a static method:-
class SuperClass{
......
......
......
}
......
......
superClassWithSuperCons.staticMethod();
superClassWithSubCons.staticMethod();
subClassWithSubCons.staticMethod();
...
Output:-
Notice the second line of the output. Had the staticMethod been overriden this line should have been
identical to the third line as we're invoking the 'staticMethod()' on an object of Runtime Type as
'SubClass' and not as 'SuperClass'. This confirms that the static methods are always resolved using their
compile time type information only.
http://geekexplains.blogspot.com/2008/05/archives-from-category-java-9.html
A thread problem - what will 'threadObject = null' do for an active thread?
package test;
public class Thread1 extends Thread{
public void run() {
int counter = 0;
while(true){counter++;
System.out.println("Inside Thread1 - " + counter);}
}
}
package test;
public class Class2 {
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
thread1.start();
thread1 = null;
}
}
What will be the output when Class2 is run? 'thread1 = null' - what will this do?
Outout:
Inside Thread1 - 1
Inside Thread1 - 2
Inside Thread1 - 3
....
..... till the stack overflow occurs or till you forcibly terminate :-)
Did you anticipate anything else? Except the statement 'thread1 = null', everything else is pretty
straightforward - the main() method will start the execution in the 'main' thread and during the
execution, it'll create a new thread 'thread1', which will start its execution in a separate thread of
execution. The 'main' thread being the parent thread will keep waiting for the child thread 'thread1' to
finish its execution and only then the 'main' thread will exit. The child thread 'thread1' is running an
infinite loop in its run() method, so it'll keep executiing unless it's forcibly terminated either by user's
intervention OR may be due to stack overflow.
Okay... so if we include the statement 'thread1 = null' then why do you expect something else to
happen? Maybe because you think that assigning 'null' to an object will simply make that object eligible
for garbage collection (as in this case thread1 will have no other active references) and hence the
thread should stop execution. Well... threads don't get terminated that way.
In Java, the JVM continues executing a thread until either of the following three occurs:-
Runtime.exit() method (or its equivalent System.exit() method) is called and the
underlying Security Manager has permitted the method to execute. This invokes the JVM
Shutdown Sequence (Read More in this article - JVM Shutdown Sequence >>) which eventually
halts the entire JVM process (the thread under execution will just be a part of this process).
Runtime.halt() method is called and the underlying Security Manager is okay with the call.
This abruptly and immediately halts the entire JVM process.
The thread under execution has returned from its run() method either by completing the
execution of this method OR by thowing an uncaught exception which propagates beyond the
run() method. A parent thread can return only when all of its child threads have already
returned.
Now we can easily understand that 'thread1 = null' statement will not terminate the thread and the
main thread will keep executing and eventually keep waiting (as thread1 is in infinite loop) for any of
the above three cases to occur for the thread1 to terminate and after that the 'main' thread will also
get terminated. In our example, we're not explicitly calling Runtime.exit() or Runtime.halt(), so
they may be called only if we log off the machine or shut it down. Otherwise, only third case will cause
the thread to terminate. run() being in an infinite loop will never complete its execution, so only an
uncaught exception can terminate this thread. This uncaught exception can be either due to stack
overflow OR may be due to some user intervention. Thus, we can say that having 'thread1 = null' will
not at all affect the execution of any of the threads. The output will remain the same with without
having this statement as well.
CLONING
Answer: clone() method has 'protected' access in the class java.lang.Object and we normally
override this method and promote the access to 'public' for the overriden method. We do this even in
the case we are interested in using the default cloning (Shallow Copy) functionality only; otherwise we'll
get a compile time error if we try to call this method from outside. Read more about this in this article -
clone() not accessible from outside >>
This 'protected' to 'public' access promotion will ensure that all the subclasses of this class will
inherit this 'public' clone() method even though they may not need it (and hence they will not bother
about overriding the inherited clone() method for its suitability in the particular sub class). If these
subclasses (or their subclasses, and so on) don't add any non-primitive member then it'll hardly affect us
otherwise the usage of the inherited clone() method on that subclass instance will result in Shallow
Copy even if the original clone() was written for implementing Deep Copy.
Shallow Copy
This is a result of the default cloning functionality provided by the Object.clone() method if the class has
non-primitive data type members as well. Shallow Copy concept is not applicable to the classes having
only primitive data type members as in that case the default cloning will also result into a Deep Copy
only.
In case of Shallow Copy, the cloned object also refers to the same object to which the original object
refers as only the object references gets copied and not the referred objects themselves. That's why the
name Shallow Copy. Read more about Cloning and see the memory diagram to understand it better -
Cloning in Java >>
Deep Copy
We need to override the clone() method for the classes having non-primitive type members to achieve
Deep Copy as Deep Copy requires the member objects to be cloned as well, which is not done by the
default cloning mechanism. Why is it not done by the default cloning? Because clone() is a method of the
Object class and at that level it's not known what a typical class can have as its members and hence only
a field-by-field copy approach has been provided as the default cloning mechanism.
For Deep Copy, we need to ensure that the member classes also implement the Cloneable interface
otherwise calling the clone() method on the objects of those classes will result into
CloneNotSupportedException. So, to implement Deep Copy, we first need to ensure that all the member
classes (at all the levels - like if the member class itself has a member of some class type then that class
as well... and so on) are implementing the Cloneable interface. After that we override the clone()
method in all those classes (even in the classes where we have only primitive type members otherwise
we would not be able to call the protected clone()method of Object class on the instances of those
classes inside some other class ... a typical restriction of the protected access. We'll cover this in a
separate article) and finally calling clone() method on the object members in the overriden clone()
method definition.
Answer: clone() is defined as a protected method in the Object class. When we implement the
marker interface Cloneable then only that class gets the license to call the default Object.clone()
method i.e., only the methods of that implementing class can call the inherited clone() method. The
Object.clone() method carries a protected access, so even if we want the default clone() (Shallow
Copy) to be called from outside, we need to override the clone() method in the class implementing
Cleanble and promote the access specifier of the overriden clone() method to 'public'.
...
...
...
sampleACloned = sampleA.clone();
...
'sampleACloned = sampleA.clone();' - this statement is valid in this case as we have overriden the
clone() method with a 'public' access specifier in the class SampleA. Otherwise, it'll throw a
compile-time error "method clone() has protected access in class java.lang.Object'.
Cloneable interface
Class A {
...
}
A objA = new A();
A objACloned = (A) objA.clone();
Now, objA != objACloned - this boolean expression will always be true as in any case a new object
reference will be created for the cloned copy.
Initially, objA.equals(objACloned) will return true, but any changes to any primitive data type
member of any of the objects will cause the expression to return false. It's interesting to note here
that any changes to the members of the object referenced by a member of these objects will not cause
the expression to return false. Reason being, both the copies are referring to same object as only the
object references get copied and not the object themselves. This type of copy is called Shallow Copy
(Read Next - Deep Copy vs Shallow Copy >> You may browse the links given in that article to go through
various aspects of Cloning in Java). This can be understood easily by looking at the following memory
diagram:-
Liked the article? You may like to Subscribe to this blog for regular updates. You may also like to follow
the blog to manage the bookmark easily and to tell the world that you enjoy GeekExplains. You can find
the 'Followers' widget in the rightmost sidebar.
Well... there aren't many different ways I suppose. But from an application programmer perspective here
are the different possible ways of creating objects in Java:-
Using new operator - the most commonly used way by far. 'new' is an operator and the only
operand it requires is a constructor which will be used for initializting the newly created
instance. 'new' operator allocates the memory space and initializes the fields with their default
values. Then it executes the code inside the specified constrcutor which normally re-writes the
default values of some (or all) fields with the particular values mentioned in the constructor
definition.
Using clone() method - Cloning (Shallow or Deep) makes a new copy of the specified object.
It doesn't call the 'new' operator internally. Object.clone() is a native method which
translates into instructions for allocating the memory and copying the data. Remember that
even if we override the clone() method either to implement Deep Cloning or to make the
clone() method as 'public' but then also we keep the line super.clone() inside the
overriden definition which ultimately calls Object.clone() method only. You might wonder
about what the 'new' operator actually translates into and how this approach is different from
that. Okay... we all know that 'new' does three tasks - allocating the memory, initializing the
fields with default values, and calling the specified constructor. Now the first task is same in
both the approaches and there would probably be the same native allocator being used in both
the cases. But in case of Cloning, the allocated memory is not initialized with default values and
also no constructor is called in this case. Only a datacopy instruction will be executed which
copies the data from the original object to the cloned object. Read more about Cloing in this
article - Cloning in Java >>
Using De-Serialization - this can be thought of another different way of creating an object in
Java. Again you might wonder that this internally uses 'new' operator only so why to consider
this as a new way. Yeah... you're right. It does uses the 'new' operator internally and always calls
the default constructor. But two noticeable differences between the two approaches are:- In
case of an explict 'new' call we may specify any constructor which is not the case here. It'll
always invoke the default constructor. Another difference is that in this case the newly created
object is initialized (or better to say re-written as the implicit 'new' call with default constructor
would have already initialized the object first with the default value and then with the specified
value in the default constructor) with the data from the Input Stream fetched usually from a
persistent medium. This step is obviously not involved in an explicit 'new' call.
Using Class.forName() and newInstance() - A calss can be dynamically loaded using the
Class.formName() method. This method has two variants - one which accepts only a String
type parameter which is the qualifies name of the class to be loaded and the other variant
expects three parameters - the String type qualifies class name, boolean type flag to specify
if the class should be initialized, and the ClassLoader name which should be used to load the
class. The former variant also internally calls the three-parameter variant only by assuming the
boolean flag as 'true' and the ClassLoader as returned by the getClassLoader() method.
That means 'Class.forName("qualified.ClassName")' is internally translated into
'Class.forName("qualifies.ClassName", true,
this.getClass().getClassLoader())'. Once the class has been loaded then a call of the
method newInstance() on the loaded Class object will first check if the Class object is
initialized or not and if not then it will initialize the Class object and create a new object as if
the 'new' operator has been called with the default constructor of the class under consideration.
Again you may argue how is this different from an explicit 'new' call and it won't take much of an
effort to identify the most obvious difference between the two as the inability of this approach
to call any other constructor except the default constructor. Another difference is that the
newInstance() call may throw a SecurityException as well because it checks if a Security
Manager is installed or not and if it finds a security manager then it checks for access to the
class as wellas to the package (if any package specified in the qualified name). Either of two
checks may throw a SecurityException. This step is obviously not involved with an explicit
'new' call. Another slightly different way of object creation is by using the loadClass()
method of the ClassLoader class which returns a Class object of the specified class and then
on the returned Class object we may call newInstance() method to create a new object.
I've not put this as a completely separate way because I think Class.forName() method also
internally calls this method only - either for the explcitly supplied ClassLoader or for the
implcitily obtained ClassLoader as discussed above. What's the difference between the two
approaches then? The only difference which I can see is that the former checks for the access to
the class (and package) and hence it may throw SecurityException if a Security Manager is
installed. But the latter doesn't do these checks and hence doesn't throw SecurityException.
It's normally advised not to call the loadClass() method directly as almost always you can call
Class.forName() by supplying the particular ClassLoader reference.
Is there any other different way of creating objects in Java? I don't think that there is any other way.
Using JNI may pop up as another possible way, but I don't think that JNI offers any different way of
object creation due to the fact that JNI is not meant for object creation instead it's used for interacting
with native methods written in some other languages (mainly in C/C++) and hence a Java class using JNI
code is same as any other Java from object creation perspective. Therefore, I think it uses any one of
the above mentioned approaches only - most commnonly the explicit 'new' calls. I personally don't have
much exposure to JNI and I sincerely welcome comments from the JNI experts if they think otherwise.