[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 483
  • Last Modified:

Nested Interfaces and Classes

Please let me know the functionalities and usage of "Nested Interfaces" and "Classes" in JAVA. It's crucial to support the statements with small code snippets so that it goes into my brain. :-)

Regards,
perfect_tranquility
0
perfect_tranquility
Asked:
perfect_tranquility
5 Solutions
 
MogalManicCommented:
A nested class/interface, also known as inner classes, are meant for classes that depend on the functionality defined by the outer class.  For example the java.util.Map interface contains an inner interface called Map.Entry.  The Map.Entry interface contains the Key and Value one entry in a Map.  You cannot create a Map.Entry without first creating a Map.

An inner (non-static) class has access to its class members as well as its parent classes members.  Consider this example:

class foo
{
   int x=5;
   bar barRef=new bar();

   class bar
   {
       int x=5;
       public void method()
       {
           this.x=this.foo.x*this.x;
           this.foo.method();
       }
   }


   public void method()
   {
       this.x=this.x+1;
   }

   public static int main(String[] args)
   {
        foo y=new foo();
        y.method();
        y.barRef.method();
        System.out.println("y.x="+y.x);
        System.out.println("y.barRef.x="+y.barRef.x);
}

This example will output:
    y.x=7
    y.barRef.x=30
0
 
sudhakar_koundinyaCommented:
Java lets you define a class as a member of another class. Such a class is called a nested class and is illustrated here:

class EnclosingClass{
    . . .
    class ANestedClass {
        . . .
    }
}

    Definition:  A nested class is a class that is a member of another class.

You use nested classes to reflect and enforce the relationship between two classes. You should define a class within another class when the nested class makes sense only in the context of its enclosing class or when it relies on the enclosing class for its function. For example, a text cursor makes sense only in the context of a particular text component.

As a member of its enclosing class, a nested class has a special privilege: It has unlimited access to its enclosing class's members, even if they are declared private. However, this special privilege isn't really special at all. It is fully consistent with the meaning of private and the other access specifiers. The access specifiers restrict access to members for classes outside of the enclosing class. The nested class is inside of its enclosing class so that it has access to its enclosing class's members.

Like other members, a nested class can be declared static (or not). A static nested class is called just that: a static nested class. A nonstatic nested class is called an inner class. These are illustrated in the following code:

class EnclosingClass{
    . . .
    static class AStaticNestedClass {
        . . .
    }
    class InnerClass {
        . . .
    }
}

As with static methods and variables (normally called class methods and variables), a static nested class is associated with its enclosing class. And like class methods, a static nested class cannot refer directly to instance variables or methods defined in its enclosing class-it can use them only through an object reference.

As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's instance variables and methods. Also, because an inner class is associated with an instance, it cannot define any static members itself.

To help differentiate the terms nested class and inner class further, we suggest you think about them in the following way. The term "nested class" reflects the syntactic relationship between two classes; that is, syntactically, the code for one class appears within the code of another. In contrast, the term "inner class" reflects the relationship between instances of the two classes. Consider the following classes:

class EnclosingClass {
    . . .
    class InnerClass {
        . . .
    }
}

The interesting feature about the relationship between these two classes is not that InnerClass is syntactically defined within EnclosingClass. Rather, it's that an instance of InnerClass can exist only within an instance of EnclosingClass and that it has direct access to instance variables and methods of its enclosing instance



    You may encounter nested classes of both kinds in the Java API and be required to use them. However, most nested classes that you write will be inner classes.

        Definition:  An inner class is a nested class whose instance exists within an instance of its enclosing class and has direct access to the instance members of its enclosing instance.

Other Facts about Nested Classes

    Like other classes, nested classes can be declared abstract or final. The meaning of these two modifiers for nested classes is the same as for other classes. Also, the access specifiers--private, public, protected, and package--- may be used to restrict access to nested classes just as they do to other class members.

    Any nested class, not just anonymous ones, can be declared in any block of code. A nested class declared within a method or other smaller block of code has access to any final, local variables in scope.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
sudhakar_koundinyaCommented:
Nested classes are simply static inner classes. The difference between nested classes and inner classes is the same as the difference between static and nonstatic members of a class: nested classes are associated with the enclosing class itself, whereas inner classes are associated with an object of the enclosing class.

Because of this, inner class objects require an object of the enclosing class, while nested class objects do not. Nested classes, therefore, behave just like top-level classes, using the enclosing class to provide a package-like organization. In addition, nested classes have access to all members of the enclosing class.
0
 
doronbCommented:
First compile this class:

import java.util.*;
import java.lang.reflect.*;

public class IteratorVisitor {
      private final static Hashtable visitors = new Hashtable();
      private ItemVisitor itemVisitor;
      private Class[] visitorParamTypes;
      private Object[] visitorParams;
      private Method visitorMethd;

      public interface ItemVisitor {}

      public static Object visitIterator(Iterator iter, ItemVisitor visitor) {
            return visitIterator(false, iter, visitor);
      }

      public static Object visitIterator(boolean allMatches, Iterator iter, ItemVisitor visitor) {
            Class visitorClass = visitor.getClass();
            IteratorVisitor iv = (IteratorVisitor)visitors.get(visitorClass);
            if (iv == null) {
                  iv = new IteratorVisitor(visitor);
                  visitors.put(visitorClass, iv);
            } else {
                  iv.itemVisitor = visitor;
            }
            iv.visitIterator(allMatches, iter);
            return iv.visitorParams[1];
      }

      private IteratorVisitor(ItemVisitor itemVisitor) {
            this.itemVisitor = itemVisitor;
            Class[] classTypes = null;
            Method[] methods = itemVisitor.getClass().getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                  visitorMethd = methods[i];
                  if (visitorMethd.getName().equals("visitNextItem")) {
                        classTypes = visitorMethd.getParameterTypes();
                        if (classTypes != null && classTypes.length == 2 && classTypes[0] == Iterator.class) {
                              visitorParamTypes = new Class[] {Iterator.class, classTypes[1]};
                              visitorParams = new Object[2];
                              return;
                        }
                  }
            }
            itemVisitor = null;
            visitorParamTypes = null;
            visitorParams = null;
            visitorMethd = null;
      }

      private void visitIterator(boolean allMatches, Iterator iter) {
            Vector items = null;
            Boolean quitFlag = null;
            boolean done = false;
            if (visitorMethd != null && iter != null) {
                  visitorParams[0] = iter;
                  while (!done && iter.hasNext()) {
                        visitorParams[1] = iter.next();
                        try {
                              quitFlag = ((Boolean)visitorMethd.invoke(itemVisitor, visitorParams));
                              if (quitFlag != null) {
                                    done = quitFlag.booleanValue();
                                    if (done && allMatches) {
                                          done = false;
                                          if (items == null) {
                                                items = new Vector();
                                          }
                                          items.addElement(visitorParams[1]);
                                    }
                              }
                        } catch (InvocationTargetException ex) {
                        } catch (IllegalArgumentException ex) {
                        } catch (IllegalAccessException ex) {
                        }
                  }
                  if (!done) {
                        visitorParams[1] = (items == null) ? null : items.toArray();
                  }
            }
      }
}

Now, every time you need to go through an Iterator to perform some boring task, you can do something like this:

      public static void displayAllMatches(final String name, Iterator iter) {
            IteratorVisitor.visitIterator(iter, new IteratorVisitor.ItemVisitor() {
                  public void visitNextItem(Iterator iter, Person person) {
                        if (person.getLastName().equals(name)) {
                              System.out.println(person);
                        }
                  }
            });
      }

      public static Object returnFirstMatch(final String name, Iterator iter) {
            return IteratorVisitor.visitIterator(iter, new IteratorVisitor.ItemVisitor() {
                  public boolean visitNextItem(Iterator iter, Person person) {
                        return (person.getLastName().equals(name));
                  }
            });
      }

      public static Object[] returnAllMatches(final String name, Iterator iter) {
            return (Object[])IteratorVisitor.visitIterator(true, iter, new IteratorVisitor.ItemVisitor() {
                  public boolean visitNextItem(Iterator iter, Person person) {
                        return (person.getLastName().equals(name));
                  }
            });
      }

As you can see, each of the visitNextItem(Iterator, <Object>) already accepts the proper instance already casted to whatever you need. :)
0
 
doronbCommented:
Another example I have has to do with Delegates :)

I start off with this:

public interface Delegate {
      public void register(Object instance, String methodName) throws IllegalArgumentException;
      public void unRegister(Object instance, String methodName) throws IllegalArgumentException;
      public void unRegister(Object instance) throws IllegalArgumentException;
      public void register(Class instanceClass, String methodName) throws IllegalArgumentException;
      public void unRegister(Class instanceClass, String methodName) throws IllegalArgumentException;
      public void unRegister(Class instanceClass) throws IllegalArgumentException;
      public boolean hasExceptions();
      public Throwable[] getExceptions();
}

Then, I can build on the Delegate interface and do this:

public interface IntTestInterface extends Delegate {
      public int operateOnTwoNumbers(int a, int b);
      public IntTestInterface Delegate = (IntTestInterface)DelegateManager.CreateDelegate(IntTestInterface.class);
}

public interface VoidTestInterface extends Delegate {
      public void operateOnTwoNumbers(int a, int b);
      public VoidTestInterface Delegate = (VoidTestInterface)DelegateManager.CreateDelegate(VoidTestInterface.class);
}

After defining the test interfaces, my test program looks like this:

public class TestApp {
      private interface MaxOperation extends Delegate {
            public int max(int val0, int val1);
      }

      private MaxOperation maxDelegate = (MaxOperation)DelegateManager.CreateDelegate(MaxOperation.class);

      private static final IntTestInterface intTester = IntTestInterface.Delegate;
      private static final VoidTestInterface voidTester = VoidTestInterface.Delegate;

      public TestApp() {
            maxDelegate.register(this, "findMaxValue");
      }

      public static void main(String[] args) {
            TestApp ta = new TestApp();
            try {
                  voidTester.register(ta, "vAddTwoNumbers");
                  voidTester.register(TestApp.class, "vSubTwoNumbers");
                  intTester.register(ta, "addTwoNumbers");
                  intTester.register(TestApp.class, "subTwoNumbers");
            } catch (IllegalArgumentException ex) {
                  ex.printStackTrace();
            }
            System.out.println(intTester.operateOnTwoNumbers(2, 3));
            showExceptions(intTester);
            voidTester.operateOnTwoNumbers(7, 9);
            showExceptions(voidTester);
            System.out.println(ta.maxDelegate.max(1000, 999));
            System.out.println("Test Complete.");
      }

      private static void showExceptions(Delegate delegate) {
            if (delegate.hasExceptions()) {
                  Throwable[] exceptionList = delegate.getExceptions();
                  for (int i = 0; i < exceptionList.length; i++) {
                        exceptionList[i].printStackTrace();
                  }
            }
      }

      private int findMaxValue(int value0, int value1) {
            return Math.max(value0, value1);
      }

      private int addTwoNumbers(int numberOne, int numberTwo) {
            return (numberOne + numberTwo);
      }

      private void vAddTwoNumbers(int numberOne, int numberTwo) {
            System.out.println((numberOne + numberTwo));
      }

      private static int subTwoNumbers(int numberOne, int numberTwo) {
            return (numberOne - numberTwo);
      }

      private static void vSubTwoNumbers(int numberOne, int numberTwo) {
            if (numberOne == 7) {
                  throw new NullPointerException("OOPS!");
            }
            System.out.println(numberOne - numberTwo);
      }
}

The output follows:

java.lang.IllegalArgumentException: Only one Non-Void Method is allowed to register.
      at com.pss.util.delegates.TestApp.main(TestApp.java:23)
java.lang.NullPointerException: OOPS!
      at com.pss.util.delegates.TestApp.vSubTwoNumbers(TestApp.java:62)
      at com.pss.util.delegates.TestApp.main(TestApp.java:29)
5
16
1000
Test Complete.

Of course none of this would work for you right now since DelegateManager is missing, but I the point is, inner interfaces and classes are quite useful.
0
 
sudhakar_koundinyaCommented:
:)
0

Featured Post

Important Lessons on Recovering from Petya

In their most recent webinar, Skyport Systems explores ways to isolate and protect critical databases to keep the core of your company safe from harm.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now