java基础---方法的重载(overload)和覆盖(重写)(override)


重载overload):对于类的方法(包括从父类中继承的方法),方法名相同,参数列表不同,就称之为函数的重载。 重载是一个类中多态性的一种表现。 Java 的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。 调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性。


(1) 参数列表:参数列表又叫参数签名,指三样东西:参数的类型参数的个数参数的顺序(一般不用)。这三者只要有一个不同就叫做参数列表不同。返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。

(2)重载关系发生在:同一个类中、子类中的某个方法和父类中继承下来的方法也可以发生重载的关系、构造器也可以重载。

(3)重载实现父类方法时,参数可以被放大

(4)重载实现父类方法时,返回值可以被缩小


问:区分重载方法时,为什么只有类名和方法形参列表作为标准?为什么不根据返回值对方法加以区分?

比如对下面这两个方法来说,虽然它们有同样的名字和形式参数,但其实是很容易区分它们的:

void f() {}

int f() {}

若编译器可根据上下文(语境)明确判断出含义,比如在int x=f()中,那么这样做完全没有问题。然而,我们也可能调用一个方法,同时忽略返回值;我们通常把这称为“为它的副作用去调用一个方法”,因为我们关心的不是返回值,而是方法调用的其他效果。所以假如我们象下面这样调用方法:f();

Java 怎样判断f()的具体调用方式呢?而且别人如何识别并理解代码呢?由于存在这一类的问题,所以不能根据返回值类型来区分重载的方法



基本类型的重载:

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

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

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

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

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

		void f6(float x) { prt("f6(float)"); }
		void f6(double x) { prt("f6(double)"); }

		void f7(double x) { prt("f7(double)"); }

		void testConstVal() {
		prt("Testing with 5");
		f1(5);f2(5);f3(5);f4(5);f5(5);f6(5);f7(5);
		}

		void testChar() {
		char x = 'x';
		prt("char argument:");
		f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
		}

		void testByte() {
		byte x = 0;
		prt("byte argument:");
		f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
		}

		void testShort() {
		short x = 0;
		prt("short argument:");
		f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
		}

		void testInt() {
		int x = 0;
		prt("int argument:");
		f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
		}

		void testLong() {
		long x = 0;
		prt("long argument:");
		f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
		}

		void testFloat() {
		float x = 0;
		prt("float argument:");
		f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
		}

		void testDouble() {
		double x = 0;
		prt("double argument:");
		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();
		p.testChar();
		p.testByte();
		p.testShort();
		p.testInt();
		p.testLong();
		p.testFloat();
		p.testDouble();
		}
}
Testing with 
5:              f1(int)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)
char argument:  f1(char)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)
byte argument:  f1(byte)f2(byte)f3(short)f4(int)f5(long)f6(float)f7(double)
short argument :f1(short)f2(short)f3(short)f4(int)f5(long)f6(float)f7(double)
int argument:   f1(int)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)
long argument:  f1(long)f2(long)f3(long)f4(long)f5(long)f6(float)f7(double)
float argument:  f1(float)f2(float)f3(float)f4(float)f5(float)f6(float)f7(double)
double argument:f1(double)f2(double)f3(double)f4(double)f5(double)f6(double)f7(double)</span>

 
常数值5 被当作一个int 值处。 

在其他所有情况下,若我们的传入的数据类型(实际参数类型)小于方法中声明的形式参数类型,实际数据类型就会提升

char 获得的效果稍有些不同,这是由于假设它没有发现一个准确的char 匹配,char直接提升为int型。

传入的实际数据类型(实际参数类型)大于重载中方法声明的形式参数

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

		void f3(char x) { prt("f3(char)"); }
		void f3(byte x) { prt("f3(byte)"); }
		void f3(short x) { prt("f3(short)"); }
		void f3(int x) { prt("f3(int)"); }
		void f3(long x) { prt("f3(long)"); }
		
		void f4(char x) { prt("f4(char)"); }
		void f4(byte x) { prt("f4(byte)"); }
		void f4(short x) { prt("f4(short)"); }
		void f4(int x) { prt("f4(int)"); }
		
		void f5(char x) { prt("f5(char)"); }
		void f5(byte x) { prt("f5(byte)"); }
		void f5(short x) { prt("f5(short)"); }
		
		void f6(char x) { prt("f6(char)"); }
		void f6(byte x) { prt("f6(byte)"); }
		
		void f7(char x) { prt("f7(char)"); }
		
		void testDouble() {
		double x = 0;
		prt("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) {
		PrimitiveOverloading p = new PrimitiveOverloading();
		p.testDouble();
		}
} 

double argument:
f1(double)
f2(float)
f3(long)
f4(int)
f5(short)
f6(byte)
f7(char)

方法采用了较小基本类型作为参数,若我们的传入实际参数较大,就必须用括号中的类型名将其转为适当的类型(窄化转换)。如果不这样做,编译器会报告出错。



覆盖 (override):也叫重写,就是在当父类中的某些方法不能满足要求时,子类中改写父类的方法。当父类中的方法被覆盖了后,除非用super关键字,否则就无法再调用父类中的方法了。

发生覆盖的条件

1、“三同一不低” 子类和父类的方法名称参数列表返回类型必须完全相同,而且子类方法的访问修饰符的权限不能比父类

2、子类方法不能抛出比父类方法更多的异常。即子类方法所抛出的异常必须和父类方法所抛出的异常一致,或者是其子类,或者什么也不抛出;

3、被覆盖的方法不能是final类型的。因为final修饰的方法是无法覆盖的。

4、被覆盖的方法不能为private。否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。

5、被覆盖的方法不能为static。所以如果父类中的方法为静态的,而子类中的方法不是静态的,但是两个方法除了这一点外其他都满足覆盖条件,那么会发生编译错误。反之亦然。即使父类和子类中的方法都是静态的,并且满足覆盖条件,但是仍然不会发生覆盖,因为静态方法是在编译的时候把静态方法和类的引用类型进行匹配。



重载vs覆盖

相同点:

都要求方法同名

都可以用于抽象方法和非抽象方法之间

 

不同点:

方法覆盖要求参数列表(参数签名)必须一致,而方法重载要求参数列表必须不一致。

方法覆盖要求返回类型必须一致,方法重载对此没有要求。

方法覆盖只能用于子类覆盖父类的方法,方法重载用于同一个类中的所有方法(包括从父类中继承而来的方法)

方法覆盖对方法的访问权限和抛出的异常有特殊的要求,而方法重载在这方面没有任何限制。

父类的一个方法只能被子类覆盖一次,而一个方法可以在所有的类中可以被重载多次。

另外,对于属性(成员变量)而言,是不能重载的,只能覆盖。






  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值