Java: разница между x = new A () и x = new B (), когда B расширяет a [дубликат]

Возможные Дубликаты:
наследование java-пожалуйста, объясните

Я изучаю Java и у меня два вопроса:

  1. в чем разница между:

    A x = new A();
    

    и

    A x = new B();
    

    потому что:

    class A
    class B extends A
    
  2. в чем разница между:

    A x = new B();
    (A)x.run_function();
    

    предположим, что оба A и B имеют функцию run_function, который из них будет выполнен ?

6 ответов


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

скажем, B расширяет A, а C расширяет B.

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

статический тип ссылки на объект (переменная) является типом времени компиляции: он определяет или, скорее, объявляет, какие методы могут быть вызваны для объекта ссылка на переменную.

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

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

и, наконец, вызов метода ссылка на объект-это тонкое и сложное взаимодействие между статическими и динамическими типами. (Прочитайте спецификацию языка Java при вызове метода, если вы мне не верите.)

если оба A и B реализуют метод f (), например, и статический тип A и динамический тип C для вызова метода, то B. f () будет вызван:

B extends A, C extends B
public A.f() {}
public B.f() {}
A x = new C(); // static type A, dynamic type C
x.f(); // B.f() invoked

значительно упрощая: сначала статические типы как приемника (тип A) , так и аргументов (без args) используются для решения наилучшая (наиболее специфичная) сигнатура метода для этого конкретного вызова, и это делается во время компиляции. Здесь это явно A. f ().

затем, на втором шаге во время выполнения, динамический тип используется для поиска фактической реализации нашей подписи метода. Мы начинаем с типа C, но мы не находим реализацию f (), поэтому мы переходим к B, и там у нас есть метод B. f (), который соответствует сигнатуре A. f(). Таким образом, вызывается B. f ().

в нашем примере мы говорим этот метод B. f () переопределяет метод A. f (). Механизм переопределения методов в иерархии типов называется полиморфизмом подтипов.


1. на

A x = new A();

x создание A и типа A.

а в

A x = new B();

x создание B и типа A.


2. важно отметить, что здесь (во втором случае), если вы позвоните x.someMethod() метод B будет вызываться, а не метод A (это называется динамическое связывание, а не статическое связывание). Кроме того, кастинг изменяет только тип, так что

A x = new B();
((A)x).run_function();  // Need extra parenthesis!

будут по-прежнему называть 'ы.


как я уже сказал выше, вам нужно включить эти дополнительные скобки, так как

(A)x.run_function();

эквивалентно

(A)(x.run_function());

Пример 1:

вы увидите разницу, когда у вас есть метод в B которого нет в A.

при попытке вызвать этот метод с помощью ссылки " x " он не будет виден.

Пример 2:

все вызовы методов будут основаны на типе объекта не ссылочный тип из-за полиморфизма (кроме статических методов)

A x = new B();

в этом случае B класс run_function будет выполненный.

A x = new A();

в этом случае A класс run_function будет выполнен.


1.What is the difference between: A x = new A();and A x = new B();

разница в том, что в первом случае вы создаете экземпляр класса типа A. Поэтому вы сможете вызывать только методы, определенные в A. во втором случае, если один и тот же метод имени существует как в A, так и в, то реализация B будет вызываться во время выполнения.

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

A x = new B(); (A)x.run_function();предположим, что оба A и B иметь функция run_function, которая будет выполнена ?

запомнить-переопределение решается во время выполнения, а перегрузка - во время компиляции.

таким образом, метод в классе B будет вызываться во время выполнения на основе динамической привязки.


  1. нет никакой реальной разницы. На самом деле для второго случая a olds объект B, но B является A, так что это не проблема. B в этом случае ведет себя как A.

  2. он вызовет run_function()


кроме того, с:

A x = new B()

вы не сможете выполнять методы, определенные в B и это не определено в A. Однако, как указывалось ранее из-за полиморфизма в Java, если вы выполняете любые методы и B' переопределил эти методы, тогда он будет использовать 'ы.