Java in a Nutshell, 5th Edition [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Java in a Nutshell, 5th Edition [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


3.2. Fields and Methods


A
class can be viewed as a collection of data and code to operate on
that data. The data is stored in fields, and the code is organized
into methods. This section covers fields and methods, the two most
important kinds of class
members.
Fields and methods come in two distinct types: class members (also
known as static members) are associated with the
class itself, while instance

members are
associated with individual instances of the class (i.e., with
objects). This gives us four kinds of members:

  • Class
    fields

  • Class
    methods

  • Instance
    fields

  • Instance methods


The simple class
definition for the class Circle, shown in Example 3-1, contains all four types of members.


Example 3-1. A simple class and its members

public class Circle {
// A class field
public static final double PI= 3.14159; // A useful constant
// A class method: just compute a value based on the arguments
public static double radiansToDegrees(double rads) {
return rads * 180 / PI;
}
// An instance field
public double r; // The radius of the circle
// Two instance methods: they operate on the instance fields of an object
public double area() { // Compute the area of the circle
return PI * r * r;
}
public double circumference() { // Compute the circumference of the circle
return 2 * PI * r;
}
}

The following sections explain all four kinds of members. First,
however, we cover field declaration syntax. (Method declaration
syntax is covered in Section 2.6
later in this chapter.)


3.2.1. Field Declaration Syntax


Field
declaration
syntax is much like the syntax for declaring local variables (see
Chapter 2) except that field definitions may
also include modifiers. The simplest field declaration consists of
the field type followed by the field name. The type may be preceded
by zero or more modifier keywords or annotations (see Chapter 4), and the name may be followed by an equals
sign and initializer expression that provides the initial value of
the field. If two or more fields share the same type and modifiers,
the type may be followed by a comma-separated list of field names and
initializers. Here are some valid field declarations:

int x = 1;
private String name;
public static final DAYS_PER_WEEK = 7;
String[] daynames = new String[DAYS_PER_WEEK];
private int a = 17, b = 37, c = 53;

Field
modifiers
are comprised of zero or more of the following keywords:

public

,

protected ,

private


These access modifiers specify whether and where a field can be used
outside of the class that defines it. These important modifiers are
covered in Section 3.6 later in
this chapter. No more than one of these access modifiers may appear
in any field declaration.


static


If present, this modifier specifies that the field is associated with
the defining class itself rather than with each instance of the
class.


final


This modifier specifies that once the field has been initialized, its
value may never be changed. Fields that are both
static and final are
compile-time constants that the compiler can inline.
final fields can also be used to create classes
whose instances are immutable.


transient


This modifier specifies that a field is not part of the persistent
state of an object and that it need not be serialized along with the
rest of the object. Serialization is covered in Chapter 5.


volatile


Roughly speaking, a
volatile field is like a
synchronized method: safe for concurrent use by
two or more threads. More accurately, volatile
says that the value of a field must always be read from and flushed
to main memory, and that it may not be cached by a thread (in a
register or CPU cache).




3.2.2. Class Fields



A

class field is
associated with the class in which it is defined rather than with an
instance of the class. The following line declares a class field:

public static final double PI = 3.14159;

This line declares a field of type double named
PI and assigns it a value of 3.14159. As you can
see, a field declaration looks quite a bit like a local variable
declaration. The difference, of course, is that variables are defined
within methods while fields are members of classes.

The static
modifier says that the field is a class field. Class fields are
sometimes called static fields because of this
static modifier. The final
modifier says that the value of the field does not change. Since the
field PI represents a constant, we declare it
final so that it cannot be changed. It is a
convention in Java (and many other languages) that
constants
are named with capital letters, which is why our field is named
PI, not pi. Defining constants
like this is a common use for class fields, meaning that the
static and final modifiers are
often used together. Not all class fields are constants, however. In
other words, a field can be declared static
without being declared final. Finally, the
public modifier says
that anyone can use the field. This is a visibility modifier, and
we'll discuss it and related modifiers in more
detail later in this chapter.

The key point to understand about a static field is that there is
only a single copy of it. This field is associated with the class
itself, not with instances of the class. If you look at the various
methods of the Circle class,
you'll see that they use this field. From inside the
Circle class, the field can be referred to simply
as PI. Outside the class, however, both class and
field names are required to uniquely specify the field. Methods that
are not part of Circle access this field as
Circle.PI.

A public class
field is essentially a global variable. The names of class fields are
qualified by the unique names of the classes that contain them,
however. Thus, Java does not suffer from the name collisions that can
affect other languages when different modules of code define global
variables with the same name.


3.2.3. Class Methods




As with
class fields,

class methods are declared with
the static
modifier:

public static double radiansToDegrees(double rads) { return rads * 180 / PI; }

This line declares a class method named
radiansToDegrees(). It has a single parameter of
type double and returns a
double value. The body of the method is quite
short; it performs a simple computation and returns the result.

Like class fields, class methods are associated with a class, rather
than with an object. When
invoking a class method from code that exists outside the class, you
must specify both the name of the class and the method. For example:

// How many degrees is 2.0 radians?
double d = Circle.radiansToDegrees(2.0);

If you want to invoke a class method from inside the class in which
it is defined, you don't have to specify the class
name. However, it is often good style to specify the class name
anyway, to make it clear that a class method is being invoked.

Note that the body of our
Circle.radiansToDegrees(
)
method uses the class field
PI. A class method can use any class fields and
class methods of its own class (or of any other class). But it cannot
use any instance fields or instance methods because class methods are
not associated with an instance of the class. In other words,
although the radiansToDegrees() method is defined
in the Circle class, it does not use any
Circle objects. The instance fields and instance
methods of the class are associated with Circle
objects, not with the class itself. Since a class method is not
associated with an instance of its class, it cannot use any instance
methods or fields.

As we discussed earlier, a class field is essentially a global
variable. In a similar way, a class method is a
global method, or global function. Although
radiansToDegrees() does not operate on
Circle objects, it is defined within the
Circle class because it is a utility method that
is sometimes useful when working with circles. In many
nonobject-oriented programming languages, all methods, or functions,
are global. You can write complex Java programs using only class
methods. This is not object-oriented programming, however, and does
not take advantage of the power of the Java language. To do true
object-oriented programming, we need to add instance fields and
instance methods to our repertoire.


3.2.4. Instance Fields




Any field declared without the
static modifier is an

instance
field :

public double r;    // The radius of the circle

Instance fields are associated with instances of the class, rather
than with the class itself. Thus, every Circle
object we create has its own copy of the double
field r. In our example, r
represents the radius of a circle. Thus, each
Circle object can have a radius independent of all
other Circle objects.

Inside a class definition, instance fields are referred to by name
alone. You can see an example of this if you look at the method body
of the circumference() instance method. In code
outside the class, the name of an instance method must be prefixed
with a reference to the object that contains it. For example, if the
variable c holds a reference to a
Circle object, we use the expression
c.r to refer to the radius of that circle:

Circle c = new Circle(); // Create a Circle object; store a reference in c
c.r = 2.0; // Assign a value to its instance field r
Circle d = new Circle(); // Create a different Circle object
d.r = c.r * 2; // Make this one twice as big

Instance fields are key to object-oriented programming. Instance
fields hold the

state of an object; the values of those
fields make one object distinct from another.


3.2.5. Instance Methods



Any method not declared with the
static
keyword is an instance method. An

instance

method operates on an instance of a class (an
object) instead of operating on the class itself. It is with instance
methods that object-oriented programming starts to get interesting.
The Circle class defined in Example 3-1 contains two instance methods, area(
)
and circumference(), that compute and
return the area and circumference of the circle represented by a
given Circle object.

To use an instance method from outside the class in which it is
defined, we must prefix it with a reference to the instance that is
to be operated on. For example:

Circle c = new Circle();   // Create a Circle object; store in variable c
c.r = 2.0; // Set an instance field of the object
double a = c.area(); // Invoke an instance method of the object

If you're new to object-oriented programming, that
last line of code may look a little strange. We do not write:

a = area(c);

Instead, we write:

a = c.area();

This is why it is called object-oriented programming; the object is
the focus here, not the function call. This small syntactic
difference is perhaps the single most important feature of the
object-oriented paradigm.

The point here is that we don't have to pass an
argument to c.area(). The object we are operating
on, c, is implicit in the syntax. Take a look at
Example 3-1 again. You'll notice
the same thing in the signature of the area( )
method: it doesn't have a parameter. Now look at the
body of the area( ) method: it uses the instance
field r. Because the area()
method is part of the same class that defines this instance field,
the method can use the unqualified name r. It is
understood that this refers to the radius of whatever
Circle instance invokes the method.

Another important thing to notice about the bodies of the
area( ) and circumference()
methods is that they both use the class field PI.
We saw earlier that class methods can use only class fields and class
methods, not instance fields or methods. Instance methods are not
restricted in this way: they can use any member of a class, whether
it is declared static or not.


3.2.5.1 How instance methods work

Consider this line of code again:

a = c.area();

What's going on here? How can a method that has no
parameters know what data to operate on? In fact, the area(
)
method does have a parameter. All instance methods are
implemented with an implicit parameter not shown in the method
signature. The implicit argument is named this; it
holds a reference to the object through which the method is invoked.
In our example, that object is a Circle.

The implicit this
parameter is not shown in method signatures because it is usually not
needed; whenever a Java method accesses the instance fields in its
class, it is implicit that it is accessing fields in the object
referred to by the this parameter. The same is
true when an instance method invokes another instance method in the
same class. I said earlier that to invoke an instance method you must
prepend a reference to the object to be operated on. When an instance
method is invoked within another instance method in the same class,
however, you don't need to specify an object. In
this case, it is implicit that the method is being invoked on the
this object.

You can use the this keyword explicitly when you
want to make it clear that a method is accessing its own fields
and/or methods. For example, we can rewrite the
area() method to use this
explicitly to refer to instance fields:

public double area() { return Circle.PI * this.r * this.r; }

This code also uses the class name explicitly to refer to class field
PI. In a method this simple, it is not necessary
to be explicit. In more complicated cases, however, you may find that
it increases the clarity of your code to use an explicit
this where it is not strictly required.

In some cases, the this keyword

is required, however. For example, when a method
parameter or local variable in a method has the same name as one of
the fields of the class, you must use this to
refer to the field since the field name used alone refers to the
method parameter or local variable. For example, we can add the
following method to the Circle class:

public void setRadius(double r) {
this.r = r; // Assign the argument (r) to the field (this.r)
// Note that we cannot just say r = r
}

Finally, note that while instance methods can use the
this keyword, class methods cannot. This is
because class methods are not associated with objects.


3.2.5.2 Instance methods or class methods?



Instance methods are one of
the key features of object-oriented programming. That
doesn't mean, however, that you should shun class
methods. In many cases, it is perfectly reasonable to define class
methods. When working with the Circle class, for
example, you might find that you often want to compute the area of a
circle with a given radius but don't want to bother
creating a Circle object to represent that circle.
In this case, a class method is more convenient:

public static double area(double r) { return PI * r * r; }

It is perfectly legal for a class to define more than one method with
the same name, as long as the methods have different parameters.
Since this version of the area() method is a class
method, it does not have an implicit this
parameter and must have a parameter that specifies the radius of the
circle. This parameter keeps it distinct from the instance method of
the same name.

As another example of the choice between instance methods and class
methods, consider defining a method named bigger(
)
that examines two Circle objects and
returns whichever has the larger radius. We can write
bigger( ) as an instance method as follows:

// Compare the implicit "this" circle to the "that" circle passed
// explicitly as an argument and return the bigger one.
public Circle bigger(Circle that) {
if (this.r > that.r) return this;
else return that;
}

We can also implement bigger( ) as a class method
as follows:

// Compare circle a to circle b and return the one with the larger radius
public static Circle bigger(Circle a, Circle b) {
if (a.r > b.r) return a;
else return b;
}

Given two Circle objects, x and
y, we can use either the instance method or the
class method to determine which is bigger. The invocation syntax
differs significantly for the two methods, however:

Circle biggest = x.bigger(y);          // Instance method: also y.bigger(x)
Circle biggest = Circle.bigger(x, y); // Static method

Both methods work well, and, from an object-oriented design
standpoint, neither of these methods is "more
correct" than the other. The instance method is more
formally object-oriented, but its invocation syntax suffers from a
kind of asymmetry. In a case like this, the choice between an
instance method and a class method is simply a design decision.
Depending on the circumstances, one or the other will likely be the
more natural choice.


3.2.6. Case Study: System.out.println( )


Throughout this book, we've seen a method
named
System.out.println()
used to display output to the terminal
window or console. We've never explained why this
method has such an long, awkward name or what those two periods are
doing in it. Now that you understand class and instance
fields and class and instance methods, it is
easier to understand what is going on: System is a
class. It has a class field named out. The field
System.out refers to an object. The object
System.out has an instance method named
println( ). If you want to explore this in more
detail, you can look up the java.lang.System class
in the reference section. The class synopsis there tells you that the
field out is of type
java.io.PrintStream, and you can look up that
class to find out about the println( )
method.


/ 1191