Print Post Print Post

Some Java Interview Questions (Immutability, Polymorphism, etc.)

Interview questions are so bogus. If your retention span is as bad as mine, without Google you are sunk. But, here are some questions that you will see on many interviews.

String Immutability

Strings are immutable and final in Java. You cannot change the object, but you can change the reference. Consider the following code.

package com.tutorial.junk;

public class VariousThings {
  int size;
  public static void main(String[] args) 
  {
    String a = "abc";
    String c = a;
    c = "test";

    VariousThings x = new VariousThings();
    x.size = 11;

    VariousThings y = x;
    y.size = 22;

     System.out.println(a + " " + c + " " + x.size + " " + y.size);
  }
}

Which when printed results in the following.

ab test 22 22

The a variable refers to the space in memory containing “xyz” while b refers to the “123” space.  The c variable creates a new space in memory containing “xyz” and refers to the newly created space, not the space referred to by the a variable. When c is set equal to the “test” value, only c is changed, as c does not refer to the same space as the a variable.

Contrast String behavior to the simple class VariousThings. The x variable refers to a new instance of VariousThings. Its size is set to eleven. The variable y also refers to x which in turn refers to the particular instance of VariousThings that it refers to. And the value of size is eleven. As y refers to the same object instance as x, when size is changed for y it is also changed for x.

String/Array Reversal

If you are sneaky, just use a StringBuilder’s reverse method. Or, use the ArrayUtils.reverse method from Apache Commons. However, this is rarely what the interviewer is looking for. Instead, he or she is testing if you remembered programming 101.

In the following example, we first reverse a string array. We also determine if a String is a palindrome.

package com.tutorial.junk;

public class Palindrome {

  public static void main(String[] args) {

    String z[] = {"1","2","3","4","5","6","7"};
    int right = z.length-1;            
    int left = 0;

    for(;left < z.length/2;left++} {
      String temp = z[right];
      z[right--] = z[left];
      z[left] = temp;
    }

    for(int i = 0; i < z.length; i++) {
      System.out.print(z[i] + " ");
    }

    String a = "bxxxxb";
    System.out.println(Palindrome.isPalindrome(a));

    String b = "abc";
    System.out.println(Palindrome.isPalindrome(b));
  }

  public static boolean isPalindrome(String a) {
    char[] chars = a.toCharArray();
    int right = chars.length-1;  
    int left = 0;

    for(;left <= right;left++) {
      if(chars[left] != chars[right--]) return false;
    }
    return true;
  }
}

One solution to array reversal is to create a right and left index, where the right begins at the array’s length minus one while the left begins at zero. Then with each iteration, swap the value the two values at the right and left and then increment the left and decrement the right by one. Repeat until the left index reaches the array’s middle. If the array is an odd length, then the middle element remains in place, as it doesn’t switch. If even the middle two elements switch places.

A Stupid Static Question

Do not shoot the messenger. This example is the type of trivia not so skilled interviewers might ask to appear smarter than he or she really is. It’s the type of question I personally hate, but it might be asked.

package com.tutorial.junk;

public class WillCompile {

  public static String sayIt(){
    System.out.println("I compiled");
    return "test";
  }

  public static void main(String args[]){
    WillCompile objWillCompile = null;
    System.out.println(objWillCompile.sayIt());
  }
}

Which prints the following.

I compiled
Test

Why is this a trick question? The compiler sees that sayIt is a static method; therefore, it automagically the objWillCompile instance with the class WillCompile. And so the code compiles and runs even though the objWillCompile variable is null.

Polymorphism

Computer science defines polymorphism as when distinct objects can be accessed in the same way. There are two types of polymorphism, compile-time (static) and run-time (dynamic). Static polymorphism is achieved using method overloading. Dynamic polymorphism is achieved at runtime. This type of polymorphism is achieved through object inheritance. Consider each polymorphism type in turn.

Static Polymorphism

Consider a CommunicationWidget that is designed to send a simple message.

  1. Create a new class named CommunicationWidget.
  2. Create a method named communicate that takes a String.
  3. Create a method named communicate that takes a List of Strings.
  4. In the main method create a new CommunicationWidget class and call both communicate methods.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class CommunicationWidget {
  public void communicate(String msg) {
    System.out.println(msg);
  }

  public void communicate(List<String> msgs) {
    Stream.of(msgs).forEach(x->System.out.println(x));
  }

  public static void main(String[] args) {
    CommunicationWidget widget = new CommunicationWidget();
    widget.communicate("hello");
    List<String> vals = Arrays.asList(new String[] { "A", "B", "C", "D" });
    widget.communicate(vals);
  }
}
  1. Run the program and note the output.
hello
[A, B, C, D]

The two communicate methods have different signatures. When the code is compiled, the compiler recognizes which method is supposed to be called based on the signature. This occurs at compile time and becomes a fixed part of the program.

Dynamic Polymorphism

Polymorphism occurs at run-time rather than compile-time. It is accomplished through inheritance. Run-time polymorphism is when an object can be subclassed by objects and the behavior of the sub-object can override the parent’s behavior. For example, consider a pet, all pets make noise. However, cats purr while dogs bark.

A dog is a pet. A cat is a pet. You can represent this relationship through the following simple class diagram.

Let’s illustrate runtime polymorphism through a simple example.

  1. Create a new class named Pet and add a method named makeNoise.
package com.tutorial.junk;

public class Pet {
  public void makeNoise() {
    System.out.println("grunt");
  }
}
  1. Create a new class named Cat and have it extend Pet. In Java when a child class builds upon a parent class you say it extends the parent.
  2. Implement the makeNoise method, where the noise it makes is to purr.
package com.tutorial.junk;

public class Cat extends Pet {
  @Override
  public void makeNoise() {
    System.out.println("purr");
  }
}
  1. Create a Dog class that extends Pet.
  2. Create a makeNoise method where the noise it makes is to bark.
package com.tutorial.junk;

public class Dog extends Pet {
  @Override
  public void makeNoise() {
    System.out.println("bark");
  }
}
  1. Now create a class named RuntimePoly with a main method.
  2. Create a static method named causeNoise that takes a Pet as an argument and calls the Pet class’s makeNoise method.
  3. Create a new instance of a Dog and pass it to the causeNoise method.
  4. Create a new instance of a Cat and pass it to the causeNoise method.
  5. Create a new instance of Pet and pass it to the causeNoise method.
  6. Set the Pet instance to the Cat instance and pass it to the causeNoise method.
  7. Set the Pet instance to the Dog instance and pass it to the causeNoise method.
package com.tutorial.junk;

public class RuntimePoly {

  public static void causeNoise(Pet pet) {
    pet.makeNoise();
  }

  public static void main(String[] args) {
    Dog a = new Dog();
    RuntimePoly.causeNoise(a);
    Cat b = new Cat();
    RuntimePoly.causeNoise(b);
    Pet c = new Pet();
    c.makeNoise();
    c = a;
    c.makeNoise();
    c = b;
    c.makeNoise();}
  }
}
  1. Compile and run the program.
bark
purr
grunt
bark
purr

The causeNoise method takes a Pet. But a Dog is a Pet and so the code compiles. Moreover, the Dog makeNoise method overRides the Pet makeNoise method. The same is true for Cat when it is passed to the makeNoise method.

The causeNoise method takes any object that subclasses Pet. This is one aspect of dynamic polymorphism. In the main method, the new instance of Pet is assigned to the Dog instance (remember the variable c is a reference to an instance of Pet). Because c references a Pet, it can be changed to reference a Dog or a Cat and the appropriate makeNoise method is called. The correct makeNoise method is determined at runtime and is not precompiled statically.

Leave a Reply

Your email address will not be published. Required fields are marked *