一、方法重载
1)在同一个类中,如果想创建多个名称相同的方法,那么就会用到方法重载。方法重载通过参数区分名称相同的方法,参数可以类型不同,数目不同,或者顺序不同
package com.example; public class T{ public void show(){ System.out.println("show()"); } /*error public int show(){ return 100; } */ public void show(int i){ System.out.println("show" + "(" + i + ")"); } public void show(String str){ System.out.println("show" + "(" + str + ")"); } public void show(int i, String str){ System.out.println("show" + "(" + i + ", " + str + ")"); } public void show(String str, int i){ System.out.println("show" + "(" + str + ", " + i + ")"); } }
package com.example; public class Test{ public static void main(String[] args){ T t = new T(); t.show(); t.show(10); t.show("张三"); t.show(10, "张三"); t.show("张三", 10); } }
运行结果: show() show(10) show(张三) show(10, 张三) show(张三, 10)
- 方法名称相同时,不能通过改变返回值的类型来进行区分,只能通过改变参数的类型、参数的数目、或者参数的顺序来对方法进行区分
2)类中可以创建多个构造器也是利用了方法重载
package com.example; public class T{ public T(){ } public T(int i){ } public T(String str){ } }
3)方法重载时,如果参数列表都是基本数据类型,编译器会将传入的参数自动匹配相应的类型。如果没有相匹配的类型,编译器会将参数进行类型提升或者窄化转换
例1:
package com.example; public class T{ public void f1(char i) {System.out.print("f1(char) ");} public void f1(byte i) {System.out.print("f1(byte) ");} public void f1(short i) {System.out.print("f1(short) ");} public void f1(int i) {System.out.print("f1(int) ");} public void f1(long i) {System.out.print("f1(long) ");} public void f1(float i) {System.out.print("f1(float) ");} public void f1(double i) {System.out.print("f1(double) ");} public void f2(byte i) {System.out.print("f2(byte) ");} public void f2(short i) {System.out.print("f2(short) ");} public void f2(int i) {System.out.print("f2(int) ");} public void f2(long i) {System.out.print("f2(long) ");} public void f2(float i) {System.out.print("f2(float) ");} public void f2(double i) {System.out.print("f2(double) ");} public void f3(short i) {System.out.print("f3(short) ");} public void f3(int i) {System.out.print("f3(int) ");} public void f3(long i) {System.out.print("f3(long) ");} public void f3(float i) {System.out.print("f3(float) ");} public void f3(double i) {System.out.print("f3(double) ");} public void f4(int i) {System.out.print("f4(int) ");} public void f4(long i) {System.out.print("f4(long) ");} public void f4(float i) {System.out.print("f4(float) ");} public void f4(double i) {System.out.print("f4(double) ");} public void f5(long i) {System.out.print("f5(long) ");} public void f5(float i) {System.out.print("f5(float) ");} public void f5(double i) {System.out.print("f5(double) ");} public void f6(float i) {System.out.print("f6(float) ");} public void f6(double i) {System.out.print("f6(double) ");} public void f7(double i) {System.out.print("f7(double) ");} public void showChar(){ char i = 0; System.out.println("char: "); f1(i); f2(i); f3(i); f4(i); f5(i); f6(i); f7(i); System.out.println(" "); } public void showByte(){ byte i = 0; System.out.println("byte: "); f1(i); f2(i); f3(i); f4(i); f5(i); f6(i); f7(i); System.out.println(" "); } public void showShort(){ short i = 0; System.out.println("short: "); f1(i); f2(i); f3(i); f4(i); f5(i); f6(i); f7(i); System.out.println(" "); } public void showInt(){ int i = 0; System.out.println("int: "); f1(i); f2(i); f3(i); f4(i); f5(i); f6(i); f7(i); System.out.println(" "); } public void showLong(){ long i = 0; System.out.println("long: "); f1(i); f2(i); f3(i); f4(i); f5(i); f6(i); f7(i); System.out.println(" "); } public void showFloat(){ float i = 0; System.out.println("float: "); f1(i); f2(i); f3(i); f4(i); f5(i); f6(i); f7(i); System.out.println(" "); } public void showDouble(){ double i = 0; System.out.println("double: "); f1(i); f2(i); f3(i); f4(i); f5(i); f6(i); f7(i); System.out.println(" "); } }
package com.example; public class Test{ public static void main(String[] args){ T t = new T(); t.showChar(); t.showByte(); t.showShort(); t.showInt(); t.showLong(); t.showFloat(); t.showDouble(); } }
运行结果: 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)
- char 类型比较特别,当重载的方法中没有 char 类型时,传入的参数会提升为 int 类型,而不是 byte 类型,例如:f2 方法和 f3 方法,这两个方法都没有重载 char 类型的参数,所以传入的参数直接提升为 int 类型,从运行结果的第一行可以看到这一特性
例2:
package com.example; public class T{ public void f1(char i) {System.out.print("f1(char) ");} public void f1(byte i) {System.out.print("f1(byte) ");} public void f1(short i) {System.out.print("f1(short) ");} }
package com.example; public class Test{ public static void main(String[] args){ int i = 0; T t = new T(); //t.f1(i); // error t.f1((char)i); t.f1((byte)i); t.f1((short)i); } }
运行结果: f1(char) f1(byte) f1(short)
- 如果传入的参数需要窄化转型,那么必须要显式地对传入的参数进行强制类型转换
二、方法重写
1)方法重写只存在于子类中(继承或实现接口)
package com.example; public class Person{ // 父类 public void speak(){ System.out.println("Person: speak()"); } }
package com.example; public class Man extends Person{ // 子类 public void speak(){ // 重写父类的 speak 方法 super.speak(); // 调用父类的 speak 方法 System.out.println("Man: speak()"); } }
运行结果: Person: speak() Man: speak()
- 方法重写时,子类方法的方法名称、返回值类型、参数列表都应该与父类中的方法相同
2)子类中重写的方法的访问控制权限不能低于父类中方法的访问控制权限
package com.example; public class Person{ // 父类 public void p1(){ } protected void p2(){ } void p3(){ } private void p4(){ } }
package com.example; public class Man extends Person{ // 子类 public void p1(){ // 父类的 p1 方法的访问控制权限是 public,那么子类的 p1 方法的访问控制权限只能是 public } /* public void p2(){ // 可以是 public 或者 protected } */ protected void p2(){ } /* public void p3(){ } protected void p3(){ } */ void p3(){ } /* public void p4(){ } protected void p4(){ } void p4(){ } */ private void p4(){ } }
3)继承关系中,子类也可以对父类的方法进行方法重载
package com.example; public class Person{ // 父类 public void speak(int i){ System.out.println("Person: speak" + "(" + i + ")"); } }
package com.example; public class Man extends Person{ // 子类 public void speak(String str){ // 方法重载 System.out.println("Man: speak" + "(" + str + ")"); } }
package com.example; public class Test{ public static void main(String[] args){ Man m = new Man(); m.speak("张三"); } }
运行结果: Man: speak(张三)
4)Java 为了保证重写方法时不会出错,所以引入了 @Override
package com.example; public class Person{ // 父类 public void speak(int i){ System.out.println("Person: speak" + "(" + i + ")"); } }
package com.example; public class Man extends Person{ // 子类 /* @Override public void speak(String str){ System.out.println("Man: speak" + "(" + str + ")"); } */ // error,用了 @Override ,那么 @Override 下面的方法必须是方法重写,否则编译时会出错 @Override public void speak(int i){ System.out.println("Man: speak" + "(" + i + ")"); } }
package com.example; public class Test{ public static void main(String[] args){ Man m = new Man(); m.speak(10); } }
运行结果: Man: speak(10)
参考资料:
《Java 编程思想》第4版