Java: разница между x = new A () и x = new B (), когда B расширяет a [дубликат]
Возможные Дубликаты:
наследование java-пожалуйста, объясните
Я изучаю Java и у меня два вопроса:
-
в чем разница между:
A x = new A();
и
A x = new B();
потому что:
class A class B extends A
-
в чем разница между:
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 будет вызываться во время выполнения на основе динамической привязки.
нет никакой реальной разницы. На самом деле для второго случая a olds объект B, но B является A, так что это не проблема. B в этом случае ведет себя как A.
он вызовет run_function()
кроме того, с:
A x = new B()
вы не сможете выполнять методы, определенные в B
и это не определено в A
. Однако, как указывалось ранее из-за полиморфизма в Java, если вы выполняете любые методы и B'
переопределил эти методы, тогда он будет использовать 'ы.