子類父類擁有同名的方法時……
(這個程序是不能運行的)
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、子類函數的訪問修飾權限不能少於父類的