📄 java2.txt
字号:
allows you to set up different protections for each. The method
to read the value, for example, could be public, whereas the
method to change the value can be private or protected,
effectively creating a variable that's read-only except in a few
cases (which is different from constant, which is read-only in
all cases).
Using methods to access an instance variable is one of the most
frequently used idioms in object-oriented programs. Applying it
liberally throughout all your classes repays you numerous times
with more robust and reusable programs.
Creating Accessor Methods
Creating accessor methods for your instance variables simply
involves creating two extra methods for each variable. There's
nothing special about accessor methods; they're just like any
other method. So, for example, here's a modified Circle class
that has three private instance variables: x, y, and radius. The
public getRadius() method is used to retrieve the value of the
radius variable, and the setRadius() method is used to set it
(and update other parts of the class that need to be updated at
the same time):
class Circle {
private int x, y radius;
public int getRadius() {
return radius;
}
public int setRadius(int value) {
radius = value;
draw();
doOtherStuff();
return radius;
}
....
}
In this modified example of the Circle class the accessor
methods for the instance variable radius have the words set and
get appended with the name of the variable. This is a naming
convention popular among many programmers for accessor methods,
so you always know which methods do what and to which variable.
To access or change the value of the instance variable,
therefore, you'd just call the methods setRadius() and
getRadius(), respectively:
theCircle.getRadius(); //get the value
theCircle.setRadius(4); //set the value (and redraw, etc)
Another convention for naming accessor methods is to use the
same name for the methods as for the variable itself. In Java it
is legal for instance variables and methods to have the same
name; Java knows from how they are used to perform the right
operation. While this does make accessor methods shorter to type
(no extra "set" or "get" to type at the beginning of each
variable), there are two problems with using this convention:
* The fact that methods and variables can have the same names
is a vague point in the Java specification. If someday this
becomes more clarified and they cannot have the same names,
you will have to change your code to fix the problem.
* I find that using the same name for instance variables and
methods makes my code more difficult to read and understand
than using a more explicit name.
Which convention you use is a question of personal taste. The
most important thing is to choose a convention and stick with it
throughout all your classes so that your interfaces are
consistent and understandable.
Using Accessor Methods
The idea behind declaring instance variables private and
creating accessor methods is so that external users of your
class will be forced to use the methods you choose to modify
your class's data. But the benefit of accessor methods isn't
just for use by objects external to yours; they're also there
for you. Just because you have access to the actual instance
variable inside your own class doesn't mean you can avoid using
accessor methods.
Consider that one of the good reasons to make instance variables
private is to hide implementation details from outside your
object. Protecting a variable with accessor methods means that
other objects don't need to know about anything other than the
accessor methods-you can happily change the internal
implementation of your class without wreaking havoc on everyone
who's used your class. The same is true of your code inside that
class; by keeping variables separate from accessors, if you must
change something about a given instance variable all you have to
change are the accessor methods and not every single reference
to the variable itself. In terms of code maintenance and reuse,
what's good for the goose (external users of your class) is
generally also good for the gander (you, as a user of your own
class).
Class Variables and Methods
You learned about class variables and methods early last week,
so I won't repeat a long description of them here. Because they
use modifiers, however, they deserve a cursory mention.
To create a class variable or method, simply include the word
static in front of the method name. The static modifier
typically comes after any protection modifiers, like this:
public class Circle {
public static float pi = 3.14159265F;
public float area(float r) {
return pi * r * r;
}
}
Note
The word static comes from C and C++. While static has a
specific meaning for where a method or variable is stored in
a program's runtime memory in those languages, static simply
means that it's stored in the class in Java. Whenever you
see the word static, remember to mentally substitute the
word class.
Both class variables and methods can be accessed using standard
dot notation with either the class name or an object on the left
side of the dot. However, the convention is to always use the
name of the class, to clarify that a class variable is being
used, and to help the reader to know instantly that the variable
is global to all instances. Here are a few examples:
float circumference = 2 * Circle.pi * getRadius();
float randomNumer = Math.random();
Tip
Class variables, for the same reasons as instance variables,
can also benefit from being declared private and having
accessor methods get or set their values.
Listing 15.1 shows a class called CountInstances that uses class
and instance variables to keep track of how many instances of
that class have been created.
Listing 15.1. The CountInstances class, which uses
class and instance variables.
1: public class CountInstances {
2: private static int numInstances = 0;
3:
4: protected static int getNumInstances() {
5: return numInstances;
6: }
7:
8: private static void addInstance() {
9: numInstances++;
10: }
11:
12: CountInstances() {
13: CountInstances.addInstance();
14: }
15:
16: public static void main(String args[]) {
17: System.out.println("Starting with " +
18: CountInstances.getNumInstances() + " instances");
19: for (int i = 0; i < 10; ++i)
20: new CountInstances();
21: System.out.println("Created " +
22: CountInstances.getNumInstances() + " instances");
23: }
24:}
Started with 0 instances
Creates 10 instances
This example has a number of features, so let's go through it
line by line. In line 2 we declare a private class variable to
hold the number of instances (called numInstances). This is a
class variable (declared static) because the number of instances
is relevant to the class as a whole, not to any one instance.
And it's private so that it follows the same rules as instance
variables accessor methods.
Note the initialization of numInstances to 0 in that same line.
Just as an instance variable is initialized when its instance is
created, a class variable is initialized when its class is
created. This class initialization happens essentially before
anything else can happen to that class, or its instances, so the
class in the example will work as planned.
In lines 4 through 6, we created a get method for that private
instance variable to get its value (getNumInstances()). This
method is also declared as a class method, as it applies
directly to the class variable. The getNumInstances() method is
declared protected, as opposed to public, because only this
class and perhaps subclasses will be interested in that value;
other random classes are therefore restricted from seeing it.
Note that there's no accessor method to set the value. The
reason is that the value of the variable should be incremented
only when a new instance is created; it should not be set to any
random value. Instead of creating an accessor method, therefore,
we'll create a special private method called addInstance() in
lines 8 through 10 that increments the value of numInstances by
1.
Lines 12 through 14 have the constructor method for this class.
Remember, constructors are called when a new object is created,
which makes this the most logical place to call addInstance()
and to increment the variable.
And finally, the main() method indicates that we can run this as
a Java application and test all the other methods. In the main()
method we create 10 instances of the CountInstances class,
reporting after we're done the value of the numInstances class
variable (which, predictably, prints 10).
Finalizing Classes, Methods, and Variables
Although it's not the final modifier I'll discuss today, the
final modifier is used to finalize classes, methods, and
variables. Finalizing a thing effectively "freezes" the
implementation or value of that thing. More specifically, here's
how final works with classes, variables, and methods:
* When the final modifier is applied to a class, it means that
the class cannot be subclassed.
* When applied to a variable, final means that the variable is
constant.
* When applied to a method, final means that the method cannot
be overridden by subclasses.
Finalization (using the final modifier) freezes the
implementation of a class, method, or variable.
Finalizing Classes
To finalize a class, add the final modifier to its definition.
final typically goes after any protection modifiers such as
private or public:
public final class AFinalClass {
. . .
}
You declare a class final for only two reasons:
* To prevent others from subclassing your class. If your class
has all the capabilities it needs, and no one else should be
able to extend its capabilities, then that class should be
final.
* For better efficiency. With final classes you can rely on
instances of only that one class (and no subclasses) being
around in the system, and optimize for those instances.
The Java class library uses final classes extensively. Classes
that have been finalized to prevent their being subclassed
include java.lang.System, java.net.InetAddress, and
java.net.Socket (although, as you learned on Day 14, "Windows,
Networking, and Other Tidbits," the latter will no longer be
final as of Java 1.1). A good example of a class being declared
final for efficiency reasons is java.lang.String. Strings are so
common in Java, and so central to it that Java handles them
specially.
In most cases, it will be a rare event for you to create a final
class yourself since extendible classes are so much more useful
than finalized classes, and the efficiency gains are minimal.
You will, however, most likely have plenty of opportunity to be
upset at certain system classes being final (making it more
difficult to extend them).
Finalizing Variables
A finalized variable means its value cannot be changed. This is
effectively a constant, which you learned about early in Week 1.
To declare constants in Java, use final variables with initial
values:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -