在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()
呢?别人该如何理解这种代码呢?因此,根据方法的返回值来区分重载方法是行不通的