Upcasting на java
В Java предположим, что у меня есть 3 класса, C простирается от B, который простирается от A.
class X {
interface A {}
interface B extends A {}
interface C extends B {}
void f(A a) {}
void test() {
C c = new C()
B b = (B) c;
f(b);
}
}
Если я сделаю что-то подобное, как показано в test() выше:
C c = new C()
B b = (B) c;
f(b);
f() принимает b как Тип C, так как C и B оба простираются от A. Я хотел f() получить b как тип B, а не Тип C.
Есть ли в любом случае, чтобы форсировать эту передачу?
9 ответов:
f()будет Всегда получать что-то, напечатанное как A (несмотря на то, что под обложками это на самом деле B или C, и может быть соответствующим образом опущено).Вы можете определить дополнительный f () таким образом
f(B b);И при необходимости
f(C c);И правильный будет вызван в зависимости от класса аргумента. то есть компилятор определяет, какая функция вызывается в зависимости от типа аргумента. Это отличается от динамической отправки (или полиморфизма), которая произошла бы во время выполнения.
Обратите внимание, что ваш бросок в вопросе избыточен. Вы можете написать:
C c = new C() B b = c; f(b);Поскольку C простирается от B, C является a B.
Похоже, вас смущает разница между типом времени компиляции и типом времени выполнения.
Вы создаете объект (на который указывают ссылки c и b) типа C, и он будет оставаться C, потому что невозможно изменить тип времени выполнения объекта и, следовательно, поведение; путем приведения вы можете просто изменить его тип времени компиляции, что влияет на то, как компилятор обрабатывает его.
Можете ли вы дать дополнительную информацию о конкретной проблеме, которую вы пытаетесь решить? Скорее всего, есть способ достичь своей цели, изменив дизайн.
Я хотел, чтобы f получал b как тип B, а не тип C.
A
C- этоB- этоA.Внутри
Именно так работают виртуальные функции. Идея состоит в том, что объект, на который ссылаются, действительно являетсяf,fвидит только частьAсвоего параметраa, Еслиfвызывает открытую функциюA, которая переопределена вC, вызывается переопределениеC.C, поэтому он должен проявлятьCповедение. Если вы хотитеBповедения, передайте экземплярB, не экземплярC.Если 'C' и' B ' должны иметь одинаковое поведение, не проверяйте это поведение в
C.Почему вы хотите это сделать?
Ваш вопрос не имеет смысла. Что вы подразумеваете под "f принимает b как Тип C"?
F принимает b как тип A, так как сигнатура метода говорит "A". Если вы вызываете методы на b, они будут вызваны на C, если C переопределяет их. Но это стандартное поведение в Java (все методы подобны виртуальным методам в C++), и нет никакого способа изменить его.
Может быть, вы сможете описать вашу реальную проблему, тогда мы сможем помочь.
Тот факт, что вы можете передать любой подкласс A в качестве параметра f(A a), присущ OO в Java, нет никакого способа обойти это. Если C расширяет A, вы можете Всегда использовать его там, где ожидается A.
Вы можете использовать отражение, чтобы проверить, относится ли параметр к классу A:
Не знаю, хотите ли вы этого, но это может быть полезно.public void f(A a) { if (a.getClass() == A.class) { // ok, go on } else { System.err.println("The parameter is not of class A!"); } }
Ваша проблема может быть решена путем понимания разницы между ссылочным типом и типом экземпляра. При приведении объекта C в качестве B изменяется только ссылочный тип-фактический экземпляр объекта по - прежнему является объектом C-это должно быть совершенно очевидно, если вы смотрите на объект в режиме отладки. Изменение ссылочного типа влияет только на то, как компилятор обрабатывает / воспринимает код-поведение среды выполнения не должно быть затронуто. Любой вызов метода на объект, всегда будет вызывать с метод (независимо от того, был ли объект приведен к чему-то другому или нет). Если вы переопределяете метод из B и хотите вызвать версию метода B, то вам нужно будет создать экземпляр B.
Тот факт, что ваш код имеет ссылку на A, не означает, что указываемый объект тоже является A. Если это A C, то он остается C. ссылка в исходном коде ограничивает только доступные методы в исходном коде. Приведение необходимо только потому, что иногда требуется метод на другом типе,и нам нужно обмануть компилятор, чтобы он позволил нам начать использовать методы на кастах для ввода. Естественно, приведение может потерпеть неудачу во время выполнения, если попытка является недействительной.
In upcasting and downcasting the object first upcast then downcastenter class A { } class B extends A { } Class M { psvm(String ar[]) { A a1= new B(); B b2=(B)a1; }
Comments