Google

Sep 23, 2011

Java OO Interview Questions and Answers

If you asked me to pick a section that is most popular with the interviewers, this is it. If you don't perform well in Object Oriented (i.e. OO) programming , your success rate in interviews will be very low. Good interviewers will be getting you to analyze or code for a particular scenario. They will be observing your decisions with interfaces and classes, and question your decisions to ascertain your technical skills, analytical skills, and communication skills. You can't memorize your answers. This section requires some level of experience to fully understand.

In this blog, I cover some OO interview questions and answers. If you are interested in more questions and answers, the "Core Java Career Essentials" book has a whole chapter dedicated for OO questions and answers with enough examples to get through your OO interview questions with flying colors.

Q. How do you know that your classes are badly designed?
A.

  • If your application is fragile – when making a change, unexpected parts of the application can break.
  • If your application is rigid – it is hard to change one part of the application without affecting too many other parts.
  • If your application is immobile – it is hard to reuse the code in another application because it cannot be separated.

Overly complex design is as bad as no design at all. Get the granularity of your classes and objects right without overly complicating them. Don't apply too many patterns and principles to a simple problem. Apply them only when they are adequate. Don't anticipate changes in requirements ahead of time. Preparing for future changes can easily lead to overly complex designs. Focus on writing code that is not only easy to understand, but also flexible enough so that it is easy to change if the requirements change.


Q. Can you explain if the following classes are badly designed?
The following snippets design the classes & interfaces for the following scenario. Bob, and Jane work for a restaurant. Bob works as manager and a waiter. Jane works as a waitress. A waiter's behavior is to take customer orders and a manager's behavior is to manage employees.


package badrestaurant;

public interface Person {}


package badrestaurant;

public interface Manager extends Person {
    public void managePeople( );
}

package badrestaurant;

public interface Waiter extends Person {
    public void takeOrders( ); 
}


package badrestaurant;

public class Bob implements Manager, Waiter {

    @Override
    public void managePeople( ) {
        //implementation goes here
    }

    @Override
    public void takeOrders( ) {
        //implementation goes here
    }
}


package badrestaurant;

public class Jane implements Waiter {

    @Override
    public List<string> takeOrders( ) {
        //implementation goes here
    }
}

The Restaurant class uses the above classes as shown below.

package badrestaurant;

public class Restaurant {
    
    public static void main(String[ ] args) {
        
        Bob bob = new Bob( );
        bob.managePeople( );
        bob.takeOrders( );
        
        Jane jane = new Jane( );
        jane.takeOrders( );
    }
}


A. The above classes are badly designed for the reasons described below.

The name should be an attribute, and not a class like Bob or Jane. A good OO design should hide non-essential details through abstraction. If the restaurant employs more persons, you don't want the system to be inflexible and create new classes like Peter, Jason, etc for every new employee.

The above solution's incorrect usage of the interfaces for the job roles like Waiter, Manager, etc will make your classes very rigid and tightly coupled by requiring static structural changes. What if Bob becomes a full-time manager? You will have to remove the interface Waiter from the class Bob. What if Jane becomes a manager? You will have to change the interface Waiter with Manager.

The above drawbacks in the design can be fixed as shown below by asking the right questions. Basically waiter, manager, etc are roles an employee plays. You can abstract it out as shown below.


package goodrestuarant;

public interface Role {
    public String getName( );
    public void perform( );
}


package goodrestuarant;

public class Waiter implements Role {
    
    private String roleName;
    
    public Waiter(String roleName) {
        this.roleName = roleName;
    }

    @Override
    public String getName( ) {
       return this.roleName;
    }

    @Override
    public void perform( ) {
       //implementation goes here
    }
}

package goodrestuarant;

public class Manager implements Role {
    
    private String roleName;   
    
    public Manager(String roleName) {
        this.roleName = roleName;
    }

    @Override
    public String getName( ) {
       return this.roleName;
    }

    @Override
    public void perform( ) {
       //implementation goes here
    }
}



The Employee class defines the employee name as an attribute as opposed to a class. This makes the design flexible as new employees can be added at run time by instantiating new Employee objects with appropriate names. This is the power of abstraction. You don't have to create new classes for each new employee. The roles are declared as a list using aggregation (i.e. containment), so that new roles can be added or existing roles can be removed at run time as the roles of employees change. This makes the design more flexible.

package goodrestuarant;

import java.util.ArrayList;
import java.util.List;

public class Employee {
    
    private String name;
    private List<role> roles = new ArrayList<role>(10);
    
    public Employee(String name){
        this.name = name;
    }

    public String getName( ) {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<role> getRoles( ) {
        return roles;
    }

    public void setRoles(List<role> roles) {
        this.roles = roles;
    }
    
    public void addRole(Role role){
        if(role == null){
            throw new IllegalArgumentException("Role cannot be null");
        }
        roles.add(role);
    }
    
    public void removeRole(Role role){
        if(role == null){
            throw new IllegalArgumentException("Role cannot be null");
        }
        roles.remove(role);
    }
}

The following Restaurant class shows how flexible, extensible, and maintainable the above design is.

package goodrestuarant;

import java.util.List;

public class Restaurant {
    
    public static void main(String[ ] args) {
        
        Employee emp1 = new Employee ("Bob");
        Role waiter = new Waiter("waiter");
        Role manager = new Manager("manager");
        
        emp1.addRole(waiter);
        emp1.addRole(manager);
        
        Employee emp2 = new Employee("Jane");
        emp2.addRole(waiter);
        
        List<role> roles = emp1.getRoles( );
        for (Role role : roles) {
            role.perform( );
        }
        
        //you can add more employees or change roles based on 
        //conditions here at runtime. More flexible.   
    }
}



Q. What do you achieve through good class and interface design?
A.

  • Loosely coupled classes, objects, and components enabling your application to easily grow and adapt to changes without being rigid or fragile.
  • Less complex and reusable code that increases maintainability, extendability and testability.

Q. What are the 3 main concepts of OOP?
A. Encapsulation, polymorphism, and inheritance are the 3 main concepts or pillars of an object oriented programming. Abstraction is another important concept that can be applied to both object oriented and non object oriented programming. [Remember: a pie ? abstraction, polymorphism, inheritance, and encapsulation.]


Q. What problem(s) does abstraction and encapsulation solve?
A. Both abstraction and encapsulation solve same problem of complexity in different dimensions. Encapsulation exposes only the required details of an object to the caller by forbidding access to certain members, whereas an abstraction not only hides the implementation details, but also provides a basis for your application to grow and change over a period of time. For example, if you abstract out the make and model of a vehicle as class attributes as opposed to as individual classes like Toyota, ToyotaCamry, ToyotaCorolla, etc, you can easily incorporate new types of cars at runtime by creating a new car object with the relevant make and model as arguments as opposed to having to declare a new set of classes.


Q. How would you go about designing a “farm animals” application where animals like cow, pig, horse, etc move from a barn to pasture, a stable to paddock, etc? The solution should also cater for extension into other types of animals like circus animals, wild animals, etc in the future.


A.

package subclass0;

public abstract class Animal {
    private int id;                                // id is encapsulated

    public Animal(int id) {
        this.id = id;
    }

    public int getId( ) {
        return id;
    }

    public abstract void move(Location location);
}


package subclass0;

public class FarmAnimal extends Animal {

    private Location location = null;                   // location is encapsulated

    public FarmAnimal(int id, Location defaultLocation) {
        super(id);
        validateLocation(defaultLocation);
        this.location = defaultLocation;
    }

    public Location getLocation( ) {
        return location;
    }

    public void move(Location location) {
        validateLocation(location);
        System.out.println("Id=" + getId( ) + " is moving from "
                + this.location + " to " + location);
        this.location = location;
    }

    private void validateLocation(Location location) {
        if (location == null) {
            throw new IllegalArgumentException("location=" + location);
        }
    }
}

package subclass0;

public enum Location  {
    Barn, Pasture, Stable, Cage, PigSty, Paddock, Pen
}



package subclass0;

public class Example {

    public static void main(String[ ] args) {
        Animal pig = new FarmAnimal(1, Location.Barn);
        Animal horse = new FarmAnimal(2, Location.Stable);
        Animal cow = new FarmAnimal(3, Location.Pen);

        pig.move(Location.Paddock);
        horse.move(Location.Pen);
        cow.move(Location.Pasture);
    }
}  


Output:

Id=1 is moving from Barn to Paddock
Id=2 is moving from Stable to Pen
Id=3 is moving from Pen to Pasture

In the above example, the class FarmAnimal is an abstraction used in place of an actual farm animal like horse, pig, cow, etc. In future, you can have WildAnimal, CircusAnimal, etc extending the Animal class to provide an abstraction for wild animals like zebra, giraffe, etc and circus animals like lion, tiger, elephant, etc respectively. An Animal is a further abstraction generalizing FarmAnimal, WildAnimal, and CircusAnimal. The Location is coded as an enumeration for simplicity. The Location itself can be an abstract class or an interface providing an abstraction for OpenLocation, EnclosedLocation, and SecuredLocation further abstracting specific location details like barn, pen, pasture, pigsty, stable, cage, etc. The location details can be represented with attributes like “name”, “type”, etc.

The FarmAnimal class is also well encapsulated by declaring the attribute “location” as private. Hence the “location” variable cannot be directly accessed. Assignment is only allowed through the constructor and move(Location location) method, only after a successful precondition check with the validateLocation(...) method. The validateLocation(...) itself marked private as it is an internal detail that does not have to be exposed to the caller. In practice, the public move(..) method can make use of many other private methods that are hidden from the caller. The caller only needs to know what can be done with an Animal. For example, they can be moved from one location to another. The internal details as to how the animals are moved is not exposed to the caller. These implementation details are specific to FarmAnimal, WildAnimal, and CircusAnimal classes.

The above code does not satisfy the following questions.

1) Why does the Employee class need to be mutable?
2) Why aren't the roles defensive copied?
3) Why would the Employee need to know how to add and remove roles?
4) Waiter and Manager are placed in a collection but don't override hashcode and equals. That will cause the contains method on a List to not behave as expected.
5) You check if the role is null then throw an IllegalArgumentException, that should instead be a NullPointerException.
6) The code that checks for null roles being added is duplicated, thus defeating the DRY principle.


Some of the above questions are answered in How to write immutable Java classes?

Labels: ,

28 Comments:

Anonymous Anonymous said...

well written....
helped me a lot..

3:58 AM, December 27, 2011  
Anonymous milan said...

Thank you for providing this detail. It is very helpful to me

4:30 AM, February 03, 2012  
Anonymous Anonymous said...

It's said that java is a highly secure language. Why does it call so?

7:52 AM, May 24, 2012  
Blogger Unknown said...

It is not true that Java is highly secured. It depends on how you use the language. But here are some features that makes it more secured than some other languages.

--The fact that Java does not allocate direct pointers to memory and does not allow you to access out of bound arrays to cause buffer overflow security threats, make Java more secured than some of the other languages like C.


--The Automatic Garbage Collection minimizes the chances of accidental errors that can cause security vulnerabilities.

--The Java String class is immutable, hence the password value cannot be modified.

--The Java applications have to run on a JVM, which performs byte code verification.

--Java applets/applications can execute within a sand box. The Security Manager concept makes it relatively easy to run a Java application within a "sandbox" that prevents it from any security vulnerabilities from the system it is running on.

3:30 PM, May 24, 2012  
Blogger venkatesh said...

hai,you have assigned the local variable location to an instance variable and every time ie.,when you call FarmAnimal constructor and move method every time the instance variable ie., this.location values will vary why you have did like that can you explain me and explain me about how to use setter and getters.

8:32 PM, June 01, 2012  
Blogger venkatesh said...

explain me how to use setters and getters

8:33 PM, June 01, 2012  
Anonymous Anonymous said...

very well explained, Thanks a lot for your books and blogs... may be you can write a book on "how to program in java".

8:57 PM, June 08, 2012  
Blogger Unknown said...

Thanks for the compliments. The core java career essentials book is detailed enough to meet that title :)

2:14 PM, June 10, 2012  
Anonymous Bori Konstantinov said...

Thank you so much for posting this. As I have a 2nd Round Java Interview soon, I found this to be very helpful! Cheers!

3:11 AM, June 18, 2012  
Blogger javin paul said...

Indeed very well written. sometime they also ask questions like which pattern you used and why? like if you said you have used Factory than what benefit it offer, which OOPS concept it support etc. Factory is based upon Encapsulation quite well to encapsulate object creation code. By the way I also shared few Java design pattern questions, may help.

3:06 PM, June 25, 2012  
Blogger Unknown said...

Thanks, the "Core Java Essentials" book has a lot more OO examples with design principles. Good to hear that you have blogged about the design patterns.

5:16 PM, June 25, 2012  
Blogger punk3688 said...

Very well Explained specially stuff regarding good restaurant and bad restaurant

4:33 PM, August 02, 2012  
Anonymous Shubha said...

Arul,

Where can i find ur book?

7:45 PM, August 17, 2012  
Blogger Unknown said...

Follow the links on the RHS panel.

10:36 PM, August 17, 2012  
Blogger Unknown said...

Thanks a lot! The design questions were very well explained.
Can you please provide some more related links.
Thanks again!

7:29 AM, September 06, 2012  
Blogger nolan said...

This comment has been removed by a blog administrator.

11:01 PM, September 22, 2012  
Anonymous Anonymous said...

I am also hosting java interview questions quiz

3:58 AM, November 29, 2012  
Anonymous Anonymous said...

Thumbs up for that Manager waiter example!

8:49 PM, February 27, 2013  
Blogger Unknown said...

great article. Thanks

-Mahesh Bharathi


6:53 PM, July 21, 2013  
Blogger Unknown said...

It is very helpful for me. Please keep posting this type of questions...

7:44 PM, August 26, 2013  
Blogger Unknown said...

Very helpful interview questions...

4:14 PM, August 27, 2013  
Blogger Unknown said...

1) Why does the Employee class need to be mutable?
2) Why aren't the roles defensive copied?
3) Why would the Employee need to know how to add and remove roles?
4) Waiter and Manager are placed in a collection but don't override hashcode and equals. That will cause the contains method on a List to not behave as expected.
5) You check if the role is null then throw an IllegalArgumentException, that should instead be a NullPointerException.
6) The code that checks for null roles being added is duplicated, thus defeating the DRY principle.
The issues above indicate a bad design for other reasons.

7:01 AM, September 20, 2013  
Anonymous Anonymous said...

plz explain me oop ....and example for each features of oop

8:22 PM, January 24, 2014  
Blogger Unknown said...

helpfull

3:03 PM, January 26, 2014  
Blogger Unknown said...

Core Java Career Essentials book has many examples.

12:44 PM, January 31, 2014  
Blogger Unknown said...

awsome explanation..very helpful

12:17 PM, March 25, 2014  
Blogger Unknown said...

Glad that you liked it.

1:27 PM, March 25, 2014  
Blogger Evan said...

I have a question, there is no co relation between java and javascripts. But can object oriented concepts be used for javascripts.

Regards,
Creately

10:24 PM, October 20, 2014  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home