In it simplest form, a Java class definition has the following structure.
public class A { object and class member definitions }
The object and class member definitionsare method (including constructor), variable, and constant definitions, which are like C function, variable, and constant definitions with the exception of some keyword modifiers as described below.
There is one important difference between Java member definitions and their C counterparts: Java does not require that class members be defined prior to their use. A Java compiler works like an assembler in that it makes multiple passes through a code file. The early passes are just recording symbols and types associated with them.
There is a price to pay for this added freedom: it complicates error handling by the compiler. Error messages from the compiler can be frustrating because as you fix errors, new errors are uncovered. It is not uncommon to get an early report of a small number of errors and a large number of errors after the first errors are fixed.
In Java, members may be associated with either objects or classes.
Members that are associated with objects are usually called
instance members.
In a class definition, all members are instance members except those
that are qualified by the static
keyword.
In a message that accesses an instance member, the receiver is specified
by a variable or expression that references an object.
In a message that accesses a class member, the receiver is specified by
the name of a class.
The most important variables that are defined in a class are
instance variables.
Instance variables are attached to objects so that each object in a
class has its own instance variables.
All variable declarations are declarations of instance variables unless
qualified by the static
keyword.
The static
keyword indicates that the variable is a
class variable.
A class variable is attached to the class in which its definition
appears so that its value or reference is shared by all objects in the
class.
The following declaration declares x
to be a class variable
of type int
.
static int count;
If this declaration appears in class A
then the variable is
accessed with the message A.count
.
This message returns the value of the variable, which may be part of a
more complex expression, such as
System.out.println(A.count);
Here, out
is a variable of the System
class.
Like variables, methods are instance methods except when declared as
class methods using the keyword static
.
If class A
defines method f() as static then messages using
the method must be sent to the class as in
x = A.f();
Unlike C, Java uses the keyword final
to declares
constants.
Many constants are also class variables, so they are often declared like
static final int taxRate;
Java uses the keywords public
, protected
, and
private
to modify access to members in a class definition.
These keywords determine the kinds of scope from which a member can be
accessed.
There is also a default scope for members that are defined without an
access keyword.
A scope is a limited portion of source code that provides a context for interpreting identifiers or names. An identifier can refer to different things depending on the scope in which it appears. This is one of the important mechanisms for encapsulation.
As in C, the scope for a local variable or parameter is the method or
innermost block in which it is declared.
A block scope is either a control statement or a segment of code
delimited by braces.
For example, the scope for the local variable i
in the
following code is the entire for
statement.
The scope of the local variable x
is the region enclosed by
the braces.
for (int i = 0; i < 100; i++) { double x; . . }
There are two scopes in Java that are not available in C: class scopes and package scopes.
To be used in a package scope, a source code file should contain a statement with the following form.
package package-name;
Here, package-nameis the name of the package. Rules for naming class source code files and packages are described in the section "Naming Java Source Code Files and Packages".
Access to a member of a Java class can be limited to a scope using one
of the keywords public
, protected
, or
private
, or to a default scope if none of these keywords is
used.
If an access keyword is used, it should precede the type for the member.
A
is declared
with the public
keyword, it can be accessed through any
reference to an object from class A
.
A
is declared
with the protected
keyword, it can be accessed only
within the package that contains A
or in the class
definition of a subclass of A
.
A
is declared
with the private
keyword, it can be accessed only in the
class definition of A
.
A
is declared
without one of these keywords, it can be accessed only within the
package that contains A
.
Most Java objects are created using the keyword new
with a
call to a constructor method.
A class can provide a default parameterless constructor that is
inherited from the Object class or specialized constructors can be
defined in the class.
Java constructor definitions are similar to method definitions except for two things:
Most constructors are declared public
, so their definition
has the form
public class-name(typed parameter list) { object initialization code }
The typed parameter list has the same syntax as the parameter list in a C function definition.
A constructor is usually called in a
new
expression, which has the form
new class-name(parameter list)
This expression returns a new instance of the class named by class-name. The expression can be used in any context where an object of this class is legal. For example it could be the right-hand side of an assignment statement to a variable of the appropriate type, or it could be used as a parameter in a method call.
There is one context where a constructor is called without a
new
expression: inside a constructor for an object of the
same class.
In this case, the initialization code of the called constructor is
executed without creating a new object.
Two special syntax forms are used to do this:
this(parameter list);
and
super(parameter list);
The first form performs the initialization code in the constructor whose parameter types match the actual parameters (usually a different constructor). The second form performs the initialization code in a constructor defined in the superclass.
Often, there is one primary constructor for a class, with all of the
necessary parameters for constructing an object, and one or more
secondary constructors that omit some of the parameters.
The initialization code for the secondary constructors is just a call to
the primary constructor with default values provided for the omitted
parameters.
For example, in the String
standard library class, there is
a primary constructor with a String
parameter that returns
a copy of the parameter.
There is also a secondary constructor that returns an empty
String
.
The code for the secondary constructor is
public String() { this(""); }
The this
statement just calls the primary constructor,
providing an empty String
as a default value.
When designing the constructors for a class, data integrity is an important consideration. All public constructors should create objects that satisfy data integrity constraints. All classes have a default parameterless constructor that only does initialization specified in the default constructor for the superclass. If that does not create an object that satisfies data integrity constraints then a new default constructor should be defined for the class, overriding the inherited one.
Sometimes there is no reasonable way of defining a parameterless
constructor.
In that case, the default constructor should be declared as either
private
or protected
.
The latter is sometimes useful for allowing subclasses to call the
default constructor in their initialization code.