Showing posts with label Interview. Show all posts
Showing posts with label Interview. Show all posts

Wednesday, June 13, 2012

10 Tricky Java Interview Questions

Here are some Java interview questions which are  un-common
  1. What is the performance effect of a large number of import statements which are not used?
    Answer: They are ignored if the corresponding class is not used.
  2. Give a scenario where hotspot will optimize your code?
    Answer: If we have defined a variable as static and then initialized this variable in a static block then the Hotspot will merge the variable and the initialization in a single statement and hence reduce the code.
  3. What will happen if an exception is thrown from the finally block?
    Answer: The program will exit if the exception is not catched in the finally block.
  4.  How does decorator design pattern works in I/O classes?
    Answer:  The various classes like BufferedReader , BufferedWriter workk on the underlying stream classes. Thus Buffered* class will provide a Buffer for Reader/Writer classes.
  5. If I give you an assignment to design Shopping cart web application, how will you define the architecture of this application. You are free to choose any framework, tool or server?
    Answer:  Usually I will choose a MVC framework which will make me use other design patterns like Front Controller, Business Delegate, Service Locater, DAO, DTO, Loose Coupling etc. Struts 2 is very easy to configure and comes with other plugins like Tiles, Velocity and Validator etc. The architecture of Struts becomes the architecture of my application with various actions and corresponding JSP pages in place.
  6. What is a deadlock in Java? How will you detect and get rid of deadlocks?
    Answer:  Deadlock exists when two threads try to get hold of a object which is already held by another object.
  7. Why is it better to use hibernate than JDBC for database interaction in various Java applications?
    Answer:  Hibernate provides an OO view of the database by mapping the various classes to the database tables. This helps in thinking in terms of the OO language then in RDBMS terms and hence increases productivity.
  8. How can one call one constructor from another constructor in a class?
    Answer:  Use the this() method to refer to constructors.
  9. What is the purpose of intern() method in the String class?
    Answer:  It helps in moving the normal string objects to move to the String literal pool
  10. How will you make your web application to use the https protocol?
    Answer:  This has more to do with the particular server being used  than the application itself. Here is how it can be done on tomcat:

Monday, June 11, 2012

Java stack data structure interview questions and answers

The Java Collection library is one of the most frequently used libraries.The LIFO access mechanism used by a stack has many practical uses.  For example, Evaluation of expressions / syntax Parsing, validating and parsing XML, undo sequence in a text editor, pages visited history in a web browser, etc. Here are a few Java based interview questions and answers on a stack.

What LIFO implementation would you use in Java?
The Vector based Stack class is a legacy and the Javadoc documentation for this class states that Deque should be used instead because it provides better LIFO operation support. Implementations of Deque are typically expected to perform better than Stack. J2SE 5 introduced a Queue interface and the Deque interface extends this interface. The Deque interface supports should be pronounced "deck" rather than "de-queue" and is not related to dequeue used to indicate removal from a queue. The double-ended queue supports addition or removal of elements from either end of the data structure, so it can be used as a queue (first-in-first-out/FIFO) or as a stack (last-in-first-out/LIFO).

Note:  The legacy Vector class uses internal synchronization, and it is rarely good enough for actual consistency, and can slow down execution when it is not really needed. The new java.util.concurrent package provides a more efficient way of thread-safety.

Can you write a program to evaluate if a given string input has proper closing bracket for every opening bracket?
A. Firstly, think of the pseudo code. The pseudo-code goes as follows.

1. Store every opening parenthesis (i.e. a LHS parenthesis) in a stack. This will enable LIFO.
2. When you encounter a closing parenthesis (i.e. RHS parenthesis ), pop the last entry, which should be the corresponding opening parenthesis.
3. If not found, then the parentheses are not matched.

If required, draw a diagram as shown below.





Here is a sample program to illustrate a Stack (i.e. LIFO) in action in evaluating if a program has balanced parentheses. The enum constants class that defines the parentheses.



public enum PARENTHESIS {
 LP('('), RP(')'), LB('{'), B('}'), LSB('['), RSB(']');
  char symbol;
 PARENTHESIS(Character symbol) {
  this.symbol = symbol;
 }

 char getSymbol() {
  return this.symbol;
 }


Now, the stack in action using its LIFO mechanism to marry a closing parenthesis (i.e RHS) with an opening parenthesis (i.e. LHS). If you find any LHS parenthesis, push it into a stack, and when you find a RHS parenthesis, pop the stack to see if you have a corresponding LHS parenthesis.




















import java.util.ArrayDeque;
import java.util.Deque;
public class Evaluate {
  //stores the parentheses
 final Deque<character> paranthesesStack = new ArrayDeque<character>();

 public boolean isBalanced(String s) {
   for (int i = 0; i < s.length(); i++) {
   if (s.charAt(i) == PARENTHESIS.LP.getSymbol() ||
       s.charAt(i) == PARENTHESIS.LB.getSymbol() ||
       s.charAt(i) == PARENTHESIS.LSB.getSymbol())
     
     paranthesesStack.push(s.charAt(i));// auto boxing takes place
                                       // push the opening parentheses
    //for each RHS parenthesis check if there is a matching LHS Parenthesis
   //if the stack is empty or does not have a matching LHS parenthesis
   //then not balanced.
   else if (s.charAt(i) == PARENTHESIS.RP.getSymbol()){ 
    if (paranthesesStack.isEmpty() || paranthesesStack.pop()
        !=   PARENTHESIS.LP.getSymbol())
     return false;
   }
    else if (s.charAt(i) == PARENTHESIS.RB.getSymbol() ) {
    if (paranthesesStack.isEmpty() 
      || paranthesesStack.pop() !=PARENTHESIS.LB.getSymbol() )
     return false;
   }
    else if (s.charAt(i) == PARENTHESIS.RSB.getSymbol()) {
    if (paranthesesStack.isEmpty() 
       || paranthesesStack.pop() != PARENTHESIS.LSB.getSymbol())
     return false;
   }
  }
   return paranthesesStack.isEmpty();
   //if the stack is empty, then all matched well, otherwise not matched.
 }
}

Note: ArrayDeque is not thread-safe and does not allow for elements of the data structure to be null. The concurrent package has BlockingDeque and LinkedBlockingDequeue.

Finally, a simple JUnit class to test.


import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
 public class EvaluateTest {
  
 Evaluate eval = null;
  
 @Before
 public void setUp(){
  eval = new Evaluate();
 }
  
 @Test
 public void testPositiveIsBalanced(){
   boolean result = eval.isBalanced("public static void main(String[] args) {}");
      Assert.assertTrue(result);  
       
 }
  
 @Test
 public void testNegativeIsBalanced(){
   boolean result = eval.isBalanced("public static void main(String[ args) {}");   // missing ']'
      Assert.assertFalse(result);
       
      result = eval.isBalanced("public static void main(String[] args) }");          // missing '{'
      Assert.assertFalse(result);
       
       
      result = eval.isBalanced("public static void main String[] args) {}");        // missing '('
      Assert.assertFalse(result);
       
 }
}
Tip: When testing, test positive and negative scenarios.

Note: The above example is shown to illustrate how a LIFO mechanism can be used to determine if the parentheses are balanced. The actual implementation is far from being optimum. Where ever there is a large block of if-else or switch statements, one should think about an object oriented solution.

Why Deque interface is different from other collection classes?
In Deque, You can insert and delete the objects from the both start and end of the the collection. Whereas in a normal collection, inserts/deletes are happening at last only.

What are the different ways to look at the trace of your program execution?
1.Java is a stack based language, and the program execution is pushed and popped out of a stack. When a method is entered into, it is pushed into a stack, and when that method invokes many other methods, they are pushed into the stack in the order in which they are executed. As each method completes its execution, they are popped out of the stack in the LIFO order. Say methodA( ) invoked methodB( ), and methodB( ) invoked methodC ( ), when execution of methodC( ) is completed, it is popped out first, and then followed by methodB( ) and then methodA( ). When an exception is thrown at any point, a stack trace is printed for you to be able to find where the issue is.


2. A Java developer can access a stack trace at any time. One way to do this is to call


Thread.currentThread().getStackTrace() ; //handy for tracing

You could get a stack trace of all the threads using the Java utilities such as jstack, JConsole or by sending a kill -quit signal (on a Posix operating system) or <ctrl><break> on WIN32 platform to get a thread dump. You could also use the JMX API as shown below. ThreadMXBean is the management interface for the thread system of the JVM.



ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] infos = bean.dumpAllThreads(true, true);
for (ThreadInfo info : infos) { 
    StackTraceElement[] elems = info.getStackTrace(); 
 //...do something
}

The thread dumps are very useful in identifying concurrency issues like dead locks, contention issues, thread starvation, etc.

Is recursive method calls possible in Java?
Yes. Java is stack based and because of its LIFO (Last In First Out) property, it remembers its 'caller'. So it knows whom to return when the method has to return.

How would you go about analysing stack traces correctly?
1. One of the most important concepts of correctly understanding a stack trace is to recognize that it lists the execution path in reverse chronological order from most recent operation to earliest operation. That is, it is LIFO.
2. The stack trace below is simple and it tells you that the root cause is a NullPointerException on Class C. So you look at the top most class.

Exception in thread "main" java.lang.NullPointerException
        at com.myapp.ClassC.methodC(ClassC.java:16)
        at com.myapp.ClassB.methodB(ClassB.java:25)
        at com.myapp.ClassA.main(ClassA.java:14)
3. The stack trace can get more complex with multiple "caused by" clauses, and in this case you usually look at the bottom most "caused by". For example,

Exception in thread "main" java.lang.IllegalStateException: ClassC has a null property
        at com.myapp.ClassC.methodC(ClassC.java:16)
        at com.myapp.ClassB.methodB(ClassB.java:25)
        at com.myapp.ClassA.main(ClassA.java:14)
Caused by: com.myapp.MyAppValidationException
        at com.myapp.ClassB.methodB(ClassB.java:25)
        at com.myapp.ClassC.methodC(ClassC.java:16)
        ... 1 more
Caused by: java.lang.NullPointerException
        at com.myapp.ClassC.methodC(ClassC.java:16)
        ... 1 more

The root cause is the last "caused by", which is a NullPointerException on ClassC

4. When you use plethora of third-party libraries like Spring, Hibernate, etc, your stack trace's "caused by" can really grow and you need to look at the bottom most "caused by" that has the package relevant to you application like com.myapp.ClassC and skip library specific ones like org.hibernate.exception.*.

Can you reverse the following numbers {1, 4, 6, 7, 8, 9}?
There are a number of ways to achieve this. Speaking of LIFO, the following example illustrates using a stack based implementation.


import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;  

public class ReverseNumbers { 
 public static void main(String[] args) {
  Integer[] values = {1, 4, 6, 7, 8, 9};
  Deque<integer> numberStack = new ArrayDeque<integer>(10);
   
  for (int i = 0; i < values.length; i++) {
   numberStack.push(values[i]);  // push the numbers in given order
  }
   
  Integer[] valuesReversed = new Integer[values.length];
   
  int i = 0;
  while (!numberStack.isEmpty()) {
   valuesReversed[i++] = numberStack.pop();
    // pop it - as this happens in reverse order
    // i++ is a post increment i.e.
    // assign it and then increment it
    // for the next round
  }
   System.out.println(Arrays.deepToString(valuesReversed));
   
 }
}

The output will be

[9, 8, 7, 6, 4, 1]

Java multithreading interview questions and answers

Q. What is the difference between processes and threads?
A. A process is an execution of a program but a thread is a single execution sequence within the process. A process can contain multiple threads. A thread is sometimes called a lightweight process.


A JVM runs in a single process and threads in a JVM share the heap belonging to that process. That is why several threads may access the same object. Threads share the heap and have their own stack space. This is how one thread’s invocation of a method and its local variables are kept thread safe from other threads. But the heap is not thread-safe and must be synchronized for thread safety.

Q. Explain different ways of creating a thread?
A. Threads can be used by either
  • Extending the Thread class.
  • Implementing the Runnable interface.
  • Using the Executor framework (this creates a thread pool) 













class Counter extends Thread {
    
    //method where the thread execution will start
    public void run(){
        //logic to execute in a thread   
    }
    //let’s see how to start the threads
    public static void main(String[] args){
       Thread t1 = new Counter();
       Thread t2 = new Counter();
       t1.start();  //start the first thread. This calls the run() method.
       t2.start(); //this starts the 2nd thread. This calls the run() method. 
    }


class Counter extends Base implements Runnable{
   
    //method where the thread execution will start
    public void run(){
        //logic to execute in a thread   
    }
    //let us see how to start the threads
    public static void main(String[] args){
         Thread t1 = new Thread(new Counter());
         Thread t2 = new Thread(new Counter());
         t1.start();  //start the first thread. This calls the run() method.
         t2.start();  //this starts the 2nd thread. This calls the run() method. 
    }

The thread pool is more efficient and  learn why and how to create pool of  threads using the executor framework.

Q. Which one would you prefer and why?
A. The Runnable interface is preferred, as it does not require your object to inherit a thread because when you need multiple inheritance, only interfaces can help you. In the above example we had to extend the Base class so implementing Runnable interface is an obvious choice. Also note how the threads are started in each of the different cases as shown in the code sample. In an OO approach you should only extend a class when you want to make it different from it’s superclass, and change it’s behavior. By implementing a Runnable interface instead of extending the Thread class, you are telling to the user that the class Counter is an object of type Base and will run as a thread.

Q. Briefly explain high-level thread states?
A. The state chart diagram below describes the thread states.


  • Runnable — A thread becomes runnable when you call the start( ), but does  not necessarily start running immediately.  It will be pooled waiting for its turn to be picked for execution by the thread scheduler based on thread priorities.

    ?
    1
    2
    MyThread aThread = new MyThread();
    aThread.start();                   //becomes runnable
  • Running: The processor is actively executing the thread code. It runs until it becomes blocked, or voluntarily gives up its turn with this static method Thread.yield( ). Because of context switching overhead, yield( ) should not be used very frequently
  • Waiting: A thread is in a blocked state while it waits for some external processing such as file I/O to finish.A call to currObject.wait( ) method causes the current thread to wait until some other thread invokes currObject.notify( ) or the currObject.notifyAll( ) is executed.
  • Sleeping: Java threads are forcibly put to sleep (suspended) with this overloaded method: Thread.sleep(milliseconds), Thread.sleep(milliseconds, nanoseconds);
  • Blocked on I/O: Will move to runnable after I/O condition like reading bytes of data etc changes.
  • Blocked on synchronization: will move to Runnable when a lock is acquired. 
  • Dead: The thread is finished working.
Thread.State enumeration contains the possible states of a Java thread in the underlying JVM.

Q. What is the difference between yield and sleeping? What is the difference between the methods sleep( ) and wait( )?
A. When a task invokes yield( ), it changes from running state to runnable state. When a task invokes sleep (), it changes from running state to waiting/sleeping state.

The method wait(1000), causes the current thread to sleep up to one second. A thread could sleep less than 1 second if it receives the notify( ) or notifyAll( ) method call. The call to sleep(1000) causes the current thread to sleep for 1 second.

Q. How does thread synchronization occurs inside a monitor? What levels of synchronization can you apply? What is the difference between synchronized method and synchronized block?
A. In Java programming, each object has a lock. A thread can acquire the lock for an object by using the synchronized keyword. The synchronized keyword can be applied in method level (coarse grained lock – can affect performance adversely) or block level of code (fine grained lock). Often using a lock on a method level is too coarse. Why lock up a piece of code that does not access any shared resources by locking up an entire method. Since each object has a lock, dummy objects can be created to implement block level synchronization. The block level is more efficient because it does not lock the whole method.


The JVM uses locks in conjunction with monitors. A monitor is basically a guardian who watches over a sequence of synchronized code and making sure only one thread at a time executes a synchronized piece of code. Each monitor is associated with an object reference. When a thread arrives at the first instruction in a block of code it must obtain a lock on the referenced object. The thread is not allowed to execute the code until it obtains the lock. Once it has obtained the lock, the thread enters the block of protected code. When the thread leaves the block, no matter how it leaves the block, it releases the lock on the associated object.

Java Interview Questions & Answers: Compile-time versus runtime

During development and design, one needs to think in terms of compile-time, run-time, and build-time. It will also help you understand the fundamentals better. These are beginner to intermediate level questions.

Q. What is the difference between line A & line B in the following code snippet?

public class ConstantFolding {
    static final  int number1 = 5;
    static final  int number2 = 6;
    static int number3 = 5;
    static int number4= 6;
     
    public static void main(String[ ] args) {
          int product1 = number1 * number2; //line A
          int product2 = number3 * number4; //line B
    }
}
A. Line A, evaluates the product at compile-time, and Line B evaluates the product at runtime. If you use a Java Decompiler (e.g. jd-gui), and decompile the compiled ConstantFolding.class file, you will see whyas shown below.

public class ConstantFolding
{
  static final int number1 = 5;
  static final int number2 = 6;
  static int number3 = 5;
  static int number4 = 6;
  public static void main(String[ ] args)
  {
      int product1 = 30;
      int product2 = number3 * number4;
  }
}

Constant folding is an optimization technique used by the Java compiler. Since final variables cannot change, they can be optimized. Java Decompiler and javap command are handy tool for inspecting the compiled (i.e. byte code ) code.

Q. Can you think of other scenarios other than code optimization, where inspecting a compiled code is useful?
A. Generics in Java are compile-time constructs, and it is very handy to inspect a compiled class file to understand and troubleshoot generics.


Q. Does this happen during compile-time, runtime, or both?
A. 



Method overloading: This happens at compile-time. This is also called compile-time polymorphism because the compiler must decide how to select which method to run based on the data types of the arguments.


public class {
     public static void evaluate(String param1);  // method #1
     public static void evaluate(int param1);     // method #2
}

If the compiler were to compile the statement:


evaluate(“My Test Argument passed to param1”);

it could see that the argument was a string literal, and generate byte code that called method #1.

Method overriding: This happens at runtime. This is also called runtime polymorphism because the compiler does not and cannot know which method to call. Instead, the JVM must make the determination while the code is running.


public class A {
   public int compute(int input) { //method #3
        return 3 * input;
   }       
}
public class B extends A {
   @Override
   public int compute(int input) { //method #4
        return 4 * input;
   }       
}

The method compute(..) in subclass “B” overrides the method compute(..) in super class “A”. If the compiler has to compile the following method,


public int evaluate(A reference, int arg2)  {
     int result = reference.compute(arg2);
}

The compiler would not know whether the input argument 'reference' is of type “A” or type “B”. This must be determined during runtime whether to call method #3 or method #4 depending on what type of object (i.e. instance of Class A or instance of Class B) is assigned to input variable “reference”.

Generics (aka type checking): This happens at compile-time. The compiler checks for the type correctness of the program and translates or rewrites the code that uses generics into non-generic code that can be executed in the current JVM. This technique is known as “type erasure”. In other words, the compiler erases all generic type information contained within the angle brackets to achieve backward compatibility with JRE 1.4.0 or earlier editions.


List<String> myList = new ArrayList<String>(10);
after compilation becomes:

List myList = new ArrayList(10);

Annotations: You can have either run-time or compile-time annotations.

public class B extends A {
   @Override
    public int compute(int input){      //method #4
        return 4 * input;
    }       
}

@Override is a simple compile-time annotation to catch little mistakes like typing tostring( ) instead of toString( ) in a subclass. User defined annotations can be processed at compile-time using the Annotation Processing Tool (APT) that comes with Java 5. In Java 6, this is included as part of the compiler itself.

public class MyTest{
    @Test
     public void testEmptyness( ){
         org.junit.Assert.assertTrue(getList( ).isEmpty( ));
     }
     private List getList( ){
        //implemenation goes here
     }
}

@Test is an annotation that JUnit framework uses at runtime with the help of reflection to determine which method(s) to execute within a test class.

@Test (timeout=100)
public void testTimeout( ) {
    while(true);   //infinite loop
}

The above test fails if it takes more than 100ms to execute at runtime.

@Test (expected=IndexOutOfBoundsException.class)
public void testOutOfBounds( ) {
       new ArrayList<Object>( ).get(1);
}


The above code fails if it does not throw IndexOutOfBoundsException or if it throws a different exception at runtime. User defined annotations can be processed at runtime using the new AnnotatedElement and “Annotation” element interfaces added to the Java reflection API.

Exceptions: You can have either runtime or compile-time exceptions.

RuntimeException is also known as the unchecked exception indicating not required to be checked by the compiler. RuntimeException is the superclass of those exceptions that can be thrown during the execution of a program within the JVM. A method is not required to declare in its throws clause any subclasses of RuntimeException that might be thrown during the execution of a method but not caught.

Example: NullPointerException, ArrayIndexOutOfBoundsException, etc

Checked exceptions are verified by the compiler at compile-time that a program contains handlers like throws clause or try{} catch{} blocks for handling the checked exceptions, by analyzing which checked exceptions can result from execution of a method or constructor.

Aspect Oriented Programming (AOP): Aspects can be weaved at compile-time, post-compile time, load-time or  runtime.
  • Compile-time:  weaving is the simplest approach. When you have the source code for an application, the AOP compiler (e.g. ajc – AspectJ Compiler)  will compile from source and produce woven class files as output. The invocation of the weaver is integral to the AOP compilation process. The aspects themselves may be in source or binary form. If the aspects are required for the affected classes to compile, then you must weave at compile-time. 
 
  • Post-compile: weaving is also sometimes called binary weaving, and is used to weave existing class files and JAR files. As with compile-time weaving, the aspects used for weaving may be in source or binary form, and may themselves be woven by aspects.
  
  • Load-time: weaving is simply binary weaving deferred until the point that a class loader loads a class file and defines the class to the JVM. To support this, one or more "weaving class loaders", either provided explicitly by the run-time environment or enabled through a "weaving agent" are required. 
  • Runtime: weaving of classes that have already been loaded  to the JVM.
Inheritance –  happens at compile-time, hence is static.
Delegation or composition – happens at run-time, hence is dynamic and more flexible.

Q. Have you heard the term "composition should be favored over inheritance"? If yes, what do you understand by this phrase?
A. Inheritance is a polymorphic tool and is not a code reuse tool. Some developers tend to use inheritance for code reuse when there is no polymorphic relationship. The guide is that inheritance should be only used when a subclass ‘is a’ super class.
  • Don’t use inheritance just to get code reuse. If there is no ‘is a’ relationship then use composition for code reuse. Overuse of implementation inheritance (uses the “extends” key word) can break all the subclasses, if the super class is modified. This is due to tight coupling occurring between the parent and the child classes happening at compile time.
  • Do not use inheritance just to get polymorphism. If there is no ‘is a’ relationship and all you want is polymorphism then use interface inheritance with composition, which gives you code reuse and runtime flexibility.
This is the reason why the GoF (Gang of Four) design patterns favor composition over inheritance. The interviewer will be looking for the key terms -- "coupling", "static versus dynamic" and  "happens at compile-time vs runtime" in your answers.The runtime flexibility is achieved in composition as the classes can be composed dynamically at runtime either conditionally based on an outcome or unconditionally. Whereas an inheritance is static.

Q. Can you differentiate compile-time inheritance and runtime inheritance with examples and specify which Java supports?
The term “inheritance” refers to a situation where behaviors and attributes are passed on from one object to another. The Java programming language natively only supports compile-time inheritance through subclassing as shown below with the keyword “extends”.


public class Parent {
    public String saySomething( ) {
          return “Parent is called”;
    }
}


public class Child extends Parent {
     @Override
     public String saySomething( ) {
          return super.saySomething( ) +  “, Child is called”;
    }
}

A call to saySomething( ) method on the class “Child” will return “Parent is called, Child is called” because the Child class inherits “Parent is called” from the class Parent. The keyword “super” is used to call the method on the “Parent” class. Runtime inheritance refers to the ability to construct the parent/child hierarchy at runtime. Java does not natively support runtime inheritance, but there is an alternative concept known as “delegation” or “composition”, which refers to constructing a hierarchy of object instances at runtime. This allows you to simulate runtime inheritance. In Java, delegation is typically achieved as shown below:


public class Parent {
    public String saySomething( ) {
          return “Parent is called”;
    }
}


public class Child  {
     public String saySomething( ) {
          return new Parent( ).saySomething( ) +  “, Child is called”;
    }
}

The Child class delegates the call to the Parent class. Composition can be achieved as follows:


public class Child  {
     private Parent parent = null;
     public Child( ){
          this.parent = new Parent( );
     }
     public String saySomething( ) {
          return this.parent.saySomething( ) +  “, Child is called”;
    }
}

Tricky Java interview questions and answers

Q. Can interfaces contain inner classes?
Yes, but not recommended as it can compromise on clarity of your code.
The interface with an inner class for demo purpose only


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package innerstatic;
 
public interface InterfaceWithInnerClass {
     
     
    public static final Util UTIL = new Util( );
     
 
    public String getName(); // next node in this list
 
    public final static InterfaceWithInnerClass FIELD =
      //anonymous inner class as the interface field declaration 
      new InterfaceWithInnerClass() {
          public String getName() {
            return "Peter";
        }
    };
 
     
 //static inner class
    public static class Util {
        public String getDetail(){
            return FIELD.getName() + " age 25";
        }
    }
}


The class that implemnts the above interface.

1
2
3
4
5
6
7
8
9
10
11
12
13
package innerstatic;
 
public class Test implements InterfaceWithInnerClass {
 
    @Override
    public String getName() {
        return FIELD.getName() + " : " + UTIL.getDetail();
    }
     
    public static void main(String[] args) {
        System.out.println(new Test().getName());
    }
}

The output is:

Peter : Peter age 25


Q. What happens if you pass a primitive int value to a method that accepts

a) long primitive
b) float primitive
c) Float object
d) Number object

A.
a) A widening conversion takes place from int to long. So, no compile or run time error.
b) A widening conversion takes place from int to float. So, no compile or run time error.
c) compile-time error. primitive type int can be auto-boxed to type Integer, but type Integer and Float are derived from type Number, and don't have the parent child relationship. So, they cannot be implicityly or exlplicitly cast to each other.
d) primitive type int can be auto-boxed to type Integer, and then implicitly cast to type Number as Number and Integer have the parent child relationship. So, no compile or run time error.