In interview questions series: part 1 and part 2 we discussed some important questions which interviewer ask most of the time. Now is the time to take that discussion forward. In this post, I will talk about below given list of questions.
Deep copy and shallow copy? What is synchronization? Class level locking and object level locking? Difference between sleep() and wait()? Can you assign null to this reference variable? What if the difference between && and &?? How to override equals and hashCode() methods? Explain all access modifiers? What is garbage collection? Can we enforce it? What is native keyword? What is serialization? Explain the catches?
Deep copy and shallow copy?
A clone is an exact copy of the original. In java, it essentially means the ability to create an object with similar state as the original object. The clone() method provides this functionality.
Shallow copies duplicate as little as possible. By default, java cloning is shallow copy or ‘field by field copy’ i.e. as the Object class does not have idea about the structure of class on which clone() method will be invoked. So, JVM when called for cloning, do following things:
1) If the class has only primitive data type members then a completely new copy of the object will be created and the reference to the new object copy will be returned.
2) If the class contains members of any class type then only the object references to those members are copied and hence the member references in both the original object as well as the cloned object refer to the same object.
Deep copies duplicate everything. A deep copy of a collection is two collections with all of the elements in the original collection duplicated. Here, we want a clone which is independent of original and making changes in clone should not affect original.
Deep cloning requires satisfaction of following rules.
- No need to separately copy primitives.
- All the member classes in original class should support cloning and in clone method of original class in context should call super.clone() on all member classes.
- If any member class does not support cloning then in clone method, one must create a new instance of that member class and copy all its attributes one by one to new member class object. This new member class object will be set in cloned object.
What is synchronization? Object level locking and class level locking?
Synchronization refers to multi-threading. A synchronized block of code can only be executed by one thread at a time. Java supports multiple threads to be executed. This may cause two or more threads to access the same fields or objects. Synchronization is a process which keeps all concurrent threads in execution to be in synch. Synchronization avoids memory consistence errors caused due to inconsistent view of shared memory. When a method is declared as synchronized; the thread holds the monitor for that method’s object If another thread is executing the synchronized method, your thread is blocked until that thread releases the monitor.
Synchronization in java is achieved using synchronized keyword. You can use synchronized keyword in your class on defined methods or blocks. Keyword can not be used with variables or attributes in class definition.
Object level locking is mechanism when you want to synchronize a non-static method or non-static code block such that only one thread will be able to execute the code block on given instance of the class. This should always be done to make instance level data thread safe.
Class level locking prevents multiple threads to enter in synchronized block in any of all available instances on runtime. This means if in runtime there are 100 instances of DemoClass, then only one thread will be able to execute demoMethod() in any one of instance at a time, and all other instances will be locked for other threads. This should always be done to make static data thread safe.
Difference between sleep() and wait()?
sleep() is a method which is used to hold the process for few seconds or the time you wanted but in case of wait() method thread goes in waiting state and it won’t come back automatically until we call the notify() or notifyAll().
The major difference is that wait() releases the lock or monitor while sleep() doesn’t releases any lock or monitor while waiting. Wait is used for inter-thread communication while sleep is used to introduce pause on execution, generally.
Thread.sleep() sends the current thread into the “Not Runnable” state for some amount of time. The thread keeps the monitors it has aquired — i.e. if the thread is currently in a synchronized block or method no other thread can enter this block or method. If another thread calls t.interrupt() it will wake up the sleeping thread. Note that sleep is a static method, which means that it always affects the current thread (the one that is executing the sleep method). A common mistake is to call t.sleep() where t is a different thread; even then, it is the current thread that will sleep, not the t thread.
object.wait() sends the current thread into the “Not Runnable” state, like sleep(), but with a twist. Wait is called on a object, not a thread; we call this object the “lock object.” Before lock.wait() is called, the current thread must synchronize on the lock object; wait() then releases this lock, and adds the thread to the “wait list” associated with the lock. Later, another thread can synchronize on the same lock object and call lock.notify(). This wakes up the original, waiting thread. Basically, wait()/notify() is like sleep()/interrupt(), only the active thread does not need a direct pointer to the sleeping thread, but only to the shared lock object.
Can you assign null to this reference variable?
NO. You can’t. In java, left hand side of an assignment statement must be a variable. ‘this’ is a special keyword which represent the current instance always. This is not any variable.
Similarly, null can not be assigned to ‘super’ or any such keyword for that matter.
What if the difference between && and &??
& is bitwise and && is logical.
- & evaluates both sides of the operation.
- && evaluates the left side of the operation, if it’s true, it continues and evaluates the right side.
How to override equals and hashCode() methods?
hashCode() and equals() methods have been defined in Object class which is parent class for java objects. For this reason, all java objects inherit a default implementation of these methods.
hashCode() method is used to get a unique integer for given object. This integer is used for determining the bucket location, when this object needs to be stored in some HashTable like data structure. By default, Object’s hashCode() method returns and integer representation of memory address where object is stored.
equals() method, as name suggest, is used to simply verify the equality of two objects. Default implementation simply check the object references of two objects to verify their equality.
Below are the important points to keep remember while overriding these functions.
- Always use same attributes of an object to generate hashCode() and equals() both. As in our case, we have used employee id.
- equals() must be consistent (if the objects are not modified, then it must keep returning the same value).
- Whenever a.equals(b), then a.hashCode() must be same as b.hashCode().
- If you override one, then you should override the other.
Explain all access modifiers?
Java classes, fields, constructors and methods can have one of four different access modifiers:
If a method or variable is marked as private, then only code inside the same class can access the variable, or call the method. Code inside subclasses cannot access the variable or method, nor can code from any external class.
If a class is marked as private then no external class an access the class. This doesn’t really make so much sense for classes though. Therefore, the access modifier private is mostly used for fields, constructors and methods.
The default access level is declared by not writing any access modifier at all. Default access levels means that code inside the class itself + code inside classes in the same package as this class, can access the class, field, constructor or method. Therefore, the default access modifier is also sometimes called a package access modifier.
Subclasses cannot access methods and member variables in the superclass, if they have default accessibility declared, unless the subclass is located in the same package as the superclass.
The protected acces modifier does the same as the default access, except subclasses can also access protected methods and member variables of the superclass. This is true even if the subclass is not located in the same package as the superclass.
The public access modifier means that all code can access the class, field, constructor or method, regardless of where the accessing code is located.
|Modifiers||Same Class||Same Package||Subclass||Other packages|
What is garbage collection? Can we enforce it?
Garbage collection is an automatic memory management feature in many modern programming languages, such as Java and languages in the .NET framework. Languages that use garbage collection are often interpreted or run within a virtual machine like the JVM. In each case, the environment that runs the code is also responsible for garbage collection. A GC has two goals: any unused memory should be freed, and no memory should be freed unless the program will not use it anymore.
Can you force garbage collection?? Nope, System.gc() is as close as you can get. Your best option is to call System.gc() which simply is a hint to the garbage collector that you want it to do a collection. There is no way to force and immediate collection though as the garbage collector is non-deterministic. Also, under the documentation for OutOfMemoryError it declares that it will not be thrown unless the VM has failed to reclaim memory following a full garbage collection. So if you keep allocating memory until you get the error, you will have already forced a full garbage collection.
What is native keyword? Explain in detail?
The native keyword is applied to a method to indicate that the method is implemented in native code using JNI. It marks a method, that it will be implemented in other languages, not in Java.
Native methods were used in the past to write performance critical sections but with Java getting faster this is now less common. Native methods are currently needed when
- You need to call a library from Java that is written in other language.
- You need to access system or hardware resources that are only reachable from the other language (typically C). Actually, many system functions that interact with real computer (disk and network IO, for instance) can only do this because they call native code.
The downsides of using native code libraries are also significant:
- JNI / JNA have a tendency to destabilize the JVM, especially if you try to do something complicated. If your native code gets native code memory management wrong, there’s a chance that you will crash the JVM. If your native code is non-reentrant and gets called from more than one Java thread, bad things will happen … sporadically. And so on.
- Java with native code is harder to debug than pure Java or pure C/C++.
- Native code can introduce significant platform dependencies / issues for an otherwise platform independent Java app.
- Native code requires a separate build framework, and that may have platform / portability issues as well.
What is serialization? Explain the catches?
In computer science, in the context of data storage and transmission, serialization is the process of translating data structures or object state into a format that can be stored and “resurrected” later in the same or another computer environment. When the resulting series of bits is reread according to the serialization format, it can be used to create a semantically identical clone of the original object.
Java provides automatic serialization which requires that the object be marked by implementing the java.io.Serializable interface. Implementing the interface marks the class as “okay to serialize,” and Java then handles serialization internally. There are no serialization methods defined on the Serializable interface, but a serializable class can optionally define methods with certain special names and signatures that if defined, will be called as part of the serialization/deserialization process.
Once an object is serialized, changes in its class break the de-serialization process. To identify the future changes in your class which will be compatible and others which will prove incompatible, please read the full guide here. In short, I am listing down here:
- Deleting fields
- Moving classes up or down the hierarchy
- Changing a non-static field to static or a non-transient field to transient
- Changing the declared type of a primitive field
- Changing the writeObject or readObject method so that it no longer writes or reads the default field data
- Changing a class from Serializable to Externalizable or vice-versa
- Changing a class from a non-enum type to an enum type or vice versa
- Removing either Serializable or Externalizable
- Adding the writeReplace or readResolve method to a class
- Adding fields
- Adding/ Removing classes
- Adding writeObject/readObject methods [defaultReadObject or defaultWriteObject should be called first]
- Removing writeObject/readObject methods
- Adding java.io.Serializable
- Changing the access to a field
- Changing a field from static to non-static or transient to non transient
Happy Learning !!