Chapter 1. Declarations, Initialization and Scoping (Part-1)
Develop code that declares classes (including abstract and all forms of nested classes), interfaces, and enums, and includes the appropriate use of package and import statements (including static imports).
In this tutorial you will learn about Declaration, Class declaration, Class modifiers, Abstract classes, Inner Classes and Enclosing Instances, Typesafe enumerations and Properties of the enum type.
Declaration
Class declarations define new reference types and describe how they are implemented
A nested class is any class whose declaration occurs within the body of another class or interface. A top level class is a class that is not a nested class.
A named class may be declared abstract and must be declared abstract if it is incompletely implemented; such a class cannot be instantiated, but can be extended by subclasses. A class may be declared final, in which case it cannot have subclasses. If a class is declared public, then it can be referred to from other packages.
Each class except Object is an extension of (that is, a subclass of) a single existing class and may implement interfaces.
The body of a class declares members (fields and methods and nested classes and interfaces), instance and static initializers, and constructors. The scope of a member is the entire declaration of the class to which the member belongs. Field, method, member class, member interface, and constructor declarations may include the access modifiers public, protected, or private. The members of a class include both declared and inherited members. Newly declared fields can hide fields declared in a superclass or superinterface. Newly declared class members and interface members can hide class or interface members declared in a superclass or superinterface. Newly declared methods can hide, implement, or override methods declared in a superclass or superinterface.
Field declarations describe class variables, which are incarnated once, and instance variables, which are freshly incarnated for each instance of the class. A field may be declared final, in which case it can be assigned to only once. Any field declaration may include an initializer.
Member class declarations describe nested classes that are members of the surrounding class. Member classes may be static, in which case they have no access to the instance variables of the surrounding class; or they may be inner classes.
Member interface declarations describe nested interfaces that are members of the surrounding class.
Method declarations describe code that may be invoked by method invocation expressions. A class method is invoked relative to the class type; an instance method is invoked with respect to some particular object that is an instance of the class type. A method whose declaration does not indicate how it is implemented MUST be declared abstract. A method may be declared final, in which case it cannot be hidden or overridden. A method may be implemented by platform-dependent native code. A synchronized method automatically locks an object before executing its body and automatically unlocks the object on return, as if by use of a synchronized statement, thus allowing its activities to be synchronized with those of other threads.
Method names may be overloaded.
Instance initializers are blocks of executable code that may be used to help initialize an instance when it is created.
Static initializers are blocks of executable code that may be used to help initialize a class when it is first loaded.
Constructors are similar to methods, but cannot be invoked directly by a method call; they are used to initialize new class instances. Like methods, they may be overloaded.
Class declaration
A class declaration specifies a new named reference type:
ClassDeclaration:
ClassModifiers(optional) class Identifier Super(optional) Interfaces(optional) ClassBody
The "Identifier" in a class declaration specifies the name of the class. A compile-time error occurs if a class has the same simple name as any of its enclosing classes or interfaces.
Class modifiers
A class declaration may include class modifiers (one of):
public protected private
abstract static final strictfp
Not all modifiers are applicable to all kinds of class declarations. The access modifier public pertains only to top level classes and to member classes. The access modifiers protected and private pertain only to member classes within a directly enclosing class declaration. The access modifier static pertains only to member classes. A compile-time error occurs if the same modifier appears more than once in a class declaration. If two or more class modifiers appear in a class declaration, then it is customary, though not required, that they appear in the order consistent with that shown above.
Abstract classes
An abstract class is a class that is incomplete, or to be considered incomplete. Only abstract classes may have abstract methods, that is, methods that are declared but not yet implemented. If a class that is not abstract contains an abstract method, then a compile-time error occurs. A class C has abstract methods if any of the following is true:
- C explicitly contains a declaration of an abstract method.
- Any of C's superclasses declares an abstract method that has not been implemented in C or any of its superclasses.
- A direct superinterface of C declares or inherits a method (which is therefore necessarily abstract) and C neither declares nor inherits a method that implements it.
In the example:
abstract class Point {
.....int x = 1, y = 1;
.....void move(int dx, int dy) {
..........x += dx;
..........y += dy;
..........alert();
.....}
.....abstract void alert();
}
abstract class ColoredPoint extends Point {
.....int color;
}
class SimplePoint extends Point {
.....void alert() { }
} |
a class Point is declared that must be declared abstract, because it contains a declaration of an abstract method named alert. The subclass of Point named ColoredPoint inherits the abstract method alert, so it must also be declared abstract. On the other hand, the subclass of Point named SimplePoint provides an implementation of alert(), so it need not be abstract.
A compile-time error occurs if an attempt is made to create an instance of an abstract class using a class instance creation expression.
Thus, continuing the example just shown, the statement:
Point p = new Point(); // wrong
would result in a compile-time error; the class Point cannot be instantiated because it is abstract. However, a Point variable could correctly be initialized with a reference to any subclass of Point, and the class SimplePoint is not abstract, so the statement:
Point p = new SimplePoint(); // correct
would be correct.
A subclass of an abstract class that is not itself abstract may be instantiated, resulting in the execution of a constructor for the abstract class and, therefore, the execution of the field initializers for instance variables of that class. Thus, in the example just given, instantiation of a SimplePoint causes the default constructor and field initializers for x and y of Point to be executed. It is a compile-time error to declare an abstract class type such that it is not possible to create a subclass that implements all of its abstract methods. This situation can occur if the class would have as members two abstract methods that have the same method signature but different return types.
As an example, the declarations:
interface Colorable {
.....void setColor(int color);
}
abstract class Colored implements Colorable {
.....abstract int setColor(int color);
} |
result in a compile-time error: it would be impossible for any subclass of class Colored to provide an implementation of a method named setColor, taking one argument of type int, that can satisfy both abstract method specifications, because the one in interface Colorable requires the same method to return no value, while the one in class Colored requires the same method to return a value of type int.
A class type should be declared abstract only if the intent is that subclasses can be created to complete the implementation. If the intent is simply to prevent instantiation of a class, the proper way to express this is to declare a constructor of no arguments, make it private, never invoke it, and declare no other constructors. A class of this form usually contains class methods and variables. The class Math is an example of a class that cannot be instantiated; its declaration looks like this:
public final class Math {
.....private Math() { } // never instantiate this class
.....// ... declarations of class variables and methods ...
} |
Inner Classes and Enclosing Instances
An inner class is a nested class that is not explicitly or implicitly declared static. Inner classes may not declare static initializers or member interfaces. Inner classes may not declare static members, unless they are compile-time constant fields.
To illustrate these rules, consider the example below:
|
class HasStatic{
.....static int j = 100;
}
class Outer{
.....class Inner extends HasStatic{
..........static final x = 3;
..........// ok - compile-time constant
..........static int y = 4;
..........// compile-time error, an inner class
.....}
.....static class NestedButNotInner{
..........static int z = 5;
..........// ok, not an inner class
.....}
.....interface NeverInner{}
.....// interfaces are never inner
}
|
Inner classes may inherit static members that are not compile-time constants even though they may not declare them. Nested classes that are not inner classes may declare static members freely, in accordance with the usual rules of the Java programming language. Member interfaces are always implicitly static so they are never considered to be inner classes.
A statement or expression occurs in a static context if and only if the innermost method, constructor, instance initializer, static initializer, field initializer, or explicit constructor statement enclosing the statement or expression is a static method, a static initializer, the variable initializer of a static variable, or an explicit constructor invocation statement.
Any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared final, and must be definitely assigned before the body of the inner class.
Inner classes include local, anonymous and non-static member classes. Here are some examples:
|
class Outer {
.....int i = 100;
.....static void classMethod() {
..........final int l = 200;
..........class LocalInStaticContext{
...............int k = i; // compile-time error
...............int m = l; // ok
..........}
.....}
.....void foo() {
..........class Local { // a local class
...............int j = i;
..........}
.....}
}
|
The declaration of class LocalInStaticContext occurs in a static context-within the static method classMethod. Instance variables of class Outer are not available within the body of a static method. In particular, instance variables of Outer are not available inside the body of LocalInStaticContext. However, local variables from the surrounding method may be referred to without error (provided they are marked final).
Inner classes whose declarations do not occur in a static context may freely refer to the instance variables of their enclosing class. An instance variable is always defined with respect to an instance. In the case of instance variables of an enclosing class, the instance variable must be defined with respect to an enclosing instance of that class. So, for example, the class Local above has an enclosing instance of class Outer. As a further example:
|
class WithDeepNesting {
.....boolean toBe;
.....WithDeepNesting(boolean b) { toBe = b;}
.....class Nested {
.....boolean theQuestion;
.....class DeeplyNested {
..........DeeplyNested(){
....................theQuestion = toBe || !toBe;
...............}
..........}
.....}
}
|
Here, every instance of WithDeepNesting.Nested.DeeplyNested has an enclosing instance of class WithDeepNesting.Nested (its immediately enclosing instance) and an enclosing instance of class WithDeepNesting (its 2nd lexically enclosing instance).
Typesafe enumerations
The J2SE 5.0 enum declaration looks as follows:
|
public enum MainMenu {FILE, EDIT, FORMAT, VIEW};
enum MachineState { BUSY, IDLE, BLOCKED } // Canonical form
enum Day {
.....MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
.....FRIDAY, SATURDAY, SUNDAY
}
|
This approach has many advantages including:
- It provides strong compile-time type safety
- It provides a separate namespace for each enum type and thus eliminates the need to include a prefix in each constant name
- Constants are not compiled into clients so you can freely add, remove, or reorder them without recompiling the clients
- Printed values are informative instead of just numbers
- Enum constants can be used wherever objects can be used
There are a couple of important things to note about enum declarations. As an example, consider the following declaration:
public enum MainMenu {FILE, EDIT, FORMAT, VIEW};
- Keyword enum is used to declare an enum type.
- The word enum is reserved and therefore if you have been using it as an identifier, you should adjust your code when compiling with a J2SE 5.0 compiler.
- The above enum declaration generates a class (MainMenu in the above example), which automatically implements the Comparable and Serializable interfaces, and provides several members including:
- Static variables FILE, EDIT, FORMAT, and VIEW.
- Static method values(), which is an array containing the constants in the enum.
- Static method valueOf(String) that returns the appropriate enum for the string passed in.
- Appropriately overloaded equals(), hasCode(), toString(), and compareTo() methods.
Here is a complete example that declares an enumeration and then prints the values:
|
public class Example {
.....public enum MainMenu {FILE, EDIT, FORMAT, VIEW}
.....public static void main(String[] argv) {
..........for (MainMenu menu : MainMenu.values()) {
...............System.out.println(menu);
..........}
.....}
}
|
And the following segment of code shows another example using the switch statement:
|
for(MainMenu menu : MainMenu.values()) {
.....switch(menu) {
..........case FILE:
...............System.out.println("FILE Menu");
...............break;
..........case EDIT:
...............System.out.println("EDIT Menu");
...............break;
..........case FORMAT:
...............System.out.println("FORMAT Menu");
...............break;
..........case VIEW:
...............System.out.println("VIEW Menu");
...............break;
.....}
}
|
It is worth noting that two classes have been added to java.util in support of enums: EnumSet (a high-performance Set implementation for enums; all members of an enum set must be of the same enum type) and EnumMap (a high-performance Map implementation for use with enum keys).
Properties of the enum type
An enum declaration is a special kind of class declaration:
- It can be declared at the top-level and as static enum declaration.
- It is implicitly static, i.e. no outer object is associated with an enum constant.
- It is implicitly final unless it contains constant-specific class bodies, but it can implement interfaces.
- It cannot be declared abstract unless each abstract method is overridden in the constant-specific class body of every enum constant.
|
// (1) Top level enum declaration
public enum SimpleMeal {
.....BREAKFAST, LUNCH, DINNER
}
|
public class EnumTypeDeclarations {
.....// (2) Static enum declaration is OK.
.....public enum SimpleMeal {
..........BREAKFAST, LUNCH, DINNER
.....};
.....public void foo() {
..........// (3) Local (inner) enum declaration is NOT OK!
..........enum SimpleMeal {
...............BREAKFAST, LUNCH, DINNER
..........}
.....}
} |
_____________
Author: Mikalai Zaikin. Please Click Here to visit Authors site for any updates and changes to the study notes.
Trackback(0)
|