A class definition is the fundamental mechanism for encapsulation of data and functionality in Java. In the object-oriented approach, a class describes a set of similar objects - objects with the same properties and functionality. These objects are called instances of the class. The class declaration defines the data an instance will contain and the functionality (methods) an instance will provide. A class declaration can be thought of as a "template" for creating new instances.
A class declaration also defines a reference type. Values of this type are references to instances of the class, or to instances of subclasses of the class.
A class can be a member of a package, in which case it is called an outer class or top-level class. Or it can be a member of another class, in which case it is a nested class or inner class.
The fully-qualified name of an outer class consists of the class name prefixed with the package name: e.g.,
java.util.Vector javax.swing.text.html.HTML
are fully-qualified names of the class Vector
defined in the package java.util
, and of the class HTML
defined in the package javax.swing.text.html
. A nested class is named by prefixing the class name with the name of the containing class:
e.g.,
javax.swing.text.html.HTML.Tag
is the name of the class Tag
defined in the class javax.swing.text.html.HTML
.
A class may be anonymous, in which case it does not have a name.
A class declaration consists of a heading and a body. The heading specifies the name of the class, the (super)class that the class extends, and any interfaces the class implements. The body is enclosed in braces and follows the heading. The body contains the declarations of class members.
An interface is a structure that is in many ways similar to a class. An interface contains only specification information, and no implementation. Interfaces are considered in a separate section.
A class heading consists of the key word class
followed by an identifier that names the class.
A class that is a member of a package may be specified public
, in which case its scope is global:
i.e., it is visible throughout the entire program. For instance,
public class Circle
Otherwise its scope is limited to the package of which it is a member. That is, the class can be accessed only from package members.
A class may be specified as final
, in which case it cannot be extended. For instance,
public final class Math
A class may be specified as abstract
. Abstract classes are discussed below.
A class that is a member of another class may have its scope modified just as any other class member. It may also be declared static
. Scope modifiers and static modifiers of class members are explained below.
Modifiers can be written in any order. Thus specifications
public abstract class List
and
abstract public class List
are equivalent.
If the class explicitly extends a (super)class or implements an interface, these are listed following the name of the class. The superclass is named in an
extends clause, consisting of the keyword extends
followed by the name of the superclass. For instance,
public class EnchantedRoom extends Room
A class extends exactly one other class. If an extends clause is not included in the class heading, the class implicitly extends java.lang.Object
.
Any interfaces explicitly implemented by the class are named in an
implements clause, consisting of the key word implements
followed by a comma separated list of interfaces. For example,
public class Room implements Cloneable, MazeFeature
A class heading may contain both an extends clause and an implements clause. In this case, the extends clause precedes the implements clause.
public class HexedRoom extends Room implements HexedObject
Extending classes and implementing interfaces are explained below.
A class body contains a sequence of member declarations, constructor declarations, and initializers, enclosed in braces. Class members are variables, named constants, methods, classes, and interfaces. The heading and the body make up the class declaration. For instance, the class declaration
public class Circle { // A constructor declaration: public Circle (int radius) { this.radius = radius; } // A method declaration: public int radius () { return this.radius; } // A variable declaration: private int radius; }
defines a class named Circle
, with one constructor and two members: a method radius
, and a variable also named radius
. Objects that are instances of the class are created by invoking the constructor. For example, the constructor invocation
new Circle(10)
creates a Circle
instance, and returns a reference to the newly created instance. The type of the value returned is
reference-to-Circle
.
Class members are variables, named constants, methods, classes, and interfaces. Members are either declared in the class, inherited from a superclass, or inherited from an interface that the class implements.
Members are either associated with the class itself or with each instance of the class. If the member is specified as static
, it is associated with the class itself rather than with an instance of the class. Examples are:
static void main (String[] args) { ... } static boolean condition (boolean preCondition) { ... }
Non-static members are associated with each instance of the class. We refer to non-static members as "instance members." Suppose, for example, a class Monitor
contains the following variable declarations:
public class Monitor { ... private static int global = 0; private int local; }
The first declaration results in creation of a single variable named global
. This variable exists whether or not the class is ever instantiated. However, each instance of the class has its own variable named local
. The variable is created when the instance is created.
A variable, method, and class defined in the same class can all have the same simple name. (The class Circle
shown above has both a method and variable named radius
, for instance.) A class can define several methods with the same name as long as the methods differ in the number and/or types of their parameters. (This is called "overloading.") For example, a class can contain the following three methods, all named m
:
public void m (Object obj) { ... } public void m (Circle c) { ... } public void m (Object obj, Circle c) { ... }
It may not contain both of these:
public void m () { ... } private Object m () { ... }
nor may it contain both of these:
public void m (int a) { ... } private Object m (int b) { ... }
The method name and list of parameter types is the
signature of the method. For instance, the first three methods named m
mentioned above have signatures
m (Object) m (Circle) m (Object, Circle)
A class cannot contain two methods with the same signature.
A member variable or method may be declared final
:
public static final int OPEN = 3; public final void move (int direction)
A final variable is essentially a named constant. Once assigned, it's value cannot be changed. Static final variables are typically initialized in their declaration, instance final variables in their declaration or in a class constructor.
Note, though, that if the value of a final variable is a reference value, the object referenced may change state. For example, suppose START
is defined as
public static final Room START = entryway;
where entryway
is a Room
. START
will always contain the same value - that is, it will always reference the same object. But the state of the object referenced can change.
A final method cannot be overridden. Overriding is explained below.
Static members are generally referenced by prefixing the member name with the class name. If the static method condition
specified above is defined in the class Require
, it can be invoked as
Require.condition(i >= 0);
An instance member can be accessed by prefixing the member name with a reference to the instance. For example, if monitor
is an instance of the class Monitor
:
Monitor monitor = new Monitor(...);
then monitor.local
denotes it's instance variable local
.
The reference need not be from a variable. It might be obtained by a method or constructor invocation. Suppose the class Monitor
contains a method
public Circle areaSurveyed ()
Then the method invocation
monitor.areaSurveyed()
produces a reference to a Circle
object, and
monitor.areaSurveyed().radius()
invokes the Circle
's radius
method.
Clearly, static members cannot reference instance members. For example, if the class Monitor
has a static method update
, this method cannot reference the variable local
.
public static void update () { // This method is not associated with any instance, // and so cannot reference instance members ... }
Within its class, a member can generally be accessed simply by its name. The name of a static member refers to the member associated with the class; the name of an instance member refers to the member associated with the executing instance. For example, if the class Monitor
sketched above contains the method
public void getGlobal () { local = global; }
the identifier global
refers to the static class variable, while the identifier local
refers to the instance variable associated with the Monitor
instance that is executing the method.
An exception is that a member variable cannot be accessed by its name alone within the scope of an automatic variable of the same name. For example, the occurrence of the identifier local
in the following method setLocal
refers to the parameter, not to the instance variable:
public class Monitor { ... public void setLocal (int local) { global = local; } ... private static int global; private int local; ... }
The keyword this
refers to the executing instance. Within its class, an instance member can always be accessed by prefixing its simple name with the keyword word this
. The following method copies the value of the parameter local
to the instance variable local
:
public void setLocal (int local) { this.local = local; }
A member of an instance of a textually enclosing class can be accessed by qualifying the keyword this
. For example, suppose Node
is an inner class of Bag
:
public class Bag { ... private Node first; ... private class Node { ... private Node first; } // end of class Node ... } // end of class Bag
Both Bag
and Node
have instance variables named first
. Within the class Node
, the Bag
's instance variable first
can be referenced as Bag.this.first
. The class Node
might contain a statement such as
this.first = Bag.this.first;
This assigns the value of the Bag
's instance variable first
to the Node
's instance variable first
. If the class Node
did not declare an instance variable named first
, the Bag
's variable could be accessed in Node
simply as first
.
A member defined in an immediate superclass can be accessed in the subclass by prefixing the member name with the keyword super
. This is useful for referencing overridden methods or hidden variables. For example, consider the class GrabBag
that extends Bag
:
public class Bag { ... public boolean equals (Object obj) { ... } ... protected int length; } public class GrabBag extends Bag { ... public boolean equals (Object obj) { ... } ... private double length; // hides inherited length }
GrabBag
overrides the Bag
method equals
, and declares its own variable length
, hiding the variable length
inherited from Bag
. In GrabBag
, the overridden method can be invoked as super.equals(someObject)
and the hidden variable accessed as super.length
. Hiding and overriding are explained below.
If an outer class is not declared public
, then access to any member of the class (or any member of a nested class) is restricted to the class's package. An outer class declared public
has global scope: the class can be referenced anywhere in the program. In the following discussion, we generally assume a public outer class.
A member can be specified as public
, protected
, or private
. Otherwise, the member is
restricted or package private.
public void reset () { ... } protected int numberTaken; int updateEnrollment (Student s) { ... } private class Node { ... } private int count;
Public members have the same scope as the class. For example, if size
is a public member of public class Bag
public class Bag { ... public int size () { ... } ... }
then the method size
has global scope. The following code
Bag b = new Bag(...); if (b.size() > 0) ...
can occur essentially anywhere in the program.
The scope of a private member is limited to the (outer) class declaration. For example, if length
is a private member of the class Bag
,
public class Bag { ... private int length; ... }
then the reference b.length
, where b
is a Bag
, can occur only in the body of Bag
: that is, only between the braces {
and }
that delimit the definition of Bag
.
The scope of a restricted member is the package of the outer class. If verify
is a restricted Bag
member,
public class Bag { ... void verify () { ... } ... }
the reference b.verify()
, where b
is again a Bag
, can occur anywhere in the package of which Bag
is a member.
Like restricted members, protected members are accessible in the package in which they are declared. A protected member may be accessed from outside the package only by code "responsible for the implementation of the object." That is, protected members are available (as inherited members) in subclasses of the defining class. Suppose limit
is a protected member of Bag
, and GrabBag
is a subclass:
public class Bag { ... protected int limit; ... } public class GrabBag extends Bag { ... }
If gb
is a GrabBag
, the reference gb.limit
is legal in Bag
, GrabBag
, and the package of which Bag
is a member. (Since GrabBag
is a subclass of Bag
, Bag
is "responsible for the implementation" of the GrabBag
object.) But it is not otherwise legal in a subclass of GrabBag
. In particular, the reference b.limit
, where b
is a Bag
, is not valid in GrabBag
unless GrabBag
and Bag
are in the same package.
The combination of packaging, inheritance, and scope specification can lead to very confusing situations. Suppose class Bottom
extends class Middle
which extends class Top
. Suppose further that Top
and Bottom
are in the same package, and that Middle
is in a different package.
Top
defines a restricted variable rest
and a protected variable prot
:
public class Top { ... int rest; protected int prot; }
Middle
does not inherit rest
since it is not in the same package as Top
. And since Bottom
extends Middle
, Bottom
does not inherit rest
.
However, since Top
and Bottom
are in the same package, the rest
variable of a Top
instance can be accessed in Bottom
. For instance, Bottom
can contain the method:
public setRest (Top t) { t.rest = 0; }
The protected variable prot
is inherited by Middle
, and hence by Bottom
. Both Middle
and Bottom
can contain the statement:
this.prot = 0;
or even:
prot = 0;
Furthermore, Middle
can reference the prot
member of a Bottom
(since as a superclass, Middle
code is "responsible" for the implementation of a Bottom
), but not of a Top
. That is, the class Middle
can contain this method:
public setBottomProt (Bottom b) { b.prot = 0; }
but not this one:
public setTopProt (Top t) { t.prot = 0; }
The class Bottom
can contain the method setTopProt
because Top
and Bottom
are in the same package. In fact, the class Bottom
can contain the method:
public setMidProt (Middle m) { m.prot = 0; }
because Bottom
is in the package in which prot
is declared.
We suggest the following use of scope specification:
Scope rules always refer to the outer class containing the definition. For example, if Node
is an inner class of Bag
defined as follows
public class Bag { ... private class Node { ... private Node next; } ... private int length; }
the Bag
variable length
and the Node
variable next
can be accessed anywhere in the declaration of the class Bag
. The class Bag
, for instance, could contain the method:
private Node advanceFrom (Node n, int i) { while (i > 0) { n = n.next; i = i-1; } return n; }
and the class Node
could contain:
private void evaporate () { length = length - 1; next.evaporate(); next = null; }
Every class (except the class java.lang.Object
)
extends exactly one other class. The class extended is specified in the class heading:
public class EnchantedRoom extends Room
If the class heading has no extends clause, the class extends java.lang.Object
. The extending class is a
subclass of the extended class; the extended class is a
superclass of the extending class. Thus EnchantedRoom
is a subclass of Room
, and Room
is a superclass of EnchantedRoom
.
The relations "subclass" and "superclass" are transitive. That is, if A extends B, and B extends C, then A is considered to be a subclass of C. But A is an immediate subclass of B only, and B is the immediate superclass of A.
A class may also implement any number of interfaces. These are also specified in the heading:
public class Ring extends Item implements Wearable, Hexable
The implementing class is a subclass of the interface, and the interface is a superinterface of the class.
A class inherits all the public and protected members of its immediate superclass and of any immediate superinterfaces. That is, members of the superclass or superinterface are also members of the class. A class also inherits restricted members of its immediate superclass if it is in the same package as its superclass.
Since inheriting from an interface is essentially the same as inheriting from a class, we limit our attention to classes in the following discussion.
If, for example, the class Room
defines the method getWidth
:
public class Room { ... public int getWidth () { ... } ... }
the class EnchantedRoom
also has this method as a member. If garden
is an EnchantedRoom
, the method can be invoked as garden.getWidth()
.
Subclasses of EnchantedRoom
will inherit the method from EnchantedRoom
.
Note that while a class does not technically inherit private members of its superclass, it still "has" these members: but they can be accessed only from the superclass declaration. Suppose the class Room
contains the following:
public class Room { ... public void setWidth (int newWidth) { this.width = newWidth; } ... private int width; }
The class EnchantedRoom
inherits the method setWidth
but not the variable width
. EnchantedRoom
could contain the method
public void doubleWidth () { this.setWidth(this.getWidth()*2); }
but neither the method
public void doubleWidth () { this.width = this.width*2; }
nor the method
public void doubleWidth () { super.width = super.width*2; }
The variable width
can only be accessed within the body of Room
.
If one class is a subclass of another, then the reference type associated with the first class is a subset of the reference type associated with the second. For instance, if class EnchantedRoom
extends class Room
, then every EnchantedRoom
instance is also a Room
. Thus a
reference-to-EnchantedRoom
is also a
reference-to-Room
, and the set of
references-to-EnchantedRoom
is a subset of the set of
references-to-Room
. The type
reference-to-EnchantedRoom
is said to be a
subtype of the type
reference-to-Room
.
The importance of subtyping is that an instance of a subclass of class
C can be provided in any context requiring an instance of
C. If a method requires a Room
as argument:
public void enter (Room room)
the method may be invoked with an EnchantedRoom
, or an instance of any other subclass of Room
, as an argument.
A class that declares a variable with the same name as one it inherits
hides the superclass variable. Suppose class Card
declares a variable value
public class Card { ... public int value = 3; }
and subclass HighCard
declares a variable of the same name
public class HighCard extends Card { ... public double value = 10.0; }
The double
variable declared in HighCard
hides the int
declared in Card
. In the class HighCard
, the identifier value
refers to the double
. The int
can be accessed as super.value
. The following method appearing in HighCard
public void printValues () { System.out.println(value + " " + super.value); }
will write a line containing
10.0 3
Note that which variable is accessed depends on the compile-time type of the reference. For example, the following method
public void printCardValue (Card c) { System.out.pritnln(c.value); }
will write out 3
even if it is invoked with a HighCard
argument:
printCardValue(new HighCard());
The compile-time type of the parameter c
is Card
, and it does not matter that c
references a HighCard
at run-time. It is Card
's instance variable value
that will be accessed in the method.
A class can
override an instance method that it inherits, providing a different implementation of the method from its superclass. Suppose the class Line
contains a method equals
defined as follows:
public class Line { ... public boolean equals (Object obj) { if (obj instanceof Line) return this.length == ((Line)obj).length; else return false; } private int length; }
The subclass ThickLine
overrides the method by providing a different implementation:
public class ThickLine extends Line { ... public boolean equals (Object obj) { if (obj instanceof ThickLine) return this.width == ((ThickLine)obj).width; else return false; } private int width; }
Which implementation is executed depends on the run-time class of the instance, not the compile-time type of the reference. (Compare this to hiding, discussed above.) If the method
public void compareLines (Line line1, Line line2) { if (line1.equals(line2)) ... }
is invoked with a ThickLine
as the first argument
compareLines(new ThickLine(...), ...);
the implementation of equals
defined in ThickLine
will be executed, even thought the compile-time type of the variable line1
is Line
, not ThickLine
.
The implementation of equals
defined in Line
can be referenced in ThickLine
by using the keyword super
. For instance, the method equals
in ThickLine
might be implemented as follows.
public boolean equals (Object obj) { if (super.equals(obj) && obj instanceof ThickLine) return this.width == ((ThickLine)obj).width; else return false; }
(Note: a static method can be hidden, like a variable, but not overridden.)
Overloading is semantically quite distinct from overriding. But because of the similarity in syntax, it is easy to confuse the two. Overloading is defining more than one method with the same name in the same class. Overriding involves defining two distinct implementations of a method in different classes.
Suppose the method equals
defined in ThickLine
is specified as
public boolean equals (ThickLine obj)
ThickLine
inherits the method public
boolean
equals
(Object
obj)
from Line
. Since the method defined in ThickLine
has a parameter of a different type, it overloads but does not override the inherited method. ThickLine
now has two methods named equal
, one inherited:
public boolean equals (Object obj)
and the other defined in the class:
public boolean equals (ThickLine obj)
Overloading is resolved at compile-time, with compile-time types. Run-time class is relevant only in override resolution. If
Line line1 = new ThickLine(...); Line line2 = new ThickLine(...);
the compile-time type of both line1
and line2
is Line
, regardless of the fact that these variables actually reference ThickLine
instances at run-time. The method invocation
line1.equals(line2)
executes the equals
method defined in Line
. The compile-time type of line1
is Line
, and the class Line
has only one equals
method. The fact that line1
and line2
both happen to reference ThickLine
instances at run-time is of no relevance.
Similarly, if
ThickLine tline = new ThickLine(...);
the method invocation
tline.equals(line1)
executes the equals
method defined in Line
and inherited by ThickLine
. The compile-time type of line1
is Line
, not ThickLine
. A
reference-to-Line
is also a
reference-to-Object
, since
reference-to-Line
is a subtype of
reference-to-Object
.
Reference-to-Line
is not a subtype of
reference-to-ThickLine
. At compile-time, the inherited method is the one that is matched. Once again, the fact that line1
actually refers to a ThickLine
at run-time is not relevant.
A class can be declared abstract
, as in
public abstract class List
An abstract class cannot be instantiated. An abstract class serves only as a base class for building subclasses. (A class that is not abstract is sometimes called "concrete.")
Since a constructor for an abstract class will only be invoked by the constructor of a subclass, it is conventionally declared protected:
public abstract class List { protected List () { ... }
An abstract class or an interface may have abstract methods as members. An abstract method has a heading but no body. Syntactically, the body is replaced by a semicolon:
public abstract List createList ();
A concrete subclass of an abstract class must override inherited abstract methods, providing implementations. Similarly, a concrete class that implements an interface must provide implementations for inherited abstract methods.
A class can be a member of another class, in which case it is a nested class or member class. A member class that is not static is called an inner class. Member classes can be qualified ( e.g., declared private) in ways similar to other class members.
Note, though, that member access is controlled with respect to the outer class. For instance, a private member of an inner class can be accessed in the outer class of which the inner class is a member. The instance variable next
of a Node
, as defined below, can be accessed anywhere in the declaration of the class Bag
:
public class Bag { ... private void chopAfter (Node n) { n.next = null; // this is OK } ... private class Node { ... private Node next; } // end of class Node ... } // end of class Bag
Also note that the reference type defined by an inner class does not depend on the instance of which the class is a component. Suppose the class Outer
is defined as follows:
public class Outer { public class Inner { public void setX (int i) { myX = i; } } public int myX; public Inner myInner; }
Each instance of the class Outer
has a member class Inner
. The setX
method of an Inner
instance sets the myX
variable of the containing Outer
instance. For example, consider the following code:
Outer o1 = new Outer(); Outer o2 = new Outer(); Outer.Inner oi1 = o1.new Inner(); Outer.Inner oi2 = o2.new Inner(); oi1.setX(1); oi2.setX(2); System.out.println(o1.myX); System.out.println(o2.myX);
First note the syntax. The type name of the inner classes is Outer.Inner
. The expression to instantiate the inner class associated with o1
is o1.new Inner()
. Invoking oi1.setX
modifies o1
's instance variable myX
. Invoking oi2.setX
modifies o2
's variable. The output will be
1 2
But the reference values oi1
and oi2
are of the same type:
reference-to-Outer.Inner
. Thus an assignment like
o1.myInner = oi2;
is syntactically correct. After this assignment, the statement
o1.myInner.setX(3);
will change o2
's instance variable myX
.
An anonymous class is a nameless class that is simultaneously declared and instantiated in a single expression. Each anonymous class is unique and has only one instance: the instance created when the class is defined.
An anonymous class has a "parent" that is either a class or an interface. The name of the parent is used when declaring and instantiating the class. The syntax for declaring and instantiating an anonymous class is
new parent(argument list) class body
Suppose the interface Portable
is defined as
public interface Portable { int weight (); }
An anonymous class that implements the interface can be declared and instantiated as
new Portable() { public int weight () { return 0; } }
Since the interface specifies the abstract method weight
, the implementing anonymous class must implement the method weight
.
Note carefully what is happening here. The interface is not instantiated. Rather a new, nameless concrete class that implements the interface is declared, and this new class is instantiated.
The anonymous class is an immediate subclass of Object
and implements the interface Portable
. We can write:
Portable balloon = new Portable() { public int weight () { return 0; } };
Constructors are not explicitly defined for anonymous classes. They are provided by default. The constructors for an anonymous class match the constructors of its immediate superclass. The anonymous class constructor simply invokes the corresponding superclass constructor. For example, the anonymous Portable
class defined above is an immediate subclass of Object
. Since Object
has one parameterless constructor, and so does the anonymous class. On the other hand, if the class Monitor
has two constructors, one with no parameters and one with an Observable
parameter,
public Monitor () { ... } public Monitor (Observable s) { ... }
then an anonymous subclass of Monitor
will also have a two constructors. For instance, we can declare and instantiate an anonymous subclass as follows, assuming that this
is an Observable
:
new Monitor (this) { public void update (Observable o, Object arg) { ... } };
A class declaration can contain static and instance
initializers. A initializer is simply a block, optionally preceded by the keyword static
. If the block is labeled static
, it is a static initializer; otherwise it is an instance initializer.
Initializers are used to initialize static class variables and instance variables. Here's an example from the Java tutorial:
import java.util.*; class Errors { static ResourceBundle errorStrings; static { try { errorStrings = ResourceBundel.getBundle("ErrorStrings"); } catch (MissingResourceException e) { // handle error } } }
The static variable errorStrings
must be initialized in a static initializer because initialization involves invoking the method getBundle
, which might throw a checked MissingResourceException
.
Instance initializers are executed after the superclass constructor, and before the constructor body. For example, if classes A
and B
are declared as follows:
class A { public A () { System.out.print("Two"); } { System.out.print("One"); } } class B extends A { public B () { System.out.println("Four"); } { System.out.print("Three"); } }
instantiating B
results in a line of output containing "OneTwoThreeFour."