Java 重载、重写和隐藏的区别
一、重载(Overload)
注意:为了正确的区分重载和重写,请各位务必记清重载(Overload)和重写(Override)的英文。
(1)重载定义:表示两个或多个方法的名字相同,但方法的参数不同。方法参数不同有两层含义:A、参数的个数不同;B、参数的类型不同。
[java] view plain copy
- public void run(String name, int count)
- {
- System.out.println(count + " " + name + " " + "are running.");
- }
- public void run(int count, String name)
- {
- System.out.println(count + " " + name + " " + "are running.");
- }
请思考以上两个方法是否构成了重载?
(2)重载发生的时机:重载是发生在同一个类内部的两个或多个方法之间。
(3)方法的返回类型对重载没有任何影响!即,对于方法名字和参数都相同的两个方法,如果他们的返回类型不同,这种语法格式是错误的,大家可以试一试。那么,也就是说,只要是重载返回类型一定相同。否则为两个不同的方法。如下代码,这是两个不同的方法。
[java] view plain copy
- public void run()
- {
- System.out.println("dog is running");
- }
- public int run(String name, int count)
- {
- System.out.println(count + " " + name + " " + "are running.");
- return 1;
- }
(3)构造方法之间的重载:一个类中有多个构造方法,那么它们一定是重载的。
(4)重载方法之间的调用:对于普通方法的重载,重载的方法之间是可以直接调用的,如下代码一。
但是对于重载的构造方法之间的调用,需要使用this()关键字。A、this()括号中参数表示目标构造方法所接收的参数;B、对this()的调用必须是构造方法的第一条语句。如下代码二。
[java] view plain copy
- public int run(String name, int count)
- {
- System.out.println(count + " " + name + " " + "are running.");
- return 1;
- }
- public void run(int count, String name)
- {
- run(name , count);
- System.out.println(count + " " + name + " " + "are running.");
- }
[java] view plain copy
- public Dog()
- {
- this("金巴");
- System.out.println("你好世界,我是一条狗!");
- }
- public Dog(String name)
- {
- System.out.println("你好世界," + "我是一条" + name + "狗!");
- }
二、重写(Override)
(1)重写定义:子类与父类的方法的返回类型一样,方法名称一样,参数一样,这样我们就说子类与父类的方法构成了重写关系。
补充:在重写中,我们一直没提到权限的问题(public、protected、private),使用private修饰的方法是不能够进行重写的,也不能够被继承,所以private和多态扯不上关系。在同一个包下,构成重写关系,父类和子类的方法,权限可以是public和public、protected和protected、protected和public,但不可能是public和protected,即权限可以扩大但不可缩小。
(2)重写发生的时机:重写发生在父类与子类之间。
(3)构造方法时不能重写的,如果您理解是构造方法的作用,就知道构造方法为什么不能重写。
(4)在重写时,子类重写的方法调用父类被重写的方法时,可以使用super.父类方法的方式调用,其中此语句不必放在第一行。如下代码所示:
[java] view plain copy
[java] view plain copy
- class Animal
- {
- public void run()
- {
- System.out.println("animal is running");
- }
- }
- class Dog extends Animal
- {
- //override
- public void run()
- {
- System.out.println("dog is running");
- super.run();
- }
- }
三、隐藏(Hide)
(1)提到隐藏,就不得不提到一个关键字--static,static是静态的意思,具体用法意义,各位可以去查相关的资料。这里我想说的,static方法在继承中的特殊性!
(1)子类不能重写(Overriding)父类的静态方法,只能隐藏(Hiding)父类的静态方法。
(2)什么叫隐藏父类的静态方法呢?就是说父类的静态方法和子类的静态方法是同时存在的,具体调用的是哪个方法,是要看调用的方法的引用是什么类型的引用,如果是父类型的引用,调用的就是父类的静态方法,如果是子类型的引用,调用的就是子类的静态方法。【这里面有些多态(Polymorphism)的知识,不懂的可以问我哈!】具体区别我们可以看一个例子,这个例子来自官方文档。
[java] view plain copy
- public class Animal
- {
- public static void testClassMethod()
- {
- System.out.println("The class" + " method in Animal.");
- }
- public void testInstanceMethod()
- {
- System.out.println("The instance " + " method in Animal.");
- }
- }
The second class, a subclass of Animal, is called Cat:
[java] view plain copy
- public class Cat extends Animal
- {
- public static void testClassMethod()
- {
- System.out.println("The class method" + " in Cat.");
- }
- public void testInstanceMethod()
- {
- System.out.println("The instance method" + " in Cat.");
- }
- public static void main(String[] args)
- {
- Cat myCat = new Cat();
- Animal myAnimal = myCat;
- Animal.testClassMethod();
- myAnimal.testInstanceMethod();
- }
- }
隐藏:父类和子类拥有相同名字的属性或者方法时,父类的同名的属性或者方法形式上不见了,实际是还是存在的。
隐藏现象发生在子类和父类之间,隐藏是针对父类中成员变量和静态方法而言。
当子类声明与父类中成员变量具有相同的变量名的变量时,则实现了对父类中成员变量的隐藏;
当子类声明了与父类中的静态成员方法具有相同的方法名,参数列表和相同的返回值时,则实现了对父类中静态方法的隐藏。
注意:当发生隐藏的时候,声明类型是什么类,就调用对应类的属性或者方法,而不会发生动态绑定
方法隐藏只有一种形式,就是父类和子类存在相同的静态方法
属性只能被隐藏,不能被覆盖
子类实例变量/静态变量可以隐藏父类的实例/静态变量,总结为变量可以交叉隐藏
隐藏和覆盖的区别:
被隐藏的属性,在子类被强制转换成父类后,访问的是父类中的属性
被覆盖的方法,在子类被强制转换成父类后,调用的还是子类自身的方法
因为覆盖是动态绑定,是受RTTI(run time type identification,运行时类型检查)约束的,隐藏不受RTTI约束,总结为RTTI只针对覆盖,不针对隐藏
特殊情况:
1.final修饰的属性可以被隐藏,但是不能被赋值,即不能用=来赋值,网上说final属性不能被修改,这个说法不准确,因为对于引用类型的变量用final修饰后,它只是不能被指向其他对象,但是可以改它自身的值,可以用ArrayList测试,final属性可以在运行的时候进行初始化,但是不能不出现初始化语句
2.final修饰的方法不能被覆盖,可以被重载
3.final修饰的类不能被继承
4.private 方法隐式添加了final
实例:
SuperClass类:
package com.yilong.test.scjp;
- public class SuperClass {
- public static int i = 1;
- public int j = 2;
- public final int k = 3;
- public static void method1() {
- System.out.println("SuperClass Method1");
- }
- public void method2() {
- System.out.println("SuperClass Method2");
- }
- public final void method3() {
- System.out.println("SuperClass Method3");
- }
- }