Thursday 9 March 2017

Introducing Nested and Inner Classes, Exploring the String Class & Using Command-Line Arguments - Java Tutorials

Introducing Nested and Inner Classes

It is possible to define a class within another class; such classes are known as nested classes. The scope of a nested class is bounded by the scope of its enclosing class. Thus, if class B is defined within class A, then B is known to A, but not outside of A. A nested class has access to the members, including private members, of the class in which it is nested. However, the enclosing class does not have access to the members of the nested class.

There are two types of nested classes: static and non-static. A static nested class is one which has the static modifier applied. Because it is static, it must access the members of its enclosing class through an object. That is, it cannot refer to members of its enclosing class directly. Because of this restriction, static nested classes are seldom used. 

The most important type of nested class is the inner class. An inner class is a non-static nested class. It has access to all of the variables and methods of its outer class and may refer to them directly in the same way that other non-static members of the outer class do. Thus, an inner class is fully within the scope of its enclosing class.

The following program illustrates how to define and use an inner class. The class named Outer has one instance variable named outer_x, one instance method named test( ), and defines one inner class called Inner.

  // Demonstrate an inner class.
  class Outer {
    int outer_x = 100;

    void test() {
      Inner inner = new Inner();
      inner.display();
    }

    // this is an inner class
    class Inner {
      void display() {
        System.out.println("display: outer_x = " + outer_x);
      }
    }
  }

  class InnerClassDemo {
    public static void main(String args[]) {
      Outer outer = new Outer();
      outer.test();
    }
  }

Output from this application is shown here:

  display: outer_x = 100

In the program, an inner class named Inner is defined within the scope of class Outer. Therefore, any code in class Inner can directly access the variable outer_x. An instance method named display( ) is defined inside Inner. This method displays outer_x on the standard output stream. The main( ) method of InnerClassDemo creates an instance of class Outer and invokes its test( ) method. That method creates an instance of class Inner and the display( ) method is called.

It is important to realize that class Inner is known only within the scope of class Outer. The Java compiler generates an error message if any code outside of class Outer attempts to instantiate class Inner. Generalizing, a nested class is no different than any other program element: it is known only within its enclosing scope.

As explained, an inner class has access to all of the members of its enclosing class, but the reverse is not true. Members of the inner class are known only within the scope of the inner class and may not be used by the outer class. For example,

  // This program will not compile.
  class Outer {
    int outer_x = 100;

    void test() {
      Inner inner = new Inner();
      inner.display();
    }

    // this is an inner class
    class Inner {
      int y = 10; // y is local to Inner
      void display() {
        System.out.println("display: outer_x = " + outer_x);
      }
    }

    void showy() {
      System.out.println(y); // error, y not known here!
    }
  }

  class InnerClassDemo {
    public static void main(String args[]) {
      Outer outer = new Outer();
      outer.test();
    }
  }

Here, y is declared as an instance variable of Inner. Thus it is not known outside of that class and it cannot be used by showy( ).

Although we have been focusing on nested classes declared within an outer class scope, it is possible to define inner classes within any block scope. For example, you can define a nested class within the block defined by a method or even within the body of a for loop, as this next program shows.

  // Define an inner class within a for loop.
  class Outer {
    int outer_x = 100;

    void test() {
      for(int i=0; i<10; i++) {
        class Inner {
          void display() {
            System.out.println("display: outer_x = " + outer_x);
          }
        }

        Inner inner = new Inner();
        inner.display();
      }
    }
  }

  class InnerClassDemo {
    public static void main(String args[]) {
      Outer outer = new Outer();
      outer.test();
    }
  }

The output from this version of the program is shown here.

  display: outer_x = 100
  display: outer_x = 100
  display: outer_x = 100
  display: outer_x = 100
  display: outer_x = 100
  display: outer_x = 100
  display: outer_x = 100
  display: outer_x = 100
  display: outer_x = 100
  display: outer_x = 100

While nested classes are not used in most day-to-day programming, they are particularly helpful when handling events in an applet. We will return to the topic of nested classes in Chapter 20. There you will see how inner classes can be used to simplify the code needed to handle certain types of events. You will also learn about anonymous inner classes, which are inner classes that don't have a name.

One final point: Nested classes were not allowed by the original 1.0 specification for Java. They were added by Java 1.1.




Exploring the String Class

Although the String class will be examined in depth in Part II of this book, a short exploration of it is warranted now, because we will be using strings in some of the example programs shown toward the end of Part I. String is probably the most commonly used class in Java’s class library. The obvious reason for this is that strings are a very important part of programming.

The first thing to understand about strings is that every string you create is actually an object of type String. Even string constants are actually String objects. For example, in the statement

  System.out.println("This is a String, too");

the string “This is a String, too” is a String constant. Fortunately, Java handles String constants in the same way that other computer languages handle “normal” strings, so you don’t have to worry about this.

The second thing to understand about strings is that objects of type String are immutable; once a String object is created, its contents cannot be altered. While this may seem like a serious restriction, it is not, for two reasons:
  • If you need to change a string, you can always create a new one that contains the modifications.
  • Java defines a peer class of String, called StringBuffer, which allows strings to be altered, so all of the normal string manipulations are still available in Java. (StringBuffer is described in Part II of this book.)

Strings can be constructed a variety of ways. The easiest is to use a statement like this:

  String myString = "this is a test";

Once you have created a String object, you can use it anywhere that a string is allowed. For example, this statement displays myString:

  System.out.println(myString);

Java defines one operator for String objects: +. It is used to concatenate two strings. For example, this statement

  String myString = "I" + " like " + "Java.";

results in myString containing “I like Java.” The following program demonstrates the preceding concepts:

  // Demonstrating Strings.
  class StringDemo {
    public static void main(String args[]) {
      String strOb1 = "First String";
      String strOb2 = "Second String";
      String strOb3 = strOb1 + " and " + strOb2;
      System.out.println(strOb1);
      System.out.println(strOb2);
      System.out.println(strOb3);
    }
  }

The output produced by this program is shown here:

  First String
  Second String
  First String and Second String

The String class contains several methods that you can use. Here are a few. You can test two strings for equality by using equals( ). You can obtain the length of a string by calling the length( ) method. You can obtain the character at a specified index within a string by calling charAt( ). The general forms of these three methods are shown here:
  • boolean equals(String object)
  • int length( )
  • char charAt(int index)

Here is a program that demonstrates these methods:

  // Demonstrating some String methods.
  class StringDemo2 {
    public static void main(String args[]) {
      String strOb1 = "First String";
      String strOb2 = "Second String";
      String strOb3 = strOb1;

      System.out.println("Length of strOb1: " +
                          strOb1.length());

      System.out.println("Char at index 3 in strOb1: " +
                          strOb1.charAt(3));

      if(strOb1.equals(strOb2))
        System.out.println("strOb1 == strOb2");
      else
        System.out.println("strOb1 != strOb2");

      if(strOb1.equals(strOb3))
        System.out.println("strOb1 == strOb3");
      else
        System.out.println("strOb1 != strOb3");
    }
  }

This program generates the following output:

  Length of strOb1: 12
  Char at index 3 in strOb1: s
  strOb1 != strOb2
  strOb1 == strOb3

Of course, you can have arrays of strings, just like you can have arrays of any other type of object. For example:

  // Demonstrate String arrays.
  class StringDemo3 {
    public static void main(String args[]) {
      String str[] = { "one", "two", "three" };

      for(int i=0; i<str.length; i++)
        System.out.println("str[" + i + "]: " + str[i]);
    }
  }

Here is the output from this program:

  str[0]: one
  str[1]: two
  str[2]: three

As you will see in the following section, string arrays play an important part in many Java programs.




Using Command-Line Arguments

Sometimes you will want to pass information into a program when you run it. This is accomplished by passing command-line arguments to main( ). A command-line argument is the information that directly follows the program’s name on the command line when it is executed. To access the command-line arguments inside a Java program is quite easy—they are stored as strings in the String array passed to main( ). For example, the following program displays all of the command-line arguments that it is called with:

  // Display all command-line arguments.
  class CommandLine {
    public static void main(String args[]) {
      for(int i=0; i<args.length; i++)
        System.out.println("args[" + i + "]: " + args[i]);
    }
  }

Try executing this program, as shown here:

  java CommandLine this is a test 100 -1

When you do, you will see the following output:

  args[0]: this
  args[1]: is
  args[2]: a
  args[3]: test
  args[4]: 100
  args[5]: -1

All command-line arguments are passed as strings. You must convert numeric values to their internal forms manually.

No comments:

Post a Comment