JavaRush /Java Blog /Random EN /Java Core. Questions for an interview, part 3
Level 27

Java Core. Questions for an interview, part 3

Published in the Random EN group
In the previous two articles, we discussed some important questions that you are most often asked in interviews. It's time to move on and look at the rest of the questions.
Java Core.  Interview questions, part 3 - 1

Deep copying and shallow copying

An exact copy of the original is its clone. In Java, this means being able to create an object with a similar structure to the original object. The method clone()provides this functionality. Shallow copying copies as little information as possible. By default, cloning in Java is shallow, i.e. Object classdoesn't know about the structure of the class it's copying. When cloning, the JVM does the following:
  1. If a class only has members of primitive types, then an entirely new copy of the object will be created and a reference to that object will be returned.
  2. If a class contains not only members of primitive types, but also members of any other class type, then references to objects of these classes are copied. Therefore, both objects will have the same references.
Deep copying duplicates everything. Deep copying is two collections, one of which duplicates all the elements of the original collection. We want to make a copy such that making changes to any element of the copy will not affect the original collection. Deep cloning requires the following rules:
  1. There is no need to copy primitive data separately;
  2. All member classes in the original class must support cloning. For each class member, must be called super.clone()when the method is overridden clone();
  3. If any member of a class does not support cloning, then in the clone method, you need to create a new instance of that class and copy each of its members with all attributes to a new class object, one at a time.
Find out more about cloning here

What is synchronization? Object-level locking and class-level locking?

Synchronization refers to multithreading. A synchronized block of code can only be executed by one thread at a time. Java allows you to process multiple threads simultaneously. This may result in two or more threads wanting to access the same field. Synchronization helps avoid memory errors that occur when memory resources are used incorrectly. When a method is declared as synchronized, the thread holds its monitor. If another thread tries to access a synchronized method at this time, the thread is blocked and waits for the monitor to become free. Synchronization in Java is accomplished with the special synchronized keyword . You can mark individual blocks or methods in your class this way. The synchronized keyword cannot be used in conjunction with class variables or attributes. Object-level locking is a mechanism when you want to synchronize a non-static method or non-static block of code so that only one thread can execute the block of code on a given instance of the class. This should always be done to make the class instance thread safe. Class-level locking prevents multiple threads from entering a synchronized block for all available instances of the class. For example, if there are 100 instances of the DemoClass class, then only 1 thread will be able to execute demoMethod() using one of the variables at a given time. This should always be done to ensure static thread safety. Learn more about synchronization here.

What's the difference between sleep() and wait()?

Sleep()is a method that is used to delay the process for a few seconds. In the case of wait(), the thread is in a waiting state until we call the notify()or method notifyAll(). The main difference is that wait()it releases the monitor lock while it sleep()does not release the lock. Wait()used for multi-threaded applications, sleep()used simply to pause thread execution. Thread.sleep()puts the current thread in the "Not Runnable" state for a certain amount of time. The thread saves the state of the monitor that was before this method was called. If another thread calls t.interrupt(), the thread that “fell asleep” will wake up. Note that this sleep()is a static method, meaning that it always affects the current thread (the one executing the method sleep()). A common mistake is to call t.sleep()where tis another thread; even when the current thread that called the method sleep()is not ta thread. Object.wait()sends the current thread into the "Not Runnable" state for a while, just like sleep(), but with some nuance. Wait()called on an object, not a thread; we call this object “lock object”. Before calling lock.wait(), the current thread must be synchronized with the “lock object”; wait()after that, it releases this lock, and adds the thread to the “wait list” associated with this lock. Later, another thread can synchronize with the same lock object and call the lock.notify(). This method will "wake up" the original thread, which is still waiting. In principle, wait()/ notify()can be compared to sleep()/ interrupt(), only the active thread does not need a direct pointer to the sleeping thread, it only needs to know the shared lock object. Read the detailed difference here.

Is it possible to assign null to this to a reference variable?

No you can not. In Java, the left side of the assignment operator must be a variable. "This" is a special keyword that always gives the current instance of the class. It's not just any variable. Likewise, null cannot be assigned to a variable using the “super” keyword or any other similar keyword.

What's the difference between && and &?

&- bitwise and &&- logically.
  1. &evaluates both sides of the operation;
  2. &&evaluates the left side of the operation. If true, it continues to evaluate the right side.
Look here for a deeper understanding.

How to override equals() and hachCode() methods?

hashCode()and equals()methods are defined in the class Object, which is the parent class for Java objects. For this reason, all Java objects inherit the default implementation for methods. The method hashCode()is used to obtain a unique integer for a given object. This integer is used to determine the location of an object when that object needs to be stored, for example to HashTable. By default, hashCode()returns integera representation of the address of the memory location where the object is stored. The method equls(), as its name suggests, is used to simply test whether two objects are equal. The default implementation checks object references to see if they are equal. Below are important guidelines for reloading these methods:
  1. Always use the same object attributes when generating hashCode()and equals();
  2. Symmetry. Those. xif it returns true for some objects y x.equals(y), then it y.equals(x)should return true;
  3. Reflexivity. For any object x x.equals(x)must return true;
  4. Consistency. For any objects xand y x.equals(y)returns the same thing if the information used in comparisons does not change;
  5. Transitivity. For any objects x, yand z, if x.equals(y)it returns true and y.equals(z)returns true, then it x.equals(z)should return true;
  6. Whenever a method is called on the same object during application execution, it should return the same number unless the information used changes. hashCodecan return different values ​​for identical objects in different application instances;
  7. If two objects are equal, according to equals, then they hashCodemust return the same values;
  8. The opposite requirement is optional. Two unequal objects can return the same hashCode. However, to improve performance, it is better to have different objects return different codes.
Read interesting facts about these methods here.

Tell us about access modifiers

Java classes, fields, constructors, and methods can have one of four different access modifiers: private If a method or variable is marked private , then only code within the same class can access the variable, or call the method. Code inside subclasses cannot access a variable or method, nor can it access it from any other class. The private access modifier is most often used for constructors, methods, and variables. default The default access modifier is declared if the modifier is not specified at all. This modifier means that access to the fields, constructors and methods of a given class can be obtained by code inside the class itself, code inside classes in the same package. Subclasses cannot access methods and member variables of a superclass if they are declared as default , unless the subclass is in the same package as the superclass. protected The protected modifier works the same as default , except that subclasses can also access protected methods and variables of the superclass. This statement is true even if the subclass is not in the same package as the superclass. public The public access modifier means that all code can access the class, its variables, constructors, or methods, regardless of where that code is located. Java Core.  Questions for an interview, part 3 - 2

What is a garbage collector? Can we call him?

Garbage collection is a feature of automatic memory management in many modern programming languages, such as Java and languages ​​in the NET.Framework. Languages ​​that use garbage collection often interpret garbage collection in a virtual machine such as the JVM. Garbage collection has two purposes: any unused memory should be freed, and memory should not be freed if the program still uses it. Can you run garbage collection manually? No, System.gc()it gives you as much access as possible. The best option is to call the method System.gc(), which will hint to the garbage collector that it needs to run. There is no way to run it immediately since the garbage collector is non-deterministic. In addition, according to the documentation, OutOfMemoryErrorit will not be forwarded if the virtual machine failed to free memory after a full garbage collection. Learn more about garbage collector here.

What does the native keyword mean? Explain in detail

The native keyword is used to indicate that the method is implemented in a programming language other than a Java file. Native methods have been used in the past. In current versions of Java this is needed less often. Currently, native methods are needed when:
  1. You must call a library from Java that is written in another language.
  2. You need access to system or hardware resources that can only be accessed using another language (usually C). In fact, many system functions that interact with the real computer (such as disks or network data) can only be called by the native method.
The disadvantages of using native method libraries are also significant:
  1. JNI/JNA can destabilize the JVM, especially if you try to do something complex. If your native method does something wrong, there is a possibility of the JVM crashing. Also, bad things can happen if your native method is called from multiple threads. And so on.
  2. It is more difficult to debug a program with native code.
  3. Native code requires separate construction of frameworks, which can create problems with porting to other platforms.

What is serialization?

In computer science, in the context of data storage and transmission, serialization is the process of translating a data structure or the state of an object into a format that can be stored and later retrieved in another computing environment. After receiving a series of bits, they are recalculated according to the serialization format, and can be used to create a semantically identical clone of the original object. Java provides automatic serialization, which requires the object to implement the interface The interface implementation marks the class as "serializable". The interface does not have serialization methods, but the serializable class can optionally define methods that will be called as part of the serialization/diserialization process. When making changes to classes, you need to consider which ones will and will not be compatible with serialization. You can read the full instructions here. I will give the most important points: Incompatible changes:
  1. Delete a field;
  2. Move a class up or down in the hierarchy;
  3. Changing a non-static field to static or non-transient to transient;
  4. Changing the declared primitive data type;
  5. Changing the method WriteObjecteither ReadObjectso that they no longer write or read fields by default;
  6. Changing class Serializableto Externalizableor vice versa;
  7. Changing an enum class to a non-enum or vice versa;
  8. Removing Serializableor Externalizable;
  9. Adding writeReplacea readResolvemethod to a class.
Compatible changes:
  1. Adding fields;
  2. Adding/removing classes;
  3. Adding methods WriteObject/ReadObject[methods defaultReadObjector defaultWriteObjectmust be called at the beginning];
  4. Removing methods WriteObject/ReadObject;
  5. Addition;
  6. Changing field access;
  7. Changing a static field to non-static or transient to non-transient .
Links to previous parts: Java Core. Interview questions, part 1 Java Core. Interview questions, part 2 Original article Happy studying!