Какая необходимость использовать Upcasting в java?
Я просмотрел большую часть бумаг в сети, но я все еще не могу понять, почему мы должны использовать повышение.
class Animal
{
public void callme()
{
System.out.println("In callme of Animal");
}
}
class Dog extends Animal
{
public void callme()
{
System.out.println("In callme of Dog");
}
public void callme2()
{
System.out.println("In callme2 of Dog");
}
}
public class UseAnimlas
{
public static void main (String [] args)
{
Dog d = new Dog();
Animal a = (Animal)d;
d.callme();
a.callme();
((Dog) a).callme2();
}
}
Вы можете рассмотреть этот пример для повышения. Какая польза от повышения? Оба d
и a
выдают тот же результат!
Ответы
Ответ 1
В большинстве ситуаций явный выброс не нужен и не имеет никакого эффекта.
В вашем примере явный upcast
Animal a = (Animal)d;
можно заменить на это:
Animal a = d; // implicit upcast
Цель неявного преобразования (для типа объекта Java) состоит в том, чтобы "забыть" информацию о статическом типе, чтобы объект с определенным типом мог использоваться в ситуации, которая требует более общего типа. Это влияет на проверку типов во время компиляции и разрешение перегрузки, но не на поведение во время выполнения.
(Для примитивного типа преобразование с повышением частоты приводит к преобразованию и может в некоторых случаях привести к потере точности; например, long
→ float
.)
Тем не менее, существуют ситуации, когда наличие явного отката изменяет значение выражения/выражения.
Одна из ситуаций, когда необходимо использовать апкастинг в Java, - это когда вы хотите принудительно использовать определенный метод переопределения; например, предположим, что у нас перегружены методы:
public void doIt(Object o)...
public void doIt(String s)...
Если у меня есть строка и я хочу вызвать первую перегрузку, а не вторую, я должен сделать это:
String arg = ...
doIt((Object) arg);
Связанный случай:
doIt((Object) null);
где код не будет компилироваться без приведения типа. (Я не уверен, что это считается повышением, но здесь это все равно.)
Вторая ситуация включает в себя случайные параметры:
public void doIt(Object... args)...
Object[] foo = ...
doIt(foo); // passes foo as the argument array
doIt((Object) foo); // passes new Object[]{foo} as the argument array.
Третья ситуация - при выполнении операций с примитивными числовыми типами; например
int i1 = ...
int i2 = ...
long res = i1 + i2; // 32 bit signed arithmetic ... might overflow
long res2 = ((long) i1) + i2; // 64 bit signed arithmetic ... won't overflow
Ответ 2
Что нужно использовать для перехода в Java?
Не уверен, что вы правильно указали терминологию, но здесь цитата, чтобы уточнить:
приведение к базовому типу
Выполнение переноса из производного класса в более общий базовый класс.
И здесь один сценарий, где это действительно имеет значение:
class A {
}
class B extends A {
}
public class Test {
static void method(A a) {
System.out.println("Method A");
}
static void method(B b) {
System.out.println("Method B");
}
public static void main(String[] args) {
B b = new B();
method(b); // "Method B"
// upcasting a B into an A:
method((A) b); // "Method A"
}
}
Ответ 3
Активация может потребоваться, если у вас есть перегруженные методы и вы не хотите называть специализированный, как писал aioobe. (Вместо этого вы могли бы назначить новую переменную типа A
.)
Еще один пример, когда необходимость в upcast была связана с оператором ?:
, но я не помню его сейчас. И иногда вам нужны upcasts в случае varargs-методов:
public void doSomething(Object... bla) {}
Если мы хотим передать Object[] array
как единственный параметр (а не его объекты как отдельные), мы должны написать либо
doSomething((Object)array);
или
doSomething(new Object[]{array});
Ответ 4
В вашем примере не имеет никакого значения значение Upcasting (на самом деле я не могу представить ни одного случая, когда он есть), и его следует избегать, поскольку это только путает разработчиков. Некоторые IDE (IntelliJ наверняка) выдадут предупреждение в этой строке и предлагают удалить повышение).
EDIT: этот код дает те же результаты, потому что все объектные методы в Java являются виртуальными, что означает, что целевой метод обнаруживается фактическим типом объекта во время выполнения, а не ссылочным типом. Попробуйте сделать callme()
static и посмотреть, что произойдет.
Ответ 5
Рассмотрим сценарий, Банк - это класс, который предоставляет метод для получения процентной ставки. Но процентная ставка может различаться в зависимости от банков. Например, банки SBI, ICICI и AXIS предоставляют 8,4%, 7,3% и 9,7% ставки процента.
class Bank{
float getRateOfInterest(){return 0;}
}
class SBI extends Bank{
float getRateOfInterest(){return 8.4f;}
}
class ICICI extends Bank{
float getRateOfInterest(){return 7.3f;}
}
class AXIS extends Bank{
float getRateOfInterest(){return 9.7f;}
}
class TestPolymorphism{
public static void main(String args[]){
Bank b;
b=new SBI();
System.out.println("SBI Rate of Interest: "+b.getRateOfInterest());
b=new ICICI();
System.out.println("ICICI Rate of Interest: "+b.getRateOfInterest());
b=new AXIS();
System.out.println("AXIS Rate of Interest: "+b.getRateOfInterest());
}
}
Вывод:
SBI Rate of Interest: 8.4
ICICI Rate of Interest: 7.3
AXIS Rate of Interest: 9.7
Ответ 6
Учитывая, что методы объектов Java являются виртуальными по умолчанию, я вообще не вижу возможности для повышения.
Где вы видели учебники, сообщающие, что повышение должно было быть необходимо? Это первый раз, когда я слышу об этом для Java. (Обратите внимание, что это имеет смысл в С# или С++, но обычно это знак плохого дизайна.)
Ответ 7
Некоторые ответы:
- Ускорение происходит неявно при передаче определенного объекта методу, принимающему более общий объект. В вашем примере, когда вы передаете Собака методу, принимающему Животное, произойдет повышение уровня, хотя вы не делаете это явно с круглыми скобками.
- Как упоминалось здесь, в сценариях перегрузки методов, где у вас есть общие и конкретные методы. В вашем примере представьте метод, принимающий собаку, а другой с тем же именем, принимающим Animal. Если по какой-то причине вам нужно вызвать общую версию, вам необходимо явно повысить уровень вашего объекта.
- Явное повышение может использоваться как форма документации; если в какой-то момент вашего кода вам больше не нужно обращаться к Собаке, как к Собаке, но продолжать рассматривать его как Животное, может быть хорошей идеей для повышения, чтобы другие разработчики могли понять, что происходит.
Ответ 8
В этом примере мы создаем два класса Bike и Splendar. Класс Splendar расширяет класс Bike и отменяет его метод run(). Мы вызываем метод run с помощью ссылочной переменной класса Parent. Поскольку он относится к объекту подкласса, а метод подкласса переопределяет метод класса Parent, метод подкласса вызывается во время выполнения.
Так как вызов метода определяется JVM не компилятором, он известен как полиморфизм времени выполнения.
class Bike{
void run(){System.out.println("running");}
}
class Splender extends Bike{
void run(){System.out.println("running safely with 60km");}
public static void main(String args[]){
Bike b = new Splender();//upcasting
b.run();
}
}
Ответ 9
Простое объяснение "Ускорение"...
Есть 2 класса, один из которых является родительским классом (Demo1), второй - его подкласс (Demo).
-
Если метод run1 не имеет параметров, то вывод метода будет таким же. Нет возможности использовать Upcasting.
class Demo1{
void run1(){
System.out.println("hello");
}
}
class Demo extends Demo1 {
void run1(){
System.out.println("hello1");
}
public static void main(String args[]){
Demo d = new Demo();
d.run1();
Demo1 d1 = new Demo();
d1.run1();
}
}
Вывод для d.run1(); и d1.run1(); будет таким же.
output: hello1
-
Если мы используем Параметризированную перегрузку, то можно четко увидеть использование повышения. Для Уайкинга есть смысл.
class Demo1{
void run1(int a){
System.out.println(a);
}
}
class Demo extends Demo1 {
void run1(String b){
System.out.println(b);
}
public static void main(String args[]){
Demo d = new Demo();
d.run1("b");
Demo1 d1 = new Demo();
d1.run1(2);
}
}
Вывод для d.run1(); и d1.run1(); будет другим.
output: b
2