Thinking in Java - 4th Edition
1079 pág.

Thinking in Java - 4th Edition

Disciplina:Programação Orientada a Objetos1.255 materiais32.000 seguidores
Pré-visualização50 páginas
(1) Add an overloaded constructor to the previous exercise that takes a
String argument and prints it along with your message.

Exercise 5: (2) Create a class called Dog with an overloaded bark( ) method. This
method should be overloaded based on various primitive data types, and print different types
of barking, howling, etc., depending on which overloaded version is called. Write a main( )
that calls all the different versions.

Exercise 6: (1) Modify the previous exercise so that two of the overloaded methods have
two arguments (of two different types), but in reversed order relative to each other. Verify
that this works.

Exercise 7: (1) Create a class without a constructor, and then create an object of that
class in main( ) to verify that the default constructor is automatically synthesized.

Initialization & Cleanup 115 

116 Thinking in Java Bruce Eckel

The this keyword
If you have two objects of the same type called a and b, you might wonder how it is that you
can call a method peel( ) for both those objects:

//: initialization/BananaPeel.java
class Banana { void peel(int i) { /* ... */ } }
public class BananaPeel {
 public static void main(String[] args) {
 Banana a = new Banana(),
 b = new Banana();
 a.peel(1);
 b.peel(2);
 }
} ///:~

If there’s only one method called peel( ), how can that method know whether it’s being
called for the object a or b?

To allow you to write the code in a convenient object-oriented syntax in which you “send a
message to an object,” the compiler does some undercover work for you. There’s a secret first
argument passed to the method peel( ), and that argument is the reference to the object
that’s being manipulated. So the two method calls become something like:

Banana.peel(a, 1);
Banana.peel(b, 2);

This is internal and you can’t write these expressions and get the compiler to accept them,
but it gives you an idea of what’s happening.

Suppose you’re inside a method and you’d like to get the reference to the current object.
Since that reference is passed secretly by the compiler, there’s no identifier for it. However,
for this purpose there’s a keyword: this. The this keyword—which can be used only inside a
non-static method—produces the reference to the object that the method has been called
for. You can treat the reference just like any other object reference. Keep in mind that if
you’re calling a method of your class from within another method of your class, you don’t
need to use this. You simply call the method. The current this reference is automatically
used for the other method. Thus you can say:

//: initialization/Apricot.java
public class Apricot {
 void pick() { /* ... */ }
 void pit() { pick(); /* ... */ }
} ///:~

Inside pit( ), you could say this.pick( ) but there’s no need to.1

The compiler does it for you

automatically. The this keyword is used only for those special cases in which you need to
explicitly use the reference to the current object. For example, it’s often used in return
statements when you want to return the reference to the current object:

                                                            
1 Some people will obsessively put this in front of every method call and field reference, arguing that it makes it “clearer
and more explicit.” Don’t do it. There’s a reason that we use high-level languages: They do things for us. If you put this in
when it’s not necessary, you will confuse and annoy everyone who reads your code, since all the rest of the code they’ve
read won’t use this everywhere. People expect this to be used only when it is necessary. Following a consistent and
straightforward coding style saves time and money.

//: initialization/Leaf.java
// Simple use of the "this" keyword.
public class Leaf {
 int i = 0;
 Leaf increment() {
 i++;
 return this;
 }
 void print() {
 System.out.println("i = " + i);
 }
 public static void main(String[] args) {
 Leaf x = new Leaf();
 x.increment().increment().increment().print();
 }
} /* Output:
i = 3
*///:~

Because increment( ) returns the reference to the current object via the this keyword,
multiple operations can easily be performed on the same object.

The this keyword is also useful for passing the current object to another method:

//: initialization/PassingThis.java
class Person {
 public void eat(Apple apple) {
 Apple peeled = apple.getPeeled();
 System.out.println("Yummy");
 }
}
class Peeler {
 static Apple peel(Apple apple) {
 // ... remove peel
 return apple; // Peeled
 }
}
class Apple {
 Apple getPeeled() { return Peeler.peel(this); }
}
public class PassingThis {
 public static void main(String[] args) {
 new Person().eat(new Apple());
 }
} /* Output:
Yummy
*///:~

Apple needs to call Peeler.peel( ), which is a foreign utility method that performs an
operation that, for some reason, needs to be external to Apple (perhaps the external method
can be applied across many different classes, and you don’t want to repeat the code). To pass
itself to the foreign method, it must use this.

Exercise 8: (1) Create a class with two methods. Within the first method, call the second
method twice: the first time without using this, and the second time using this—just to see it
working; you should not use this form in practice.

Initialization & Cleanup 117 

Calling constructors from constructors

When you write several constructors for a class, there are times when you’d like to call one
constructor from another to avoid duplicating code. You can make such a call by using the
this keyword.

Normally, when you say this, it is in the sense of “this object” or “the current object,” and by
itself it produces the reference to the current object. In a constructor, the this keyword takes
on a different meaning when you give it an argument list. It makes an explicit call to the
constructor that matches that argument list. Thus you have a straightforward way to call
other constructors:

//: initialization/Flower.java
// Calling constructors with "this"
import static net.mindview.util.Print.*;
public class Flower {
 int petalCount = 0;
 String s = "initial value";
 Flower(int petals) {
 petalCount = petals;
 print("Constructor w/ int arg only, petalCount= "
 + petalCount);
 }
 Flower(String ss) {
 print("Constructor w/ String arg only, s = " + ss);
 s = ss;
 }
 Flower(String s, int petals) {
 this(petals);
//! this(s); // Can’t call two!
 this.s = s; // Another use of "this"
 print("String & int args");
 }
 Flower() {
 this("hi", 47);
 print("default constructor (no args)");
 }
 void printPetalCount() {
//! this(11); // Not inside non-constructor!
 print("petalCount = " + petalCount + " s = "+ s);
 }
 public static void main(String[] args) {
 Flower x = new Flower();
 x.printPetalCount();
 }
} /* Output:
Constructor w/ int arg only, petalCount= 47
String & int args
default constructor (no args)
petalCount = 47 s = hi
*///:~

The constructor Flower(String s, int petals) shows that, while you can call one
constructor using this, you cannot call two. In addition, the constructor call must be the first
thing you do, or you’ll get a compiler error message.

This example also shows another way you’ll see this used. Since the name of the argument s
and the name of the member data s are the same, there’s an ambiguity. You can resolve it

118 Thinking in Java Bruce Eckel

Initialization & Cleanup 119 

using this.s, to say that you’re referring to the member data. You’ll often see this form used
in Java code, and it’s used in numerous places in this book.

In printPetalCount( ) you can see that the compiler won’t let you call a constructor from
inside any method other than a constructor.

Exercise 9: (1) Create a class with two (overloaded) constructors.