Nested Classes
Nested Classes
Nested Classes
O clasa imbricata este, prin definitie, o clasa membra a unei alte clase, numita
si clasa de acoperire.
class OuterClass {
...
class NestedClass {
...
}
}
Terminology: Nested classes are divided into two categories: static and non-static.
Nested classes that are declared static are called static nested classes. Non-static
nested classes are called inner classes.
class OuterClass {
...
class InnerClass {
...
}
}
Static nested classes do not have access to other members of the enclosing
class.
As a member of the outer class, a nested class can be declared private, public,
protected, or package private. Outer classes can only be declared public or
package private.
1.1 Why Use Nested Classes?
It is a way of logically grouping classes that are only used in one place: If a
class is useful to only one other class, then it is logical to embed it in that class
and keep the two together. Nesting such "helper classes" makes their package
more streamlined.
It can lead to more readable and maintainable code: Nesting small classes
within top-level classes places the code closer to where it is used.
As with class methods and variables, a static nested class is associated with its outer
class. And like static 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.
Static nested classes are accessed using the enclosing class name:
OuterClass.StaticNestedClass
For example, to create an object for the static nested class, use this syntax:
OuterClass.StaticNestedClass nestedObject =
new OuterClass.StaticNestedClass();
1.3 Inner Classes
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 methods and fields. Also,
because an inner class is associated with an instance, it cannot define any static
members itself.
Objects that are instances of an inner class exist within an instance of the outer class.
class OuterClass {
...
class InnerClass {
...
}
}
An instance of InnerClass can exist only within an instance of OuterClass and has
direct access to the methods and fields of its enclosing instance.
To instantiate an inner class, you must first instantiate the outer class. Then, create the
inner object within the outer object with this syntax:
OuterClass.InnerClass innerObject =
outerObject.new InnerClass();
There are two special kinds of inner classes: local classes and anonymous
classes
1.3.1 Shadowing
public int x = 0;
class FirstLevel {
public int x = 1;
void methodInFirstLevel(int x) {
System.out.println("x = " + x);
System.out.println("this.x = " + this.x);
System.out.println("ShadowTest.this.x = " +
ShadowTest.this.x);
}
}
The output:
x = 23
this.x = 1
ShadowTest.this.x = 0
This example defines three variables named x: the member variable of the class
ShadowTest, the member variable of the inner class FirstLevel, and the parameter in
the method methodInFirstLevel. The variable x defined as a parameter of the method
methodInFirstLevel shadows the variable of the inner class FirstLevel. Consequently,
when you use the variable x in the method methodInFirstLevel, it refers to the method
parameter. To refer to the member variable of the inner class FirstLevel, use the keyword
this to represent the enclosing scope:
Refer to member variables that enclose larger scopes by the class name to which they
belong. For example, the following statement accesses the member variable of the class
ShadowTest from the method methodInFirstLevel:
There are two additional types of inner classes. You can declare an inner class within
the body of a method. These classes are known as local classes. You can also
declare an inner class within the body of a method without naming the class.
These classes are known as anonymous classes.
1.3.3 Modifiers
You can use the same modifiers for inner classes that you use for other members of
the outer class. For example, you can use the access specifiers private, public, and
protected to restrict access to inner classes, just as you use them to restrict access do
to other class members.
Local classes are classes that are defined in a block, which is a group of zero or
more statements between balanced braces. You typically find local classes defined
in the body of a method.
Topics:
You can define a local class inside any block. For example, you can define a
local class in a method body, a for loop, or an if clause.
class LocalClass {
...
LocalClass(...){ //constructor
...
}
public ... oneMethodOfLocalClass(...) {
...//return something (or not)
}
...
...
//call oneMethodOfLocalClass
myObject1.oneMethodOfLocalClass (...) ...
...
A local class has access to the members of its enclosing class. In the previous
example, LocalClass (…) constructor accesses the member
LocalClassExample.memberOfEnclosingClass.
In addition, a local class has access to local variables. However, a local class
can only access local variables that are declared final. When a local class
accesses a local variable or parameter of the enclosing block, it captures that
variable or parameter. For example, the LocalClass (…) constructor can access
the local variable localVariable because it is declared final; localVariable is a
captured variable.
However, starting in Java SE 8, a local class can access local variables and
parameters of the enclosing block that are final or effectively final. A variable
or parameter whose value is never changed after it is initialized is effectively
final.
Starting in Java SE 8, if you declare the local class in a method, it can access
the method's parameters.
1.4.2.1 Shadowing and Local Classes
Local classes are similar to inner classes because they cannot define or declare
any static members. Local classes in static methods, such as the class
LocalClass, which is defined in the static method method1, can only refer to
static members of the enclosing class. For example, if you do not define the
member variable memberOfEnclosingClass as static, then the Java compiler
generates an error similar to "non-static variable memberOfEnclosingClass
cannot be referenced from a static context."
Local classes are non-static because they have access to instance members of
the enclosing block. Consequently, they cannot contain most kinds of static
declarations.
Anonymous classes enable you to make your code more concise. They enable you to
declare and instantiate a class at the same time. They are like local classes except
that they do not have a name. Use them if you need to use a local class only once.
Topics:
While local classes are class declarations, anonymous classes are expressions,
meaning that you define the class in another expression.
The following example, HelloWorldAnonymousClasses, uses anonymous classes in
the initialization statements of the local variables frenchGreeting and
spanishGreeting, but uses a local class for the initialization of the variable
englishGreeting:
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
Like local classes, anonymous classes can capture variables; they have the same
access to local variables of the enclosing scope:
Anonymous classes also have the same restrictions as local classes with respect to
their members:
- Fields
- Extra methods (even if they do not implement any methods of the supertype)
- Instance initializers
- Local classes
One issue with anonymous classes is that if the implementation of your anonymous
class is very simple, such as an interface that contains only one method, then the
syntax of anonymous classes may seem unwieldy and unclear. In these cases, you're
usually trying to pass functionality as an argument to another method, such as what
action should be taken when someone clicks a button. Lambda expressions enable
you to do this, to treat functionality as method argument, or code as data.
Although this is often more concise than a named class, for classes with only one
method, even an anonymous class seems a bit excessive and cumbersome. Lambda
expressions let you express instances of single-method classes more compactly.
Nested classes enable you to logically group classes that are only used in one place,
increase the use of encapsulation, and create more readable and maintainable code.
Local classes, anonymous classes, and lambda expressions also impart these
advantages; however, they are intended to be used for more specific situations:
- Local class: Use it if you need to create more than one instance of a class,
access its constructor, or introduce a new, named type (because, for example,
you need to invoke additional methods later).
- Anonymous class: Use it if you need to declare fields or additional methods.
- Lambda expression:
- Use it if you are encapsulating a single unit of behavior that you want to
pass to other code.
- Use it if you need a simple instance of a functional interface and none of
the preceding criteria apply (for example, you do not need a constructor, a
named type, fields, or additional methods).
- Nested class: Use it if your requirements are similar to those of a local class,
you want to make the type more widely available, and you don't require access
to local variables or method parameters.
- Use a non-static nested class (or inner class) if you require access to an
enclosing instance's non-public fields and methods. Use a static nested
class if you don't require this access.
2. Enum Types
An enum type is a special data type that enables for a variable to be a set of
predefined constants. The variable must be equal to one of the values that have been
predefined for it. Common examples include compass directions (values of NORTH,
SOUTH, EAST, and WEST) and the days of the week.
Because they are constants, the names of an enum type's fields are in uppercase
letters.
In the Java programming language, you define an enum type by using the enum
keyword. For example, you would specify a days-of-the-week enum type as:
Here is some code that shows you how to use the Day enum defined above:
case FRIDAY:
System.out.println("Fridays are better.");
break;
default:
System.out.println("Midweek days are
so-so.");
break;
}
}
Java programming language enum types are much more powerful than their
counterparts in other languages. The enum declaration defines a class (called an
enum type). The enum class body can include methods and other fields. The
compiler automatically adds some special methods when it creates an enum. For
example, they have a static values method that returns an array containing all of
the values of the enum in the order they are declared. This method is commonly
used in combination with the for-each construct to iterate over the values of an
enum type. For example, this code from the Planet class example below iterates over
all the planets in the solar system.
In the following example, Planet is an enum type that represents the planets in the
solar system. They are defined with constant mass and radius properties.
Each enum constant is declared with values for the mass and radius parameters.
These values are passed to the constructor when the constant is created. Java
requires that the constants be defined first, prior to any fields or methods. Also, when
there are fields and methods, the list of enum constants must end with a semicolon.
Note: The constructor for an enum type must be package-private or private access.
It automatically creates the constants that are defined at the beginning of the enum
body. You cannot invoke an enum constructor yourself.
In addition to its properties and constructor, Planet has methods that allow you to
retrieve the surface gravity and weight of an object on each planet. Here is a sample
program that takes your weight on earth (in any unit) and calculates and prints your
weight on all of the planets (in the same unit):
public enum Planet {
MERCURY (3.303e+23, 2.4397e6),
VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6),
MARS (6.421e+23, 3.3972e6),
JUPITER (1.9e+27, 7.1492e7),
SATURN (5.688e+26, 6.0268e7),
URANUS (8.686e+25, 2.5559e7),
NEPTUNE (1.024e+26, 2.4746e7);
double surfaceGravity() {
return G * mass / (radius * radius);
}
double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("Usage: java Planet
<earth_weight>");
System.exit(-1);
}