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

Thinking in Java - 4th Edition


DisciplinaProgramação Orientada A Objetos4.267 materiais60.853 seguidores
Pré-visualização50 páginas
"); } 
 void f2(int x) { printnb("f2(int) "); } 
 void f2(long x) { printnb("f2(long) "); } 
 void f2(float x) { printnb("f2(float) "); } 
 void f2(double x) { printnb("f2(double) "); } 
 
 void f3(short x) { printnb("f3(short) "); } 
 void f3(int x) { printnb("f3(int) "); } 
 void f3(long x) { printnb("f3(long) "); } 
 void f3(float x) { printnb("f3(float) "); } 
 void f3(double x) { printnb("f3(double) "); } 
 
 void f4(int x) { printnb("f4(int) "); } 
 void f4(long x) { printnb("f4(long) "); } 
 void f4(float x) { printnb("f4(float) "); } 
 void f4(double x) { printnb("f4(double) "); } 
 
 void f5(long x) { printnb("f5(long) "); } 
Initialization & Cleanup 111 
 void f5(float x) { printnb("f5(float) "); } 
 void f5(double x) { printnb("f5(double) "); } 
 
 void f6(float x) { printnb("f6(float) "); } 
 void f6(double x) { printnb("f6(double) "); } 
 
 void f7(double x) { printnb("f7(double) "); } 
 
 void testConstVal() { 
 printnb("5: "); 
 f1(5);f2(5);f3(5);f4(5);f5(5);f6(5);f7(5); print(); 
 } 
 void testChar() { 
 char x = \u2018x\u2019; 
 printnb("char: "); 
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); print(); 
 } 
 void testByte() { 
 byte x = 0; 
 printnb("byte: "); 
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); print(); 
 } 
 void testShort() { 
 short x = 0; 
 printnb("short: "); 
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); print(); 
 } 
 void testInt() { 
 int x = 0; 
 printnb("int: "); 
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); print(); 
 } 
 void testLong() { 
 long x = 0; 
 printnb("long: "); 
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); print(); 
 } 
 void testFloat() { 
 float x = 0; 
 printnb("float: "); 
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); print(); 
 } 
 void testDouble() { 
 double x = 0; 
 printnb("double: "); 
 f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); print(); 
 } 
 public static void main(String[] args) { 
 PrimitiveOverloading p = 
 new PrimitiveOverloading(); 
 p.testConstVal(); 
 p.testChar(); 
 p.testByte(); 
 p.testShort(); 
 p.testInt(); 
 p.testLong(); 
 p.testFloat(); 
 p.testDouble(); 
 } 
} /* Output: 
5: f1(int) f2(int) f3(int) f4(int) f5(long) f6(float) f7(double) 
char: f1(char) f2(int) f3(int) f4(int) f5(long) f6(float) f7(double) 
byte: f1(byte) f2(byte) f3(short) f4(int) f5(long) f6(float) f7(double) 
112 Thinking in Java Bruce Eckel 
short: f1(short) f2(short) f3(short) f4(int) f5(long) f6(float) 
f7(double) 
int: f1(int) f2(int) f3(int) f4(int) f5(long) f6(float) f7(double) 
long: f1(long) f2(long) f3(long) f4(long) f5(long) f6(float) f7(double) 
float: f1(float) f2(float) f3(float) f4(float) f5(float) f6(float) 
f7(double) 
double: f1(double) f2(double) f3(double) f4(double) f5(double) 
f6(double) f7(double) 
*///:~ 
You can see that the constant value 5 is treated as an int, so if an overloaded method is 
available that takes an int, it is used. In all other cases, if you have a data type that is smaller 
than the argument in the method, that data type is promoted. char produces a slightly 
different effect, since if it doesn\u2019t find an exact char match, it is promoted to int. 
What happens if your argument is bigger than the argument expected by the overloaded 
method? A modification of the preceding program gives the answer: 
//: initialization/Demotion.java 
// Demotion of primitives and overloading. 
import static net.mindview.util.Print.*; 
 
public class Demotion { 
 void f1(char x) { print("f1(char)"); } 
 void f1(byte x) { print("f1(byte)"); } 
 void f1(short x) { print("f1(short)"); } 
 void f1(int x) { print("f1(int)"); } 
 void f1(long x) { print("f1(long)"); } 
 void f1(float x) { print("f1(float)"); } 
 void f1(double x) { print("f1(double)"); } 
 
 void f2(char x) { print("f2(char)"); } 
 void f2(byte x) { print("f2(byte)"); } 
 void f2(short x) { print("f2(short)"); } 
 void f2(int x) { print("f2(int)"); } 
 void f2(long x) { print("f2(long)"); } 
 void f2(float x) { print("f2(float)"); } 
 
 void f3(char x) { print("f3(char)"); } 
 void f3(byte x) { print("f3(byte)"); } 
 void f3(short x) { print("f3(short)"); } 
 void f3(int x) { print("f3(int)"); } 
 void f3(long x) { print("f3(long)"); } 
 
 void f4(char x) { print("f4(char)"); } 
 void f4(byte x) { print("f4(byte)"); } 
 void f4(short x) { print("f4(short)"); } 
 void f4(int x) { print("f4(int)"); } 
 
 void f5(char x) { print("f5(char)"); } 
 void f5(byte x) { print("f5(byte)"); } 
 void f5(short x) { print("f5(short)"); } 
 
 void f6(char x) { print("f6(char)"); } 
 void f6(byte x) { print("f6(byte)"); } 
 
 void f7(char x) { print("f7(char)"); } 
 
 void testDouble() { 
 double x = 0; 
 print("double argument:"); 
 f1(x);f2((float)x);f3((long)x);f4((int)x); 
Initialization & Cleanup 113 
 f5((short)x);f6((byte)x);f7((char)x); 
 } 
 public static void main(String[] args) { 
 Demotion p = new Demotion(); 
 p.testDouble(); 
 } 
} /* Output: 
double argument: 
f1(double) 
f2(float) 
f3(long) 
f4(int) 
f5(short) 
f6(byte) 
f7(char) 
*///:~ 
Here, the methods take narrower primitive values. If your argument is wider, then you must 
perform a narrowing conversion with a cast. If you don\u2019t do this, the compiler will issue an 
error message. 
Overloading on return values 
It is common to wonder, \u201cWhy only class names and method argument lists? Why not 
distinguish between methods based on their return values?\u201d For example, these two 
methods, which have the same name and arguments, are easily distinguished from each 
other: 
void f() {} 
int f() { return 1; } 
This might work fine as long as the compiler could unequivocally determine the meaning 
from the context, as in int x = f( ). However, you can also call a method and ignore the 
return value. This is often referred to as calling a method for its side effect, since you don\u2019t 
care about the return value, but instead want the other effects of the method call. So if you 
call the method this way: 
f(); 
how can Java determine which f( ) should be called? And how could someone reading the 
code see it? Because of this sort of problem, you cannot use return value types to distinguish 
overloaded methods. 
Default constructors 
As mentioned previously, a default constructor (a.k.a. a \u201cno-arg\u201d constructor) is one without 
arguments that is used to create a \u201cdefault object.\u201d If you create a class that has no 
constructors, the compiler will automatically create a default constructor for you. For 
example: 
//: initialization/DefaultConstructor.java 
 
class Bird {} 
 
public class DefaultConstructor { 
 public static void main(String[] args) { 
 Bird b = new Bird(); // Default! 
114 Thinking in Java Bruce Eckel 
 } 
} ///:~ 
The expression 
new Bird() 
creates a new object and calls the default constructor, even though one was not explicitly 
defined. Without it, you would have no method to call to build the object. However, if you 
define any constructors (with or without arguments), the compiler will not synthesize one for 
you: 
//: initialization/NoSynthesis.java 
 
class Bird2 { 
 Bird2(int i) {} 
 Bird2(double d) {} 
} 
 
public class NoSynthesis { 
 public static void main(String[] args) { 
 //! Bird2 b = new Bird2(); // No default 
 Bird2 b2 = new Bird2(1); 
 Bird2 b3 = new Bird2(1.0); 
 } 
} ///:~ 
If you say: 
new Bird2() 
the compiler will complain that it cannot find a constructor that matches. When you don\u2019t 
put in any constructors, it\u2019s as if the compiler says, \u201cYou are bound to need some constructor, 
so let me make one for you.\u201d But if you write a constructor, the compiler says, \u201cYou\u2019ve written 
a constructor so you know what you\u2019re doing; if you didn\u2019t put in a default it\u2019s because you 
meant to leave it out.\u201d 
Exercise 3: (1) Create a class with a default constructor (one that takes no arguments) 
that prints a message. Create an object of this class. 
Exercise 4: