Hi!
Just as it is impossible to learn how to fly an airplane without special training, you cannot become a Java developer without spending long hours studying the necessary theoretical foundations.
And that is precisely what we'll work on today: we will continue to explore questions encountered during job interviews for Java developers, and, of course, we'll look at the answers.
Here are the first and second parts of this overview.
There is no doubt you can become a good Java developer without all these questions. That said, if you have a good understanding of all of Java's intricacies, you will definitely have an advantage and will look more appealing in the eyes of your future employer.
20. What elements of the language enable encapsulation?
Let's recall that encapsulation is about hiding the implementation details of a class. In other words, when our class is used, its innards and internal logic are not obvious to outsiders. And what elements of the language are responsible for this? Access modifiers, of course! Anything we need to hide, we mark with the private modifier. For example, a class's private fields or some internal methods that help implement some internal functionality. And for anything that we want to provide external access to, we add the public access modifier. For example, a method that implements some functionality (that may internally use many private methods) or, of course, getters and setters for accessing a class's private fields. We have not yet mentioned the default and protected modifiers, which can be used more flexibly and specifically customize access to certain class parts.21. What elements of the language enable inheritance?
Inheritance is a mechanism that allows you to create classes based on another class. Java has the extends keyword for this. For example, suppose we have a Cat class, and we want to create a Lion child class. In code, it will look something like this:
public class Lion extends Cat
And this means that the Lion class inherits all the methods and variables of the Cat class, except for static variables.
Another element of the language that is responsible for inheritance is super. It is a reference similar to this. The this keyword refers to the object in which it is referenced. The super keyword refers to the parent of the current object.
Typically super is used:To call the constructor of a superclass. For example, the Cat class has an internal name variable that must be initialized in the constructor. In the Lion class constructor, that will look like this:
public Lion(final String name) { super(name); }
To refer to the fields and methods of the parent. For example, in the Cat class, we have an initialized age field:
public class Cat { int age = 10;
public class Lion extends Cat {
int age = 15;
And if in a Lion object we want to refer to the age variable of the parent object, then we have to do it through super:
super.name
22. What elements of the language are responsible for polymorphism?
Polymorphism is the ability of an object with one signature to take many forms (many implementations). We can confidently state that Java's implements and extends keywords are responsible for polymorphism. When we have an interface, implements allows us to provide one possible implementation, but that doesn't have to be the only implementation, does it? Let's revisit what it looks like to use implements:
public class Cat implements Animal
Then in the Cat class, we have to implement all the abstract methods in the Animal interface.
Inheritance as well: in the child class, we can override a method's existing implementation. This means that with multiple child classes, we can have several different overrides of the same method.
Or a superclass can be abstract and have a certain method that must be implemented in a special way in each of its child classes. In other words, this method will have many different implementations.
The @Override annotation can also help us with this. It is placed above the implemented methods and indicates that we want to implement or override (if an implementation already exists in the superclass) a particular method of a superclass or interface.
It is optional and helps detect errors more easily. You use this annotation to tell the compiler that you want to override/implement the superclass/interface method. The compiler will then make sure that you don't make mistakes in the method signature.
23. What is SOLID? Provide examples
SOLID is an acronym for Robert Martin's five basic OOP design principles. S (Single-responsibility principle): states that a class should have only one purpose/responsibility. In other words, you shouldn't create classes that do everything. If you do, you may reproduce the "God Object" anti-pattern. If you have a Cat object, it should have methods only for interacting with its internal functionality, but it should not contain any business logic unrelated to that instance. For example, some mechanism for storing objects of this type. This functionality (external to the entity of a Cat) should be moved to other classes or services, whose task is to provide the business logic for the corresponding objects. O (Open-closed principle): This principle is described as follows: software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. For example, suppose we need functionality similar to but slightly different from the functionality of our existing Cat class. Instead of changing the functionality of the Cat class and thereby breaking the code everywhere it is already used, we can use inheritance or composition. Thus, we achieve our goal of modifying the functionality of the Cat class, and we do so without changing the class itself and without breaking anything. L (Liskov Substitution Principle): this is Barbara Liskov's substitution principle. The principle says that a function that takes a base type should be able to use subtypes of that base type without knowing what is happening. For example, our Cat class should be replaceable by any of its descendants, say, Lion, without fundamentally changing its behavior. The general logic (behavior) remains the same, but the implementation details of specific functionality change. I (Interface segregation principle): this principle states that it is better to have many specialized (narrowly focused) interfaces than one universal one. For example, suppose a developer implements some interface. They only need one of its methods, but the interface has nine more methods that do not relate to the logic of the required method. In this case, the developer will need to implement ten interface methods, nine of which are superfluous for them! Instead, it's better to make ten different interfaces that you can implement as needed. Well, if not ten, then several, each with methods closely related to the single purpose of the interface. D (Dependency inversion principle): The principle says that higher-level modules should not depend on lower-level modules. This principle also states, "Abstraction should not depend on details. Details should depend on abstractions." We must build our logic by referring to interfaces and pass around concrete objects of classes that implement the required interface. For example, suppose we have a Cat interface and some implementations, say, Lion and HouseCat. We build our logic specifically to interact with the Cat interface. We only then substitute the interface with a specific implementation (Lion or HouseCat), but not the other way around.24. What is a class, object, and interface?
We will recall that Java is an OOP language. That is, Java programs are built based on the interactions between objects. A program is like an anthill, where each ant is an object. Objects are collections of data that include various methods (functions) for interacting with this internal data. Classes are instructions or templates for creating objects. This means that we can have many objects built according to the same instructions but filled with different (or the same) data. Taking an example from real life, we can say that a class is a blueprint of a building, and an object is a building constructed specifically according to the blueprint. Interfaces are similar to classes, but we cannot use them to create objects. Their purpose is to add abstraction to Java. More precisely, they add flexibility to the relationship between classes and objects. By flexibility, we mean the polymorphism and abstraction previously described, which creates many opportunities for building an application's internal architecture.25. What is a POJO class? Give an example of such a class
A POJO (Plain Old Java Object) is a simple class object that does not inherit from any specific class and does not implement any service interfaces beyond those needed for the business model. In other words, a POJO class is just a class with no special requirements. The only requirement is the absence of various bells and whistles tied to a specific framework. As a rule, these classes do not inherit other classes (except for POJO classes in the same package), do not implement interfaces (sometimes an exception is made for marker interfaces from the standard library such as Serializable or Cloneable), do not use annotations, and do not depend on third party libraries. Let's note that a POJO can have methods containing business logic and constructors of any kind. If we allow annotations that do not change the semantics of the class (i.e. annotations whose absence does not change the purpose or logic of the object), then POJOs can also include JPA entities and DTO objects deserialized from XML or JSON, whose rules are specified in annotations. Another thing to keep in mind regarding POJO classes is that it is good to override their equals and hashCode methods because this can help them fulfill their role better. Example of a POJO class:
public class User {
private Long id;
private String firstName;
private String lastName;
private Long age;
public User(final Long id, final String firstName, final String lastName, final long age) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
public Long getId() {
return this.id;
}
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
public Long getAge() {
return this.age;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || this.getClass() != o.getClass()) return false;
final User user = (User) o;
return Objects.equals(this.id, user.id) &&
Objects.equals(this.firstName, user.firstName) &&
Objects.equals(this.lastName, user.lastName) &&
Objects.equals(this.age, user.age);
}
@Override
public int hashCode() {
return Objects.hash(this.id, this.firstName, this.lastName, this.age);
}
}
26. What elements can a class contain?
A class can contain the following elements:- instance fields;
- static fields;
- an initialization block;
- a static initialization block;
- constructors (an empty constructor is always declared by default);
- methods;
- static methods;
- various annotations (which can be applied to the class itself or its constituent parts);
- generics;
- inheritance of other classes (extends) or implementations of interfaces (implements).
27. Tell us about inheritance in Java. What are the specifics of the super keyword?
Above, I previously talked about inheritance and the super keyword in Java. I will mention a few more important points:- We can inherit only a single class: Java has no multiple inheritance in Java. With the advent of default methods in Java 8, this statement will become very controversial.
- Private methods and fields are also inherited. They simply cannot be accessed from the child class (but if we, for example, have a private field and have public or protected getters and setters, then we can use them to access the field).
- final classes cannot be inherited.
- final methods cannot be overridden (but they can be inherited and overloaded).
- static methods and variables are not inherited (because they are attached to classes, not objects).
- When inheriting abstract classes, their abstract methods must be implemented, or the child class must also be declared abstract.
- If there are non-default constructors in the parent, they must be overridden in the child class (but @Override is not written above them).
- You can extend the access modifier to overridden methods in the child class: private -> default -> protected -> public. Methods that are overridden in the child class can throw narrower exceptions, for example: Exception -> IOException -> FileNotFoundException.
28. What are method signatures? Provide examples of correct and incorrect signatures
A method signature is the name of the method plus the types of the input parameters (the order of the parameters matters). The method signature does not include the return value or the exceptions the method throws. Example of a correct signature:
doSomething(int, double, double)
Example of an incorrect signature:
void doSomething(int firstArg, int secondArg) throws Exception
The method signature, combined with the return type and the list of exceptions thrown, is called the method contract.
That's all for today! See you later!
GO TO FULL VERSION