2012-12-31 3 views
5

Я искал в Интернете по аналогичному вопросу, но не смог найти его. Итак, разместите здесь.Java Inheritance - это ключевое слово

В следующей программе, почему значение 'i' напечатано как 100?

AFAIK 'this' относится к текущему объекту; который в этом случае является «TestChild», и имя класса также правильно напечатано. Но почему значение переменной экземпляра не 200?

public class TestParentChild { 
    public static void main(String[] args) { 
     new TestChild().printName(); 
    } 
} 

class TestChild extends TestParent{ 
    public int i = 200; 
} 

class TestParent{ 
    public int i = 100; 
    public void printName(){ 
     System.err.println(this.getClass().getName()); 
     System.err.println(this.i); //Shouldn't this print 200 
    } 
} 

И, кроме того, выход следующего, как я ожидал. Метод дочернего класса вызывается, когда я вызываю «this.test()» из класса родителя.

public class TestParentChild { 
    public static void main(String[] args) { 
     new TestChild().printName(); 
    } 
} 

class TestChild extends TestParent{ 
    public int i = 200; 
    public void test(){ 
     System.err.println("Child Class : "+i); 
    } 

} 

class TestParent{ 
    public int i = 100; 
    public void printName(){ 
     System.err.println(this.getClass().getName()); 
     System.err.println(this.i); //Shouldn't this print 200 
     this.test(); 
    } 
    public void test(){ 
     System.err.println("Parent Class : "+i); 
    } 
} 

ответ

7

Java не имеет виртуальные полей, поэтому i поля в printName всегда относится к TestParent.i и не любому потомку ребенку.

полиморфизма через наследование в Java происходит только с методами, так что если вы хотите, чтобы поведение вы описываете, то вы хотите:

class TestChild extends TestParent{ 

    private int i = 200; 

    @Override 
    public int getI() { return this.i; } 
} 

class TestParent{ 

    private int i = 100; 

    public int getI() { return this.i; } 

    public void printName(){ 
     System.err.println(this.getClass().getName()); 
     System.err.println(this.getI()); // this will print 200 
    } 
} 
+0

Спасибо за быстрый ответ , Не могли бы вы спросить, что это значит? ** «В полях Java нельзя пометить как виртуальные» ** Как я уже упоминал, в моей второй программе метод экземпляра вызывается правильно. Но переменная экземпляра относится к классу родителя. – Jack

+0

Я обновил свой ответ. – Dai

+1

В Java все методы (если не указано) являются «виртуальными», что означает, что они имеют связанную с ним таблицу vtable, которая позволяет выполнять диспетчеризацию во время выполнения. Поля, однако, существуют как абсолютное (ish) место памяти и не компенсируются какой-либо vtable. Я обвиняю путаницу в документе дизайна Java, который не имеет явных «виртуальных» и «переопределяющих» ключевых слов, в то время как C#. – Dai

2

Поскольку поля в Java не являются наследуемыми. Используя ваши декларации, вы фактически объявили два поля i, а экземпляры TestChild будут иметь оба. Когда составлено TestParent, ссылки на i в его методах всегда будут ссылаться на TestParent.i.

+2

Поля наследуются, а не переопределяются. – Dai

+0

Конечно, это лучше фразы. – Dolda2000

2

Невозможно переопределить переменную класса.

Вы не переопределяете переменные класса в Java, а скрываете их. Переопределение - это, например, методы, и скрытие отличается от переопределения.

В примере, который вы указали, объявив переменную класса с именем «i» в классе TestChild, вы спрячете переменную класса, которую она унаследовала от своего суперкласса TestParent с тем же именем «i». Скрытие переменного таким образом не влияет на значение переменного класса «я» в суперклассе TestParent

Чтобы получить желаемое поведение, вы можете просто переопределить метод getI()

class TestChild extends TestParent{ 

    private int i = 200; 

    @Override 
    public int getI() { 
     return this.i; 
    } 
} 
+0

Большое спасибо за ваш ответ. Я читал о том, как скрываться (затенять), но забыл об этом. :(Еще раз спасибо. – Jack

+0

приветствую :) – Rahul

Смежные вопросы