Software Engineer Interview Questions to Know (Entry Level) — Principles of OOP
If you’ve just stumbled onto this series, make sure to check out the introduction here.
Question 1: Explain the four key principles of object-oriented programming.
Variants
- What is A-PIE?
- What is the difference between an abstract class and an interface?
- What is the difference between method overriding and method overloading?
- Does Java support multiple inheritance? Why or why not?
- What are getter and setter methods? Why are they used?
- Describe one principle of object-oriented programming and describe a scenario in which this principle would be helpful in the development of code.
What They’re Really Asking
- Do you have a thorough understanding of object-oriented programming? Have you taken classes in data structures, algorithms, or algorithm design?
- Can you explain technical concepts accurately and completely?
- Do you understand why these concepts are important? Do you understand how they play into actual software design?
Tools for Our Answers
- There are many principles of object-oriented programming. However, the four main principles (sometimes called the four pillars) are Abstraction, Polymorphism, Inheritance, and Encapsulation. These are often remembered by using the acronym A-PIE.
- Abstraction is the process of hiding unnecessary or complicated details to reduce complexity. This allows users to access more functionality on top of the provided abstraction.
- For example, let’s consider the use of an ArrayList. An ArrayList offers dynamic resizing, constant time access to the iᵗʰ element, constant (amortized) insertion, and built-in functions. All of this functionality can be obtained by creating an ArrayList. Engineers are able to build more complex programs using ArrayLists by building on top of the provided ArrayList.
- We can implement abstraction using abstract classes, abstract methods, and interfaces. Abstract classes cannot be instantiated. Rather subclasses use inheritance to extend these abstract classes. Abstract methods contain a function signature but no implementation. The implementation is left to the subclasses.
- The above is an abstract class. We can implement subclasses as below. We use the extends keyword to access the Mammal class and we use the Override keyword to denote we are overriding an abstract method.
- We can use an interface to implement abstraction. An interface can be thought of as the blueprint for a Class. It can contain member variables and functions but not implementations for these functions. We have a MammalActions interface below. We use the implement keyword to denote the implementation of a certain interface.
- Suppose we have a Dog subclass and our Mammal parent class. We can access properties in our subclass (i.e. Dog) and in our parent class (i.e. Mammal). We know the myDog object must implement all methods in the interface, so we can call those as well. We use the super() keyword to access our parent class.
- We can instantiate a Dog object and call methods from our interface and access properties from our parent class, which is all shown below.
- The above helps us to organize our code, reduce complexity, and group similar objects together (usually in a hierarchical structure).
- The next concept is polymorphism. Polymorphism comes from the Greek poly, meaning “many”, and morph meaning “form”. Polymorphism allows the same method or variable to take on a different form depending on the context.
- There are two kinds of polymorphism- run-time polymorphism and compile-time polymorphism. They are named based on when the polymorphism is resolved — either at run-time or compile-time.
- Below is an example of run-time polymorphism, which is also known as method overriding. Both printDescription() methods have the same method signature but they are called by different objects. The drive() method is able to take on multiple forms based on the object calling it.
- We mentioned the concept of a method signature above — a method signature includes the access modifier (public, private, and protected), the static modifier, the return type (void, int[], String, etc.), and the method arguments (Integers, chars, Arrays, etc.).
- Method overloading is when two methods have the same name but different arguments. The same object can call these methods and depending on the arguments given, the compiler can resolve which method has been called. This is compile-time polymorphism or method overloading.
- Inheritance is the process where a subclass assumes the variables, properties, and methods of a parent class. We have already seen an example of inheritance. The Dog class inherited the Mammal class. In doing so, the Dog class had the member variable type and the function printName. Inheritance is achieved by using the extends keyword.
- Inheritance is broken down into three types — single, multiple, and multilevel. Single inheritance is when a subclass extends a parent class and this parent class has no parent class of its own. Multilevel inheritance is when a child class extends a parent class and that parent class extends another parent class. This can be thought of as multiple levels (multilevel) of single inheritance.
- Multiple inheritance is when a subclass inherits two or more parent classes but these parent classes have no relationship.
- Java does not support multiple inheritance. Suppose, in the above example, that the Mammal Class and Pet Class both had an eat() method with the same arguments. If a Dog object calls eat(), Java would have no way to resolve this call. This ambiguity is one reason why Java does not support multiple inheritance.
- The final key principle of object-oriented programming is encapsulation — the practice of binding method data and method functions in one single method. We can think of a method as a capsule that contains data and the code that manipulates this data. This process of data-hiding makes sure our data is only being accessed as we expected throughout the program.
- Encapsulation in Java is achieved by making the member variables of a Class private and only allowing them to change through the use of getter and setter methods. These aptly named methods set the values of our member variables and get (and return) these values as well.
- We can call our getters and setters from our main() function.
- If we try to set myCar.make or myCar.maxSpeed directly, we will get an error since these variables have private access. Similarly, if we try to print or use myCar.make or myCar.maxSpeed, we will receive the same error.
- When we use encapsulation, we make our code more robust, secure, and easy to test. We can more safely reuse code as we know the member variables cannot be easily erroneously updated.
My Answer
The four key principles of object-oriented programming are abstraction, polymorphism, inheritance, and encapsulation.
Abstraction is the process of hiding unnecessary or complicated details to reduce complexity. This allows users to access more functionality on top of the provided abstraction. We can implement abstraction using abstract classes, abstract methods, and interfaces. These help us organize our code, reduce complexity, and group similar objects together.
Polymorphism comes from the Greek poly, meaning “many”, and morph meaning “form”. Polymorphism allows the same method or variable to take on a different form depending on the context. This happens in two ways — method overloading (compile-time polymorphism) and method overriding (run-time polymorphism).
Method overriding occurs when a child class redefines the method in the parent class. When an instantiation of the child class calls this method, the overridden method is called. This resolution occurs at run-time. Method overloading is when two methods have the same name but different arguments. Depending on how this method is called (i.e. with what arguments), the compiler can resolve which method has been called. This is compile-time polymorphism or method overloading.
The third principle of OOP is inheritance — which occurs when a child class assumes the variables, properties, and methods of a parent class. This is achieved by using the extends keyword. Inheritance is broken down into three types — single, multilevel, and multiple.
Single inheritance is when a subclass extends a parent class and this parent class has no parent class of its own. Multilevel inheritance is when a child class extends a parent class and that parent class extends another parent class. Multiple inheritance is when a subclass inherits two or more parent classes but these parent classes have no relationship. Java does not support multiple inheritance as it introduces unresolvable ambiguity.
The final concept of OOP is encapsulation — the practice of binding method data and method functions in one single method, with the goal of protecting the state of this object from external code. This is achieved in Java by setting the access modifier of member variables to private and creating getter and setter methods. Encapsulation helps to ensure our code can be safely reused and our data will only be changed when expected.
Concluding Note
The answer here is intentionally long and thorough. It is unlikely that your interviewer will ask you for this much detail. However, many questions in interviews stem from these principles of OOP (See Variants above). Having a complete understanding of these concepts is not only important for interviews but can also help you develop stronger, clearer, and more maintainable software.
As mentioned, these are the four “pillars” of OOP. However, there are many other principles including association, aggregation, and composition. These principles are readily understood but are unlikely to come up in an interview. These principles are all OOP specific. However, there are other general software development principles like Don’t Repeat Yourself (DRY) and Keep it Simple, Stupid (KISS). While these principles are certainly valuable, they extend to all software and not just object-oriented programming, making them less relevant for this question.
Check out the conclusion here!
Questions? Comments? Send me an email at andrew.oliver.medium@gmail.com! I’d love to hear from you.