Java基础:五、方法重载(2)
- 2020 年 3 月 17 日
- 筆記
方法重载
在Java里,构造器是强制重载方法名的另一个原因。既然构造器的名字已经由类名所决定,就只能有一个构造器名,如果想用多种方式创建一个对象该怎么办呢?这就需要两个构造器:一个默认构造器,另一个带有形式参数,由于都是构造器,所以它们必须有相同的名字,即类名。为了让方法名相同而形式参数不同的构造器同时存在,必须用到方法重载。同时,尽管方法重载是构造器所必需的,但也可应用于其他方法,且用法同样方便。
class Tree{ int height; Tree(){ System.out.println("Planting a seeding"); height = 0; } Tree(int initialHeight){ height = initialHeight; System.out.println("Creating new Tree that is " + height + " feel tall"); } void info(){ System.out.println("Tree is " + height+ " feet tall"); } void info(String s){ System.out.println(s + ": Tree is " + height + " feet tall"); } public static void main(String[] args) { for(int i = 0; i < 3; i++){ Tree t = new Tree(i); t.info(); t.info("overloaded method"); } new Tree(); } } // Output Creating new Tree that is 0 feel tall Tree is 0 feet tall overloaded method: Tree is 0 feet tall Creating new Tree that is 1 feel tall Tree is 1 feet tall overloaded method: Tree is 1 feet tall Creating new Tree that is 2 feel tall Tree is 2 feet tall overloaded method: Tree is 2 feet tall Planting a seeding
区分重载方法
要是几个方法有相同的方法,Java如何才能知道你指的是哪一个呢?其实规则很简单:每个重载的方法都必须有一个独一无二的参数类型列表,对于名字相同的方法,除了参数类型的差异以外,甚至参数顺序的不同也足以区分两个方法(不过,一般情况下别这么做,因为这会使代码难以维护)
// 区分重载方法 class OverLoadingOrder{ static void f(String s,int i){ System.out.println("String: " + s + ", int: " + i); } static void f(int i, String s){ System.out.println("int: " + i + ", String: " + s); } public static void main(String[] args) { f("String first",11); f(99,"Int first"); } }
基本类型的重载
class PrimitiveOverloading{ void f1(char x){ System.out.print("f1(char)"); } void f1(byte x){ System.out.print("f1(byte)"); } void f1(short x){ System.out.print("f1(short)"); } void f1(int x){ System.out.print("f1(int)"); } void f1(long x){ System.out.print("f1(long)"); } void f1(float x){ System.out.print("f1(float)"); } void f1(double x){ System.out.print("f1(double)"); } void f2(byte x){ System.out.print("f2(byte)"); } void f2(short x){ System.out.print("f2(short)"); } void f2(int x){ System.out.print("f2(int)"); } void f2(long x){ System.out.print("f2(long)"); } void f2(float x){ System.out.print("f2(float)"); } void f2(double x){ System.out.print("f2(double)"); } void f3(short x){ System.out.print("f3(short)"); } void f3(int x){ System.out.print("f3(int)"); } void f3(long x){ System.out.print("f3(long)"); } void f3(float x){ System.out.print("f3(float)"); } void f3(double x){ System.out.print("f3(double)"); } void f4(int x){ System.out.print("f4(int)"); } void f4(long x){ System.out.print("f4(long)"); } void f4(float x){ System.out.print("f4(float)"); } void f4(double x){ System.out.print("f4(double)"); } void f5(long x){ System.out.print("f5(long)"); } void f5(float x){ System.out.print("f5(float)"); } void f5(double x){ System.out.print("f5(double)"); } void f6(float x){ System.out.print("f6(float)"); } void f6(double x){ System.out.print("f6(double)"); } void f7(double x){ System.out.print("f7(double)"); } void testConstVal(){ System.out.print("5: "); f1(5);f2(5);f3(5); f4(5);f5(5); f6(5); f7(5); } void testChar(){ char x = 'x'; System.out.print("char:"); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); } void testByte(){ byte x = 0; System.out.print("byte: "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); } void testShort(){ short x = 0; System.out.print("short : "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); } void testInt(){ int x = 0; System.out.print("int : "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); } void testLong(){ long x = 0; System.out.print("long: "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); } void testFloat(){ float x = 0; System.out.print("float: "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); } void testDouble(){ double x = 0; System.out.print("double: "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); } public static void main(String[] args) { PrimitiveOverloading p = new PrimitiveOverloading(); p.testConstVal(); System.out.println(); p.testChar(); System.out.println(); p.testByte(); System.out.println(); p.testShort(); System.out.println(); p.testInt(); System.out.println(); p.testLong(); System.out.println(); p.testFloat(); System.out.println(); 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) 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)
数值5被当作int值处理,所以如果有某个重载方法接收int型参数,它就会被调用。如果传入的数据类型(实际参数类型)小于声明中的形式参数类型,实际数据类型就会被提升。char型不同,如果无法找找恰好接受char参数的方法,就会把char直接提升至int型
如果传入的实际参数大于重载方法声明的形式参数,方法接受较小的基本类型作为参数,如果传入的实际参数较大,就得通过类型转换来执行窄化转换。如果不这样做,编译器就会报错
// 基本类型的重载,窄化处理 class Demotion{ void f1(char x){ System.out.print("f1(char)"); } void f1(byte x){ System.out.print("f1(byte)"); } void f1(short x){ System.out.print("f1(short)"); } void f1(int x){ System.out.print("f1(int)"); } void f1(long x){ System.out.print("f1(long)"); } void f1(float x){ System.out.print("f1(float)"); } void f1(double x){ System.out.print("f1(double)"); } void f2(byte x){ System.out.print("f2(byte)"); } void f2(short x){ System.out.print("f2(short)"); } void f2(int x){ System.out.print("f2(int)"); } void f2(long x){ System.out.print("f2(long)"); } void f2(float x){ System.out.print("f2(float)"); } void f2(double x){ System.out.print("f2(double)"); } void f3(short x){ System.out.print("f3(short)"); } void f3(int x){ System.out.print("f3(int)"); } void f3(long x){ System.out.print("f3(long)"); } void f3(float x){ System.out.print("f3(float)"); } void f3(double x){ System.out.print("f3(double)"); } void f4(int x){ System.out.print("f4(int)"); } void f4(long x){ System.out.print("f4(long)"); } void f4(float x){ System.out.print("f4(float)"); } void f4(double x){ System.out.print("f4(double)"); } void f5(long x){ System.out.print("f5(long)"); } void f5(float x){ System.out.print("f5(float)"); } void f5(double x){ System.out.print("f5(double)"); } void f6(float x){ System.out.print("f6(float)"); } void f6(double x){ System.out.print("f6(double)"); } void f7(double x){ System.out.print("f7(double)"); } void testDouble(){ double x = 0; System.out.print("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(); } } // Output double argument: f1(double)f2(float)f3(long)f4(int)f5(long)f6(float)f7(double)
以返回值区分重载方法
如果两个方法拥有相同的类名和参数列表,如果考虑用方法的返回值来区分呢?比如现有有两个方法void f(){}
和int f(){return1}
只要编译器可以根据语境明确判断出语义,比如在int x = f()
中,那么的确可以据此区分重载方法。不过,有时你并不关心刚发的返回值,你想要的是方法调用的其他效果(这常被称为“为了副作用而调用”),这时你可能会调用方法而忽略其返回值。如果像这样调用方法f();
,此时Java如何才能判断该调用哪一个f()
呢?别人该如何理解这种代码呢?因此,根据方法的返回值来区分重载方法是行不通的