TIJ读书笔记04-方法重载

 

 

为什么会有方法重载

OOP的编程方式就是让程序的逻辑更加接近现实世界的逻辑. 而在现实世界中,自然语言本身就是很强的冗余容错能力的. 比如,水有个方法叫洗. 那么在自然语言中,洗车,洗衣服…这都是洗这个方法. 映射到程序语言就是water.wash(car);,water.wash(clothes) 而不会说以洗车的方式洗车water.washCar(car)和以洗衣服的方式洗衣服water.washClothes(clothes)

java就提供了方法重载机制,一方面,更加接近自然语言逻辑. 另一方面,由于构造方法的存在. 每个类默认都有一个无参构造器,另外如果还想自定义一些构造器的话,由于构造方法的名称是甲鱼的臀部规定好了的. 那么就意味着每个构造器都要有相同的名字. 那么,这就必须要使用重载了.

方法签名

首先,一个方法的组成,一个方法由权限修饰符,返回值类型,方法名,形参列表,抛出异常类型和方法体组成.方法是依赖于一个类的,那么对于不同类的同名方法,在调用时是不存在歧义的,所以不用考虑.

JVM在调用方法的时候是通过方法签名来调用的. 换句话说同一个类中的方法签名应该是唯一的. 在构成方法的所有元素中,能唯一标识一个方法的组合都可以成为方法签名.
java的做法是将方法名和形参列表的组合作为方法签名. 为什么呢?因为在调用一个方法的时候,这两个是必须显式写出来的. 比如person.fun1("tom",29);

所以balabala说了那么多,方法签名就是函数名+形参列表

如何区分重载

明白了jvm是怎么调用方法的,就可以理解怎么区分重载了. 方法必须有独一无二的函数签名,对于重载方法来说,由于方法名是一样的. 那么能区分签名的就只剩形参列表了. 也就是说,重载方法必须有独一无二的形参列表. 可以是形参的类型不一样,可以是形参的个数不一样,也可以是形参顺序不一样. 但是一般不会采用顺序不一样. 因为这样会难以维护.

关于基本类型的重载

package ch5_init;

public class PrimitiveOverloading {
public void print(String s){
System.out.print(s+" ");
}
public void f1(char x){print("f1(char)");}
public void f1(byte x){print("f1(byte)");}
public void f1(short x){print("f1(short)");}
public void f1(int x){print("f1(int)");}
public void f1(long x){print("f1(long)");}
public void f1(float x){print("f1(float)");}
public void f1(double x){print("f1(double)");}

public void f2(byte x){print("f2(byte)");}
public void f2(short x){print("f2(short)");}
public void f2(int x){print("f2(int)");}
public void f2(long x){print("f2(long)");}
public void f2(float x){print("f2(float)");}
public void f2(double x){print("f2(double)");}

public void f3(short x){print("f3(short)");}
public void f3(int x){print("f3(int)");}
public void f3(long x){print("f3(long)");}
public void f3(float x){print("f3(float)");}
public void f3(double x){print("f3(double)");}

public void f4(int x){print("f4(int)");}
public void f4(long x){print("f4(long)");}
public void f4(float x){print("f4(float)");}
public void f4(double x){print("f4(double)");}

public void f5(long x){print("f5(long)");}
public void f5(float x){print("f5(float)");}
public void f5(double x){print("f5(double)");}

public void f6(float x){print("f6(float)");}
public void f6(double x){print("f6(double)");}

public void f7(double x){print("f7(double)");}

public void testConstVal(){
print("5: ");
f1(5);f2(5);f3(5);f4(5);f5(5);f6(5);f7(5);
System.out.println();
}

public void testChar(){
char x = 'x';
print("char: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
System.out.println();
}

public void testByte(){
byte x = '0';
print("byte: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
System.out.println();
}

public void tesShort(){
short x = '0';
print("short: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
System.out.println();
}

public void testInt(){
int x = '0';
print("int: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
System.out.println();
}
public void testLong(){
long x = '0';
print("long: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
System.out.println();
}
public void testFloat(){
float x = '0';
print("float: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
System.out.println();
}
public void testDouble(){
double x = '0';
print("double: ");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
System.out.println();
}

public static void main(String[] args) {
PrimitiveOverloading p = new PrimitiveOverloading();
p.testConstVal();
p.testChar();
p.testByte();
p.tesShort();
p.testInt();
p.testFloat();
p.testDouble();

}
}

这是书上一个很经典的例子. 运行它可以看出来.

  • 常量5: 被当作int值处理.
  • char类型:如果无法找到接收char类型的方法. char类型会被自动转换成int型处理.
  • 对于其他类型: 如果传入的实际类型小于方法声明的参数类型,那么会发生向上转型.
  • 但是如果传入的实际类型大于方法声明的参数类型,需要显示的向下转型.

万事都要讲理. 类型转换,如果实际类型较小,那么向上转型是没有任何风险的. 精度不会受到影响,最多多占点空间,但是这对现代计算机而言不是什么大事儿. 但是如果实际类型较大,需要向下转型的时候,会发生精度丢失. jvm说,这锅我不背.

通过返回值来区分重载方法可不可以?
不可以,不用多说.因为返回值不是函数签名的一部分.是没有办法区分方法调用的.

原文地址:https://www.cnblogs.com/thecatcher/p/5843970.html