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

Thinking in Java - 4th Edition

Disciplina:Programação Orientada A Objetos2.668 materiais45.161 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\u2019s only one method called peel( ), how can that method know whether it\u2019s being
called for the object a or b?

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

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

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

Suppose you\u2019re inside a method and you\u2019d like to get the reference to the current object.
Since that reference is passed secretly by the compiler, there\u2019s no identifier for it. However,
for this purpose there\u2019s a keyword: this. The this keyword\u2014which can be used only inside a
non-static method\u2014produces 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\u2019re calling a method of your class from within another method of your class, you don\u2019t
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\u2019s 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\u2019s 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 \u201cclearer
and more explicit.\u201d Don\u2019t do it. There\u2019s a reason that we use high-level languages: They do things for us. If you put this in
when it\u2019s not necessary, you will confuse and annoy everyone who reads your code, since all the rest of the code they\u2019ve
read won\u2019t 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\u2019t 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\u2014just 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\u2019d 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 \u201cthis object\u201d or \u201cthe current object,\u201d 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\u2019t 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\u2019ll get a compiler error message.

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

118 Thinking in Java Bruce Eckel

Initialization & Cleanup 119 

using this.s, to say that you\u2019re referring to the member data. You\u2019ll often see this form used
in Java code, and it\u2019s used in numerous places in this book.

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

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