
- I will skip the questions that overlap with this series of articles in order to not unnecessarily duplicate information. I recommend reading these articles as they cover the most common (popular) Java Core interview questions.
- I could describe the answers in more detail, but I won't, because then each answer could drag on for the whole article. And nobody will ask you for that level of detail in any job interview.
11. Name all of the methods of the Object class
The Object class has 11 methods:Class<?> getClass() — get the class of the current object;
int hashCode() — get the hash code of the current object;
boolean equals(Object obj) — compare the current object with another object;
Object clone() — create and return a copy of the current object;
String toString() — get the string representation of the object;
void notify() — wake up one thread waiting on this object's monitor (the choice of thread is random);
void notifyAll() — wake up all threads waiting on this object's monitor;
void wait() — make the current thread wait on the current monitor (freeze the current thread) until a notify or notifyAll call wakes up the thread (only works in a synchronized block);
void wait(long timeout) — make the current thread wait on the current monitor (on the current synchronized block), but with a timeout for exiting the waiting state (or again, until a notify or notifyAll call wakes up the thread);
void wait(long timeout, int nanos) — this method is like the previous method, but with a more precise timeout;
void finalize() — this method is called (finally) before the object is removed by the garbage collector. It is used to clean up acquired resources.
12. What is the difference between try-with-resources and try-catch-finally when working with resources?
Typically, when using try-catch-finally, the final block is used to close resources. Java 7 introduces the new try-with-resources statement. It is analogous to try-catch-finally for freeing resources, but more compact and readable. Let's recall what try-catch-finally looks like:
String text = "some text......";
BufferedWriter bufferedWriter = null;
try {
bufferedWriter = new BufferedWriter(new FileWriter("someFileName"));
bufferedWriter.write(text);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Now let's rewrite this code, but using try-with-resources:
String text = "some text......";
try(BufferedWriter bufferedWriter =new BufferedWriter(new FileWriter("someFileName"))) {
bufferedWriter.write(text);
} catch (IOException e) {
e.printStackTrace();
}
Now that's somehow simpler, don't you think? In addition to the simpler code, there are a couple of other points to note:In try-with-resources, the resources declared in the parentheses (resources that will be closed) must implement the AutoCloseable interface and its sole close() method.
The close method is executed in an implicit finally block, otherwise, how would the program figure out exactly how to close the resource?
But you will probably rarely write your own implementations of resources and their closing method.
Blocks are executed in this order:
- The try block.
- The implicit finally block.
- The catch block, which catches exceptions that occur in the previous steps.
- The explicit finally block.
As a rule, the exceptions thrown lower in the list interrupt those thrown higher up.
13. What are bitwise operations?
Bitwise operations are operations on sequences of bits. They include logical operations and bitwise shifts. Logical operators:bitwise AND — Compares bit values. Any bit set to 0 (false) sets the corresponding bit in the result to 0. That is, if a bit is 1 (true) in both of the compared values, then the resulting bit will also be 1.
Denoted as AND or &
Example: 10111101 & 01100111 = 00100101
bitwise OR — This operation is the opposite of the previous one. Any bit set to 1 sets the corresponding bit in the result to 1. Accordingly, if the bit is 0 in both compared values, then the resulting bit will also be 0.
Denoted as OR or |
Example: 10100101 | 01100011 = 11100111
bitwise NOT — This operator is applied to a single value. It flips (inverts) the bits. That is, the bits that were 1 become 0; and those that were 0 become 1.
Denoted as NOT or ~
Example: ~10100101 = 01011010
bitwise exclusive OR — Compares bit values. If both bits are 1, then the resulting bit is 0. If both bits are 0, then the resulting bit is 0. In other words, in order for the resulting bit to be 1, just one of the bits must be 1, and the other bit must be 0.
Denoted as XOR or ^
Example: 10100101 ^ 01100011 = 11000110
- 01100011 >> 4 = 00000110
- 01100011 << 3 = 00011000


14. What standard immutable objects are there in Java?
An object is immutable if it does not allow its original values to change. It may have methods that return new objects of the same type with different values. Some standard immutable objects include:- undoubtedly, Java's most famous immutable type is String;
- instances of the wrapper classes that wrap standard types: Boolean, Character, Byte, Short, Integer, Long, Double, Float;
- BigInteger and BigDecimal objects, which are usually used for especially BIG numbers;
- StackTraceElement objects that make up a stack trace (for example, the stack trace of an exception);
- an object of the File class — it can modify files, but at the same time the object itself remains unchanged;
- UUIDs, which are often used to uniquely identify elements;
- all objects of classes in the java.time package;
- Locale objects, which are used to identify a geographic, political, or cultural region.
15. What are the advantages of immutable object over ordinary objects?
Immutable objects are safe to use in a multithreaded environment. They make it so you don't have to worry about data loss due to race conditions. This is different than when you're working with ordinary objects. In that case, you have to think and come up with good mechanisms when using the object in a parallel environment.
Immutable objects are good as keys in a map. If you use a mutable object as a HashMap key and then the object's state changes, then the data structure could get confused: the object will still be present, but if you use containsKey(), you might not find it.
Immutable objects are great for storing immutable (constant) data that should never be changed while the program is running.
Another advantage is failure atomicity. If an immutable object throws an exception, it will not be left in an unwanted (broken) state.
These classes are easy to test.
You don't need any additional mechanisms such as a copy constructor or implementation of object cloning.
Questions about OOP
16. What are the advantages of OOP in general and in comparison with procedural programming?
Okay, advantages of OOP:Complex applications are easier to write using OOP than procedural programming since everything is broken down into small modules — objects that interact with each other — and as a result, programming is reduced to relationships between objects.
Applications written with OOP are much easier to modify (when design principles are properly observed).
Since both the data and data operations form a single entity, they are not smeared all over the application (which is often the case in procedural programming).
The principle of encapsulation protects the most critical data from the user.
The same code can be reused with different data because classes let you create many objects, each with its own values.
Inheritance and polymorphism also let you reuse and extend existing code (instead of duplicating similar functionality).
Extending an application is simpler than with a procedural approach.
The OOP approach makes it possible to abstract away implementation details.
17. Tell us what disadvantages OOP has
Unfortunately, they also exist:OOP requires a lot of theoretical knowledge that must be mastered before you can write anything.
OOP ideas are not so easy to understand and apply in practice (you need to be a little philosopher at heart).
OOP reduces a program's performance slightly due to the increased complexity of the system.
The OOP approach requires more memory since everything consists of classes, interfaces, methods, which take up much more memory than ordinary variables.
The time required for the initial analysis is greater than for a procedural approach.
18. What is static polymorphism versus dynamic polymorphism?
Polymorphism allows objects of the same class or interface to behave differently. There are two types of polymorphism, which are also known as early and late binding. Static polymorphism, or early binding:- occurs at compile time (early in the program's life cycle);
- decides which method to execute at compile time;
- method overloading is an example of static polymorphism;
- early binding includes private, static, and final methods;
- inheritance is not involved in early binding;
- static polymorphism does not involve specific objects, but rather information about the class type that appears to the left of a variable name.
- occurs at runtime (while the program is running);
- dynamic polymorphism decides which specific implementation a method will have at runtime;
- method overriding is an example of dynamic polymorphism;
- late binding means assigning a specific object, a reference of its type, or its superclass;
- inheritance is associated with dynamic polymorphism.
19. Provide a definition of the principle of abstraction in OOP
In OOP, abstraction is a way to isolate a set of meaningful characteristics of an object, while excluding insignificant details. That is, when designing a program with an OOP approach, you focus on general models, without going into the details of their implementation. In Java, abstraction is realized through interfaces. For example, you have a car and that will be an interface. And the various interactions with it — for example, starting the engine, shifting gears — are functions, which we use without delving into implementation details. Indeed, when you're driving, you don't think about exactly how the gearbox fulfills its purpose, or how the key starts the engine, or how exactly the steering wheel turns the wheels. And if you replace the implementation of some functionality (for example, the engine), you might not even notice it. It doesn't matter to you: you don't delve into the implementation details. What matters to you is that the action is carried out. In essence, this abstracting away implementation details. At this point, we will stop today: to be continued!
GO TO FULL VERSION