2009-01-31 7 views
3

У меня есть что-то непонятное относительно ссылки на ссылочную переменную в Java.Значение ссылочной переменной в Java

У меня есть два класса A и B. А супер класс B. Если у меня есть два объекта, а затем оператор печати:

A a = new A(); //superclass 

B b = new B(); //subclass 

System.out.println ((A)b); 

то, что именно происходит, когда Println метод выполняется?

Я знаю, потому что B является подклассом А, я позволил сделать следующий бросок:

A a2 = (A)b; 

Я также знаю, что когда Println принимает ссылочную переменную в качестве аргумента, то ToString() метод класса, который создал объект-аргумент, вызывается (неявно). Это так, потому что метод println() ищет аргумент типа String, а метод toString() представляет объект как строку. И даже если мы не будем писать toString(), метод вызывается - неявно. Таким образом, следующие два утверждения эквивалентны:

System.out.println (b); 

System.out.println (b.toString()); 

Итак, мой вопрос: что неявное действие, предпринятое, когда мы имеем

System.out.println ((A)b); 

?

Я полагаю, что тип ссылки переменной Ь автоматически изменяется от В к А. переменная должна еще быть, указывая на тот же объект - тот, созданный с

B b = new B(); 

но только типа б теперь будет изменено. Это верно? Другой вопрос: хотя я изменил тип b на тип суперкласса, являются ли методы переопределения в подклассе, который будет вызван, а не в суперклассе?

Большое спасибо.

С уважением

ответ

1

Правильно ли это?

Сорт. Результат выражения для литья будет иметь тип A. Тип переменной «б» всегда будет оставаться типа B.

Другой вопрос: даже если я изменил тип Ъ к типу суперкласса, являются переопределены методы в подклассе собираются быть но не надклассами?

Будут называться методы экземпляра объекта , лежащего в основе объекта. Пример:

class Foo { 
    public static void main(String[] args) { 
     B b = new B(); 
     assert "B".equals(((A) b).m()); 
    } 
} 

class A { 
    String m() { return "A"; } 
} 

class B extends A { 
    String m() { return "B"; } 
} 
1

Поскольку методы Java имеют динамическую отправку, вызываемая функция не зависит от статического типа ссылки. Таким образом, результаты будут одинаковыми с литой или без нее. [Результаты могут отличаться, если вы были понижены - версия для кастинга может вызвать исключение]

4

В данном случае приведение не имеет никакого влияния.

System.out.println (XXX) принимает параметры разных типов (несколько перегруженных версий), но в этом случае вы получите версию, которая принимает объект. Поскольку каждый объект в Java поддерживает toString(), toString вызывается в фактическом аргументе, независимо от того, что это такое.

Теперь, поскольку все методы в Java отправляются динамически, версия, которая запускается, является версией, соответствующей динамическому типу. Выделение объекта B в A только изменяет статический (объявленный) тип выражения. Динамический тип (что действительно там) по-прежнему является B. Следовательно, вызывается версия в B.

+0

toString() не вызывается, если аргумент передан как String. В других случаях да. –

+0

«System.out.println (XXX) принимает параметр строки типа« .... .Это утверждение неверно. Возможно, вам придется перефразировать его, чтобы сделать его правильным. –

+0

Как отмечает Vinegar, System.out.println (XXX) в этом случае принимает параметр типа Object, который он затем внутренне вызывает toString on, перед передачей результата методу println (String). –

1

Всегда думайте о своем объекте как о типе, который он создавал как (B в вашем случае). Если это взбудоражено, подумайте об этом как ... хм - подумайте об этом, как B надевая одежду A. Это может выглядеть как A, и вы, возможно, не сможете делать какие-либо из хороших вещей, которые вы хотите сделать, но внутри одежды это все еще B - одежда вообще не меняет базовый объект.

Так резюме будет - вы можете вызывать только методы в А, но когда вы называете его, он идет прямо через и выполняет его, как если бы это был Б.

3

Есть много деклараций от println(...) в классе PrintStream (который является типом System.out).

Два из них являются:

void println(String x) 
void println(Object x) 

При вызове println((A)b) компилятор выбирает для вызова println(Object) потому A не String (или любой из других типов, которые println поддерживает). Когда вы вызываете println(b.toString()), компилятор выбирает println(String), потому что вы : Прохождение строки.

В вашем случае отливка b на A не имеет эффекта, поскольку println() не имеет декларации для типов A или B. Но приведение будет по-прежнему происходить (потому что вы его просили), или, может быть, это не произойдет, потому что компилятор оптимизирует его, поскольку он знает, что он избыточен, и он не может потерпеть неудачу и не имеет никакого эффекта.

Это не идиоматичен написать:

A a2 = (A)b; 

как это является излишним, поскольку В представляет собой подкласс A. Это может быть, что компилятор будет оптимизировать на бросок (который является операцией во время выполнения, чтобы отметьте, является ли объект определенного типа, никогда не меняйте его тип).

Как только объект типа B построен, это тип никогда изменений. Это всегда B:

class B extends/implements A {...} 
B b = new B(); // construct a B 
A a = b;   // assign a B to an A variable, it's superclass 
A a = (A) b  // as above including check to see that b is an A (redundant, may be optimised away). 

B b = a;   // Syntax error, won't compile 
B b = (B) a  // Will check whether a is of type B then assign to variable b 

В последнем случае, так как B подкласс A, это может быть, что содержит экземпляр B и бросок получится. Или может быть, что a содержит экземпляр некоторого другого класса, который расширяет/реализует/равен A и не является B, и вы получите ClassCastException.

Так как объект типа B всегда сохраняет его личность (это «B» -ness), то любые (instance-) методы, вызываемые этим объектом, всегда будут вызывать реализацию B независимо от того, будет ли переменная, через которую вы обращаетесь к объекту был объявлен как A или B.

Помните, что вы можете только вызывать методы, объявленные в классе, что переменная определена как.

Так, например, если B объявляет метод b_only(), тогда компилятор не позволит вам писать a.b_only(); вы могли бы написать ((B)a).b_only().

0

Кастинг, как уже упоминалось, не имеет значения в этом случае из-за того, что переопределенные методы динамически связаны. Поскольку toString присутствует во всех объектах, он удовлетворяет этому условию и, следовательно, тип объекта и метод для вызова определяются во время выполнения.

Обратите внимание, что это не так со всеми методами, поскольку только переопределенные методы динамически связаны. Перегруженные методы статически связаны. Многие из ответов здесь упоминают, что java-методы всегда динамически связаны, что неверно.

See this question for a more detailed explanation.

1

Я думаю, когда мы используем ссылочную переменную в Java и с помощью этой переменной можно присвоить объект любого типа класса. в большинстве случаев мы создаем ссылочную переменную интерфейса и абстрактного класса, потому что мы не можем создать объект интерфейса и абстрактный класс, поэтому присваиваем объект класса ссылочной переменной интерфейса или абстрактного класса. Экс-

Interface X { 
public abstract void xx(); 
public abstract void yy(); 
} 

Class XXX implements X { 
    ........... 
} 

Class XY extends XXX { 
    X xy = new XXX(); 
} 

здесь ху является отнесение интерфейса X и присвоить объект класса XXX в качестве ссылки интерфейса.

поэтому, согласно моей точке зрения, используя ссылочную переменную, мы также можем использовать интерфейс для участия в создании объекта.

0

вопрос: хотя я изменил тип b на тип суперкласса, являются ли методы переопределения в подклассе, который будет вызываться, а не в суперклассе?

в этом случае вызывается метод подкласса b; убедительно понять, почему; Вы можете относиться к следующему сценарию реального мира

считает родительским классом Отец демонстрирующего поведение (метод): высоту определяются как

отец высокий, высота = 6'2"

Сын класс ребенок наследует высоты поведение от отца, в результате чего он также высок, высота будучи 6' явно перекрывая поведение

всякий раз, когда ваш подкласс Сын называет высоту поведения на его имя, он отображает переопределенное поведение , то есть его собственную высоту 6 '.

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

  • Нет связанных вопросов^_^