Java为什么要支持方法重载?

举报
JavaEdge 发表于 2021/06/14 23:40:28 2021/06/14
【摘要】 为什么要使用重载?而不是把一个方法名字换成不同的。 任何编程语言中都具备的一项重要特性就是名称。当你创建一个对象时,就会给此对象分配的内存空间一个名称。一个方法就是一种行为的名称。通过名称引用所各种对象,属性和方法。良好的命名可以让系统易于理解和修改。 将人类语言细微的差别映射到编程语言中会产生一个问题。通常,相同的词可以表达多种不同的含义——它们被"重载"了。特别...

为什么要使用重载?而不是把一个方法名字换成不同的。

任何编程语言中都具备的一项重要特性就是名称。当你创建一个对象时,就会给此对象分配的内存空间一个名称。一个方法就是一种行为的名称。通过名称引用所各种对象,属性和方法。良好的命名可以让系统易于理解和修改。

将人类语言细微的差别映射到编程语言中会产生一个问题。通常,相同的词可以表达多种不同的含义——它们被"重载"了。特别是当含义的差别很小时,这会更加有用。

你会说"清洗衬衫"、“清洗车"和"清洗狗”。而如果硬要这么说就会显得很愚蠢:“以洗衬衫的方式洗衬衫”、“以洗车的方式洗车"和"以洗狗的方式洗狗”,因为听众根本不需要区分行为的动作。大多数人类语言都具有"冗余"性,所以即使漏掉几个词,你也能明白含义。你不需要对每个概念都使用不同的词汇——可以从上下文推断出含义。

大多数编程语言(尤其是 C)要求为每个方法(在这些语言中经常称为函数)提供一个独一无二的标识符。所以,你不能有一个 print() 函数既能打印整型,也能打印浮点型——每个函数名都必须不同。

但在 Java (C++) 中,还有一个因素也促使了必须使用方法重载:构造器。因为构造器方法名肯定与类名相同,所以一个类中只会有一个构造器名。
那么你怎么通过不同方式创建一个对象?例如,你想创建一个类,这个类的初始化方式有两种:一种是标准化方式,另一种是从文件中读取信息的方式。你需要两个构造器:无参构造器和有一个 String 类型参数的构造器,该参数传入文件名。两个构造器具有相同的名字——与类名相同。因此,方法重载是必要的,它允许方法具有相同的方法名但接收的参数不同。尽管方法重载对于构造器很重要,但也可以对任何方法很方便地进行重载。

重载构造器和方法:

class Tree { int height; Tree() { System.out.println("Planting a seedling"); height = 0; } Tree(int initialHeight) { height = initialHeight; System.out.println("Creating new Tree that is " + height + " feet 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 class Overloading { public static void main(String[] args) { for (int i = 0; i < 5; i++) { Tree t = new Tree(i); t.info(); t.info("overloaded method"); } new Tree(); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

一个 Tree 对象既可以是一颗树苗,使用无参构造器,也可以是一颗在温室中已长大的树,已经有一定高度,这就需要有参构造器。

你也许想以多种方式调用 info()。比如,如果你想打印额外的消息,就可以使用 info(String) 方法。若你无话可说,就可以使用 info() 方法。用两个命名定义完全相同的概念看起来很奇怪,而使用方法重载,你就可以使用一个命名来定义一个概念。

区分重载方法

如果两个方法命名相同,Java是怎么知道你调用的是哪个呢?
有一条简单的规则:每个被重载的方法必须有独一无二的参数列表。

除了通过参数列表的不同来区分两个相同命名的方法,其他也没什么方式了。你甚至可以根据参数列表中的参数顺序来区分不同的方法,尽管这会造成代码难以维护。

重载与基本类型

基本类型可以自动从小类型转为大类型。当这与重载结合时,这会令人有点困惑:

public 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); System.out.println(); } void testChar() { char x = 'x'; System.out.print("char: "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); System.out.println(); } void testByte() { byte x = 0; System.out.print("byte: "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); System.out.println(); } void testShort() { short x = 0; System.out.print("short: "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); System.out.println(); } void testInt() { int x = 0; System.out.print("int: "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); System.out.println(); } void testLong() { long x = 0; System.out.print("long: "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); System.out.println(); } void testFloat() { float x = 0; System.out.print("float: "); f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x); System.out.println(); } void testDouble() { double x = 0; System.out.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.testShort(); p.testInt(); p.testLong(); p.testFloat(); p.testDouble(); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145

输出:

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)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

若传入的参数类型大于方法期望接收的参数类型,你必须首先做缩窄转换,否则编译器就会报错。

返回值的重载

经常会有人困惑,“为什么只能通过类名和参数列表,不能通过方法的返回值区分方法呢?”。例如以下两个方法,它们有相同的命名和参数,但是很容易区分:

void f(){}
int f() {return 1;}

  
 
  • 1
  • 2

有些情况下,编译器很容易就可以从上下文准确推断出该调用哪个方法,如 int x = f()

但是,你可以调用一个方法且忽略返回值。这叫做调用一个函数的副作用,因为你不在乎返回值,只是想利用方法做些事。所以如果你直接调用 f(),Java 编译器就不知道你想调用哪个方法,阅读者也不明所以。因为这个原因,所以你不能根据返回值类型区分重载的方法。为了支持新特性,Java 8 在一些具体情形下提高了猜测的准确度,但是通常来说并不起作用。

文章来源: blog.csdn.net,作者:JavaEdge.,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/qq_33589510/article/details/72934257

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。