子类父类拥有同名的方法时……
(这个程序是不能运行的)
package yanzheng;
public class ParentChildTest {
public static void main(String[] args) {
Parent parent=new Parent();
parent.printValue();
Child child=new Child();
child.printValue();
parent=child;
parent.printValue();
parent.myValue++;
parent.printValue();
((Child)parent).myValue++;
parent.printValue();
}
}
class Parent{
public int myValue=100;
public void printValue() {
System.out.println("Parent.printValue(),myValue="+myValue);
}
}
class Child extends Parent{
public int myValue=200;
public void printValue() {
System.out.println("Child.printValue(),myValue="+myValue);
}
}
总结:子类父类拥有同名的方法时:
*当子类与父类拥有一样的方法,并且让一个父类变量引用一个子类对象时,到底调用哪个方法,由对象自己的“真实”类型所决定,这就是说:对象是子类型的,它就调用子类型的方法,是父类型的,它就调用父类型的方法。
*这个特性实际上就是面向对象“多态”特性的具体表现。
*如果子类与父类有相同的字段,则子类中的字段会代替或隐藏父类的字段,子类方法中访问的是子类中的字段(而不是父类中的字段)。如果子类方法确实想访问父类中被隐藏的同名字段,可以用super关键字来访问它。
*如果子类被当作父类使用,则通过子类访问的字段是父类的!
牢记:
在实际开发中,要避免在子类中定义与父类同名 的字段。不要自找麻烦!
附录:网络上摘取的一些代码和解释,可以帮助理解。
例1:
public class A {
protected String a = "1";
public String getA(){
return this.a;
}
}
public class B extends A {
protected String a = "2";
// public String getA(){
// return a;
// }
public static void main(String[] args) {
B x = new B();
System.out.println(x.getA());
}
}
输出的是1,父类的方法看到的变量是父类中的a。
如果B中也写一个getA方法,看到的a就是子类中的a了。
其实就是可见性的问题。
父类和子类的变量是同时存在的,即使是同名。
子类中看到的是子类的变量,父类中看到的是父类中的变量。
它们互相隐藏,而同名的方法则是实实在在的覆盖。
如A x = new B();
x是一个B,也是一个A,
那么调用方法时,是根据对象的实际类型调用的,
实际类型是B,所以永远调用子类的方法。
而访问成员变量就不同了,它是B时,访问的是子类的成员变量,
转型为A的话,访问的就是父类的成员变量了。
例2:
//Main.java
class c
{
public int name = 12;
}
class d extends c
{
d()
{name =13;}
void d2()
{
System.out.println(super.name);
}
}
public class Main
{
public static void main(String[]args)
{
d d1 = new d();
System.out.println(d1.name);
d1.d2();
}
}
//运行结果为:13,13
//Main1.java
class c
{
public int name = 12;
}
class d extends c
{
int name =13;
void d2()
{
System.out.println(super.name);
}
}
public class Main
{
public static void main(String[]args)
{
d d1 = new d();
System.out.println(d1.name);
d1.d2();
}
}
//运行结果为:13,12
首先要了解super这个关键字的意思,是调用父类的意思,
void d2()
{
System.out.println(super.name);
}这句话就是调用父类的name,虽然子类里面有一个name,但是并不是覆盖了父类里面的name,而只是父类的name隐藏起来了,使得直接调用子类里面的name显示的是子类定义的name。
第一个main。Java,不用说,子类没有定义name变量,并且父类里面的name变量不是private,子类可以直接继承name,这样子类和父类就共用一个name变量
如果父类定义了一个方法。子类重写了这个方法。那么这两个方法其实也是拥有各自的内存。
例3:
class Parent{
int i=10;// 父类变量
public void setI(int i){
this.i=i;
}
}
class Son extends Parent{
int i=10;// 子类与父类同名的变量
public static void main(String args[]){
Son son=new Son();
System.out.println("son.i="+son.i);
son.setI(100);
System.out.println("After setI(100) : son.i="+son.i);
Parent parent=son;
System.out.println("See son as Parent : son.i="+parent.i);
}
}
在这段代码中,子类定义了一个父类中同名的成员变量int i,在父类中有一个对 i 赋值的方法setI(),而在子类中没有定义这个方法。当子类调用继承而来的setI()方法对成员变量i进行改变,直接打印son.i时,成员变量i然而却没有改变。当但当把son当作Parent类型来使用,再打印它的成员变量i时,输出的结果就对了,是setI()改变之后的值。
java中类是分层次的,当子类和父类的定义同名时,父类变量被隐藏,父类的实例方法被重写,静态方法属于类级别的方法,在子类和父类中互不相碍。
例4:
为什么java中子类重写父类的方法时声明抛出异常不能比父类范围大?
在java 中,当我们子类要重写父类中的方法,如果父类的方法有异常声明,那么子类重写这个方法时候,所要声明的异常不应该比父类的大。只能是小等,或者可以没有。原因如下。
假如我们自定意义一个异常:
public class MyException extends Exception {
public MyException(String message) {}
public MyException() {}
}
那么我们有一个父类它将有一个方法,将声明抛出这个异常。我们把它做成抽象的(无所谓)
public abstract class ParentException {
public abstract void test() throws MyException;
}
那么将有一个类使用到上面这个类
public class ExceptionTest {
private ParentException exception;
public ExceptionTest(ParentException exception){
this.exception=exception;
}
public void app(){
try {
exception.test();
} catch (MyException e) {
e.printStackTrace();
}
}
}
对于以上的try~catch 我们就直接捕获MyException异常。这是正确的,它在编译的时候是没有问题的。
假如,有一个ParentException的有一个子类
public class ChildException extends ParentException{
public void test() throws Exception{ }
}
他的方法可以声明抛出比父类大的异常,假如它是正确的。
那么问题来了。当我们执行ExceptionTest类的时候,我们以这个子类做为对象传进去。
exception.test();这个地方将在运行的时候实际调用的是ChildException这个子类的test()方法,而它的声明抛 出却是比父类大的异常,这就使得在ExceptionTest类中,捕获异常处出现了毛病,因为它无法捕获Exception异常。
综上所诉,子类重写父类的方法时候不能声明抛出比父类大的异常。
例5:关于方法的重写Overriding和重载Overloading 。
方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。Overloaded的方法是可以改变返回值的类型。也就是说,重载的返回值类型可以相同也可以不同。
1、重载(Overloading)
a、方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。重载Overloading是一个类中多态性的一种表现。b、Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法,这就是多态性。
c、重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。
2、重写(Overriding)
a、父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。在Java中子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。b、若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
c、子类函数的访问修饰权限不能少于父类的