void fl(int x) System. out. println ("fl(int)")i void fl(long x)i System. out. println("fl(long)")i void fl(float x I System. out. println("fl(float)")i void fl(double x t System. out. println("fl(double)")i1 void f2(char x)i System. out. println("f2(char)") void f2 (byte x) System. out. println ("f2(byte)")i void f2(short x t System. out. println("f2(short)")i void f2(int x) System. out. println ("f2(int)") void f2(long x)( System. out. println ("f2(long)")i void f2(float x) I System. out. println("f2(float)")i void f3(char x) System. out. println("f3(char)")i void f3(byte x)[ System. out. println("f3(byte)")i H void f3(short x) t System. out. println("f3(short)")i) void f3(int x) System. out. println("f3(int)")i void f3 (long x) System. out. println("f3(long)")i) void f4(char x) System. out. println ("f4(char)")i void f4(byte x)[ System. out. println("f4(byte)") void f4(short x) void f4(int x)i System. out.println("f4(int)")i) void f5(char x) System. out. println("f5(char)")i) void f5(byte x)i System. out. println("f5(byte)")K void f5(short x t System. out. println(f5(short)")i F void f6(char x) stem out. printin ("f6(char) void f6(byte x stem out. println("f6(byte)")i void f7(char x)i System. out. println("f7(char)")i void testDouble()( double x=0 System. out. println("double argument: " f5((short)x)if6((byte)x)if7((char)x)i id main(st Demotion p= new Demotion()i estDouble ( monitor. expect (new String[] i double argument "f2(float)", f3(1ong)", )", 6(byte) 第11页共42页
shhgs@wgqqh.com 11 ✁ ✂ 42 ✁ void f1(int x) { System.out.println("f1(int)"); } void f1(long x) { System.out.println("f1(long)"); } void f1(float x) { System.out.println("f1(float)"); } void f1(double x) { System.out.println("f1(double)"); } void f2(char x) { System.out.println("f2(char)"); } void f2(byte x) { System.out.println("f2(byte)"); } void f2(short x) { System.out.println("f2(short)"); } void f2(int x) { System.out.println("f2(int)"); } void f2(long x) { System.out.println("f2(long)"); } void f2(float x) { System.out.println("f2(float)"); } void f3(char x) { System.out.println("f3(char)"); } void f3(byte x) { System.out.println("f3(byte)"); } void f3(short x) { System.out.println("f3(short)"); } void f3(int x) { System.out.println("f3(int)"); } void f3(long x) { System.out.println("f3(long)"); } void f4(char x) { System.out.println("f4(char)"); } void f4(byte x) { System.out.println("f4(byte)"); } void f4(short x) { System.out.println("f4(short)"); } void f4(int x) { System.out.println("f4(int)"); } void f5(char x) { System.out.println("f5(char)"); } void f5(byte x) { System.out.println("f5(byte)"); } void f5(short x) { System.out.println("f5(short)"); } void f6(char x) { System.out.println("f6(char)"); } void f6(byte x) { System.out.println("f6(byte)"); } void f7(char x) { System.out.println("f7(char)"); } void testDouble() { double x = 0; System.out.println("double argument:"); f1(x);f2((float)x);f3((long)x);f4((int)x); f5((short)x);f6((byte)x);f7((char)x); } public static void main(String[] args) { Demotion p = new Demotion(); p.testDouble(); monitor.expect(new String[] { "double argument:", "f1(double)", "f2(float)", "f3(long)", "f4(int)", "f5(short)", "f6(byte)", "f7(char)" }); } } ///:~
这里,方法需要的是一个更小类型的 primitive的值。如果你传的参数比 它大,那么你就只能把它转换成这个类型的值。把类型的名字放到括号里 就行了。不这么做,编译器就会报错。 你应该知道这是一个 narrowing conversion,也就是说转换过程中会丢 失一些信息。这就是为什么编译器要强制你去这么做的原因了——它要告 诉你这是一个 narrowing conversion 用返回值重载 很自然,我们会问“为什么只有类的名字和方法的参数表呢?为什么不用 返回值的类型来区分方法呢?”比如,要区分这样两个有着相同的名字和 参数的方法是很容易的 void f(( int f((I 在intx〓f)这种情况下,这种做法是行得通的。因为编译器可以根据 上下文明白无误地作出判断。但是调用方法的时候是可以忽略返回值的 由于你并不关心方法调用所返回的值,而只想利用其副作用,因此这通常 被称为“为利用其副作用而调用方法(ca∥ ing a method for its side effect)”。所以如果你这样调用方法: 那么Java该怎样判定应该调用哪个f(〕呢?读代码的人又该怎样来判图 呢?因此,不能用返回值来区分重载的方法。 默认的构造函数 正如我们前面提到过的,默认的构造函数(也就是“无参数”的构造函数) 是一种用于创建“基本对象”的无参数的构造函数。如果你写了一个没有 构造函数的类,那么编译器会自动为你创建一个默认的构造函数。例如: //: c04: DefaultConstructor java class bird public class Defaultconstructor i public static void main(String[] args) t Bird nc new Bird(i// De fault! 第12页共42页
shhgs@wgqqh.com 12 ✁ ✂ 42 ✁ ˵î%(3×( p ri m iti ve (ÄÅ¡ì(I8 AÂYZ¡ó;PA÷ø ×(P(Ñ\kg$ùË ,,X ZTáVºúû ¡vw01 3× narrowing conversion[$÷ø^â*ºü 63ÌÐÑ ZáV%ýþ¡ ZT(åæ,A%# ¡ 3× n arrowi n g con versi on ý9cº!ÍZóm(Ñ\µ(IÎÊ ZX T(QµÎÊ Ï8Ä% ¦e×m.>(Ñ\ I(µRS(y void f() {} int f() {} F int x = f( ) 5k T,(æáVÝEò Jk ñÜr1!ÀÁNµ(MÝET( ()¡XqµNDT(àó|§1æò · BÓͧ1àNµ (calling a method for its side effect )ÏDEÄÅ¡ ¦Nµy f(); YZ Java wÕ¦ÀOvwNr× f( )ÎÊ (ªüwÕ¦QÀÁ ÎÊ æòX;TQ«(µ îÄc¶dg^(ÒÙ(GÚHI([ÍÜIÏ(GÚHI) 3)LMÍ ¥KÏ(ÜI(GÚHIÄÅ¡«,3×m GÚHI(YZáVºý ¡LM3×ÒÙ(GÚHIÄy //: c04:DefaultConstructor.java class Bird { int i; } public class DefaultConstructor { public static void main(String[] args) { Bird nc = new Bird(); // Default!
}///: 注意这行 new 尽管没有明确定义过,但是它调用了那个默认的构造函数,并且创建了 个新的对象。没有它,我们构建对象的时候就没方法可调。但是,只要定 义了构造函数(不管带不带参数),编译器就不会再自动合成默认的构造函 数了 class hat Hat(int i)(I Hat(double d) 现在如果你再说 new Hat()i 编译器就会报错说它没法找到匹配的构造函数。这就像,如果你不放任何 构造函数,编译器会说“你肯定是需要构造函数的,所以我给你弄一个 吧。”但是如果你写了一个构造函数,编译器就说“你已经写了一个构造 函数,那就说明你知道你在做些什么;既然你不定义默认的构造函数,这 就是说明你不需要。” this关键词 如果有两个类型相同的对象,a和b,你可能会想该如何调用这两个对象 的f()方法。 class Banana void f(int i)i/ Banana a new Banana(),b= new Banana() b.f(2); 如果只有一个叫f()的方法,那么它又该怎样判断是对象a还是b在调 用它呢? 第13页共42页
shhgs@wgqqh.com 13 ✁ ✂ 42 ✁ } } ///:~ ¹ , new Bird(); D mñO¿^AN,Y×ÒÙ(GÚHIYLM,3 ×(¥KmAcGM¥K(MµÝNó%O ¿,GÚHI(X {X{I)áVXºÁý wÒÙ(GÚH I,y class Hat { Hat(int i) {} Hat(double d) {} } íFÄÅ¡Á$y new Hat(); áVºúû$Aôgõ(GÚHI }ÄÅ¡Xk GÚHIáVº$Í¡ÞOî%GÚHI(DE¬¡ 3× ÏÄÅ¡«,3×GÚHIáV$Í¡ôõ«,3×GÚ HIY$ñ¡01¡FTÌZ s9¡XO¿ÒÙ(GÚHI $ñ¡Xî%Ï th i s ÄÅme×>(¥Ka b¡Ý;º|wÄN e×¥K ( f( )µ class Banana { void f(int i) { /* ... */ } } Banana a = new Banana(), b = new Banana(); a.f(1); b.f(2); ÄÅóm3× f( )(µYZAüwÕ¦ÀÁ¥K a b FN AÎÊ