黑马程序员技术交流社区

标题: 重写和重载的区别是? [打印本页]

作者: Spring up    时间: 2012-12-17 16:46
标题: 重写和重载的区别是?
重写和重载的区别?
希望能用代码体现一下谢谢!!!
作者: 孙辉辉    时间: 2012-12-17 16:54
Java的重写和重载是两种在Java中经常提到的两组概念,它们在各个方面都有着很大的不同。

重载
每个类型成员都有一个唯一的签名。方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。只要签名不同,就可以在一种类型内定义具有相同名称的多种方法。当定义两种或多种具有相同名称的方法时,就称作重载。即重载时相同名称成员的参数列表是不相同的(参数顺序和类型)。

继承,重写和隐藏成员
派生的类型继承其基本类型的所有成员;也就是说,这些成员是在派生类型之上定义的,并可用于派生类型。继承成员的行为和质量可以通过以下两种方式来修改:

1、派生类型可通过使用相同的签名定义一个新成员,从而隐藏继承的成员。将先前的公共成员变成私有成员,或者为标记为 final 的继承方法定义新行为时,可以采取这种方法。

2、派生类型可以重写继承的虚方法。重写方法提供了对方法的一种新定义,将根据运行时的值的类型,而不是编译时已知的变量类型来调用方法。只有当虚方法没有标记为 final 且新方法至少可以像虚方法一样进行访问的情况下,成员才能重写虚方法。
方法名,参数相同形成重写,重写的方法不能降低原方法的"可见度",也不能改变原方法的返回值类型。

方法名相同,参数不同(个数、类型)形成重载,重载的方法可看成一个全新的方法,与原方法相比它可以有不同的"可见度"和“返回值类型”。如下例:
  1. class A {
  2. protected int method1(int a, int b) { return 0; }
  3. }
  4. public class B extends A{
  5. public int method1(int a, int b) { return 0; } //正确,重写父类方法,可以扩大访问权限
  6. //private int method1(int a, int b) { return 0; } //错误,重写父类方法,不能降低了访问权限
  7. //private long method1(int a, int b) { return 0; } //错误,重写父类方法,不能改变返回值类型
  8. public short method1(int a, long b) { return 0; }//正确,重载自身的方法,可以有不同的访问权限和返回值类型
  9. private int method1(int a, long b) { return 0; }//正确,重载自身的方法,可以有不同的访问权限和返回值类型
  10. }
复制代码
但这里 方法public short method1(int a, long b) { return 0; }和 方法private int method1(int a, long b) { return 0; }不能同时存在,因为在同一类中,不允许存在相同名字和参数类型的方法(重写的方法)。
Java的多态机制
即重写,重写主要用于子类和父类之间,在父类中定义了一个方法,同时在子类中对这个方法进行重写,实现子类行为的特殊化,例如:
  1. class Animal{
  2. void eat(){ System.out.print("animal eat");}
  3.    }
  4.    
  5.    class Tiger extends Animal{
  6. void eat(){System.out.print("Tiget eat");}
  7. }
复制代码
子类中的eat方法即对父类的eat方法实现了重写,重写最常见的例子就是下面的声明:
Animal some=new Tiger();
关于重写,遵循以下的规则:
(1)重写方法必须和被重写方法具有相同的参数列表,返回类型必须和被重写方法的返回类型相同或者是返回类型的子类型。
(2)重写方法的访问控制修饰符不能比被重写方法更严格(比如一个在父类中声明为public的方法重写成一个protected的方法)。
(3)只有实例方法才能被重写,超类中的final方法不能被重写。
(4)重写方法不能抛出新的检查异常,或者是抛出比被重写方法声明的检查异常更广泛的检查异常。
(5)注意一种特殊情况:如果超类的方法版本中声明了检查异常,但重写的子类方法中没有声明,这时如果使用多态的方式进行调用,那么编译器认为你调用的是声明了异常的方法。
(6)尽管多态是在编译时确定对象的类型,但在编译时,还是根据父类的方法声明进行程序检查。因此,如果子类中定义的方法,在父类中没有定义,则会出项编译错误。
  Java的重载机制:
    重载的实质:在一个类中使用签名相同的多个方法。
按照范围,可以将重载分为在一个类中重载,和在子类和父类中重载。现分别解释如下:
    1.在一个类中定义多个具有相同签名的方法,这些方法必须具有不同的参数列表,比如一个类的构造函数。
    2.在父类和子类中,子类由于继承而拥有了父类的某些方法,此时在子类再定义具有相同签名的方法(必须具有不同的参数列表),这个地方很容易和重写相混淆,因此千万注意。
重载的规则主要记住亮点:
    一是方法的参数列表必须改变,包括参数的类型,参数的个数多少,参数顺序。
二是重载对返回类型,访问修饰符,异常声明没有任何限制,可以作任意的修改。实质上,重载只是创建了一个方法而已,特殊的地方在于方法的名字。
注意下面的一种情况:(重写和重载的混合)
  1. class UseAnimal{
  2.      void doStuff(Animal sa){}
  3.      void doStuff(Tiger sa){}
  4.      public static void main(String[] args){
  5. UseAnimal ua=new UseAnimal();
  6. Animal an=new Tiger();
  7. ua.duStuff(an);
  8. }
  9. }
复制代码
此时,调用的方法doStuff的Animal版本,因为调用重载方法是在编译时决定的,an的声明类型是Animal。所以调用Animal版本。
始终注意一点:重载的判断始终是在编译时决定。
作者: Kevin123    时间: 2012-12-17 17:13
重写方法的规则:
1.参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载.
2.返回的类型必须一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载.
3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
4.重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常.例如,
父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常.


而重载的规则:
1.必须具有不同的参数列表;
2.可以有不同的返回类型,只要参数列表不同就可以了;
3.可以有不同的访问修饰符;
4.可以抛出不同的异常;


重写和重载的区别在于:

重写多态性起作用,对调用被重载过的方法可以大大减少代码的输入量,同一个方法名只要往里面传递不同的参数就可以拥有不同的功能或返回值.

用好重写和重载可以设计一个结构清晰而简洁的类,可以说重写和重载在编写代码过程中的作用非同一般.

下面是重载的例子:
  1. package c04.answer;//这是包名
  2. //这是这个程序的第一种编程方法,在main方法中先创建一个Dog类实例,然后在Dog类的构造方法中利用this关键字调用不同的bark方法。不同的重载方法bark是根据其参数类型的不同而区分的。

  3. //注意:除构造器以外,编译器禁止在其他任何地方中调用构造器。
  4. package c04.answer;

  5. public class Dog {
  6.       Dog()
  7.       {
  8.              this.bark();
  9.       }
  10.       void bark()//bark()方法是重载方法
  11.       {
  12.              System.out.println("no barking!");
  13.              this.bark("female", 3.4);
  14.       }
  15.       void bark(String m,double l)//注意:重载的方法的返回值都是一样的,
  16.       {
  17.              System.out.println("a barking dog!");
  18.              this.bark(5, "China");
  19.       }
  20.       void bark(int a,String n)//不能以返回值区分重载方法,而只能以“参数类型”和“类名”来区分
  21.       {
  22.              System.out.println("a howling dog");
  23.       }
  24.       
  25.       public static void main(String[] args)
  26.       {
  27.              Dog dog = new Dog();
  28.              //dog.bark();
  29. //dog.bark("male", "yellow");
  30.              //dog.bark(5, "China");
复制代码
重写的例子:
重写的主要优点是能够定义某个子类特有的特征:
如:

  1. public class Father
  2. {
  3. public void speak()
  4. {
  5. System.out.println("Father");
  6. }
  7. }
  8. public class Son extends Father
  9. {
  10. public void speak()
  11. {
  12. System.out.println("son");
  13. }
  14. }
复制代码

作者: netboy032    时间: 2012-12-17 17:21
重载是在同一个类中发生的,即如果你想用同一个类名来实现不同的功能就要用到方法重载。重载需要方法名相同参数列表不同即可。
重写是在子父类之间发生的,重写需要子父类方法要一模一样。
作者: 何创    时间: 2012-12-17 20:37
// 对overload测试的文件:OverloadTest.java

public class OverloadTest {

// 下面几个方法用来验证可以通过定义不同的参数类型和参数的数目进行方法重载。

public void fun(){

System.out.println("method fun in OverloadTest, no parameter");

}

public void fun(float f) {

System.out.println("method fun in OverloadTest, parameter type: float");

}

public void fun(int i){

System.out.println("method fun in OverloadTest, parameter type: int");

}

public void fun(int i1, int i2) {

System.out.println("method fun in OverloadTest, parameter type: int, int");

}

// 下面的两个方法用来验证可以通过定义不同的参数顺序进行方法重载。

// 需要注意:这里的参数肯定不是相同的类型,否则的顺序的先后就毫无意义。

public void fun1(int i, float f) {

System.out.println("method fun1 in OverloadTest, sequence of parameters is: int, float");

}

public void fun1(float f, int i) {

System.out.println("method fun1 in OverloadTest, sequence of parameters is: float, int");

}

// 下面的两个方法用来验证方法抛出的异常对于重载的影响.

// 无论是异常的类型还是异常的个数都不会对重载造成任何的影响。

public void fun2() throws TestException {

System.out.println("fun2 in OverloadTest, exception: TestException");

}

public void fun2(int i) throws TestException, TestException1 {

System.out.println("fun2 in OverloadTest, exception: TestException, TestException1");

}

public void fun2(float f) throws Exception {

System.out.println("fun2 in OverloadTest, exception: Exception");

}

// 不能通过抛出的异常类型来重载fun方法。

//public void fun(int i) throws Exception {

// System.out.println("method fun in OverloadTest, parameter type: int, exception: Exception");

//}

// ? 不能通过返回值重载fun方法。

//public boolean fun(int i) throws Exception {

// System.out.println("method fun in OverloadTest, parameter type: int, exception: Exception, return: boolean");

// return true;

//}

private void fun3() { }

// 不能通过不同的访问权限进行重载

public void fun3() { }

public static void main(String[] args) {

// 这里只是定义了OverloadTest的实例,所以test不会调用

// OverloadTest1中的方法。

OverloadTest test = new OverloadTest1();

// 这里定义了OverloadTest1的实例,因为OverloadTest1是OverloadTest

// 的子类,所以test1会调用OverloadTest中的方法。

OverloadTest1 test1 = new OverloadTest1();

try {

int i = 1, j = 2, m = 3;

// 这里不会调用OverloadTest1的fun方法

// test.fun(i, m, j);

test1.fun(i, j, m);

test1.fun();

// 这个调用不会执行,因为fun3()在OverloadTest中访问权限是priavte

//test1.fun3();

test1.fun3(i);

} catch(Exception e) { }

}

}

class OverloadTest1 extends OverloadTest{

// 在子类中重载fun

public void fun(int i, int m, int n) {

System.out.println("Overload fun1 in OverloadTest1, parameter type: int, int, int");

}

// 这个不是对父类中方法的重载,只是一个新的方法。

public void fun3(int i) {

System.out.println("fun2 in OverloadTest1");

}

}

// 对override测试的文件:OverrideTest.java

public class OverrideTest {

public void fun() throws TestException {

System.out.println("method fun in OverrideTest");

}

private void fun1() {

System.out.println("method fun1 in OverrideTest");

}

public static void main(String[] args) {

OverrideTest test = new OverrideTest1();

try {

test.fun();

test.fun1();

} catch(Exception e) { }

}

}

class OverrideTest1 extends OverrideTest{

// 以下正常Override

public void fun() throws TestException2 {

System.out.println("fun in OverrideTest1");

}

// 不能Override父类中的方法,因为它定义了不同的异常类型和

// 返回值。

//public int fun() throws TestException1 {

// System.out.println("method fun in Test");

// return 1;

//}

// 不能Override父类中的方法,因为它抛出了比父类中非法范围

// 更大的异常。

//public void fun() throws Exception {

// System.out.println("fun in OverrideTest1");

//}

// 这个方法并没有Override父类中的fun1方法,因为这个方法在

// 父类是private类型,所以这里只是相当于定义了一个新方法。

public void fun1() {

System.out.println("method fun1 in Test");

}

}

class TestException extends Exception{

public TestException(String msg) {

super(msg);

}

}

class TestException1 extends TestException {

public TestException1(String msg) {

super(msg);

}

}

class TestException2 extends TestException {

public TestException2(String msg) {

super(msg);

}
}
另外你还有注意看他们的构造函数区别




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2