В чем разница между преобразованием вверх и вниз относительно переменной класса?
Например, в следующей программе класс Animal содержит только один метод, но класс Dog содержит два метода, а затем мы приводим переменную Dog к переменной Animal.
Если приведение выполнено, то как мы можем вызвать другой метод Dog с переменной Animal.
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();
}
}
Dog
- это файлAnimal
. В большинстве случаев апкастинг не требуется, если вы не хотите использовать определенный перегруженный метод.callme
существует в обоихAnimal
иDog
.callme2
существует только вDog
, которые вы приводите ,a
чтобыDog
сделать его работу.Ответы:
Приведение вверх - это приведение к супертипу, а при понижении - к подтипу. Приведение вверх всегда разрешено, но оно включает проверку типа и может вызвать ошибку
ClassCastException
.В вашем случае приведение от a
Dog
к anAnimal
является восходящим, потому что aDog
is-aAnimal
. В общем, вы можете повышать качество всякий раз, когда существует связь между двумя классами.Понижающее значение будет примерно таким:
Animal animal = new Dog(); Dog castedDog = (Dog) animal;
По сути, вы говорите компилятору, что знаете, каков тип среды выполнения объекта на самом деле . Компилятор разрешит преобразование, но все равно будет вставлять проверку работоспособности, чтобы убедиться, что преобразование имеет смысл. В этом случае приведение возможно, потому что во время выполнения
animal
фактически является a,Dog
хотя статический типanimal
равенAnimal
.Однако, если вы сделаете это:
Animal animal = new Animal(); Dog notADog = (Dog) animal;
Вы получите файл
ClassCastException
. Причина в том, чтоanimal
тип среды выполнения равенAnimal
, и поэтому, когда вы говорите среде выполнения выполнить приведение, она видит, что наanimal
самом деле это не a,Dog
и поэтому выдает aClassCastException
.Чтобы вызвать метод суперкласса, вы можете выполнить
super.method()
или, выполнив приведение вверх.Чтобы вызвать метод подкласса, вы должны выполнить приведение вниз. Как показано выше, вы обычно рискуете
ClassCastException
: однако вы можете использоватьinstanceof
оператор для проверки типа среды выполнения объекта перед выполнением приведения, что позволяет предотвратитьClassCastException
s:Animal animal = getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal? if (animal instanceof Dog) { // Guaranteed to succeed, barring classloader shenanigans Dog castedDog = (Dog) animal; }
источник
ClassCastException
или нет? Как в первом случае?Down-casting и up-casting были следующими:
Апкастинг : когда мы хотим преобразовать подкласс в суперкласс, мы используем апкастинг (или расширение). Это происходит автоматически, ничего явно делать не нужно.
Downcasting : когда мы хотим преобразовать суперкласс в Sub класс, мы используем Downcasting (или сужение), а Downcasting не возможен напрямую в Java, мы должны явно это сделать.
Dog d = new Dog(); Animal a = (Animal) d; //Explicitly you have done upcasting. Actually no need, we can directly type cast like Animal a = d; compiler now treat Dog as Animal but still it is Dog even after upcasting d.callme(); a.callme(); // It calls Dog's method even though we use Animal reference. ((Dog) a).callme2(); // Downcasting: Compiler does know Animal it is, In order to use Dog methods, we have to do typecast explicitly. // Internally if it is not a Dog object it throws ClassCastException
источник
Повышающее и понижающее преобразование - важная часть Java, которая позволяет нам создавать сложные программы с использованием простого синтаксиса и дает нам большие преимущества, такие как полиморфизм или группировка различных объектов. Java позволяет рассматривать объект типа подкласса как объект любого типа суперкласса. Это называется апкастингом. Повышение качества выполняется автоматически, а понижающее преобразование должно выполняться программистом вручную , и я постараюсь объяснить, почему это так.
Повышение и понижающее приведение НЕ похожи на приведение примитивов от одного к другому, и я считаю, что это вызывает большую путаницу, когда программист начинает изучать приведение объектов.
Полиморфизм: все методы в java по умолчанию виртуальные. Это означает, что любой метод может быть переопределен при использовании в наследовании, если этот метод не объявлен как final или static .
Ниже вы можете увидеть пример
getType();
работы в зависимости от типа объекта (Dog, Pet, Police Dog).Предположим, у вас есть три собаки
Собака - это суперкласс.
Pet Dog - Собака расширяет Dog.
Police Dog - Полицейская собака расширяет Pet Dog.
public class Dog{ public String getType () { System.out.println("NormalDog"); return "NormalDog"; } } /** * Pet Dog has an extra method dogName() */ public class PetDog extends Dog{ public String getType () { System.out.println("PetDog"); return "PetDog"; } public String dogName () { System.out.println("I don't have Name !!"); return "NO Name"; } } /** * Police Dog has an extra method secretId() */ public class PoliceDog extends PetDog{ public String secretId() { System.out.println("ID"); return "ID"; } public String getType () { System.out.println("I am a Police Dog"); return "Police Dog"; } }
Полиморфизм: все методы в java по умолчанию виртуальные. Это означает, что любой метод может быть переопределен при использовании в наследовании, если только этот метод не объявлен как final или static (объяснение относится к концепции виртуальных таблиц)
public static void main (String[] args) { /** * Creating the different objects with super class Reference */ Dog obj1 = new Dog(); ` /** * Object of Pet Dog is created with Dog Reference since * Upcasting is done automatically for us we don't have to worry about it * */ Dog obj2 = new PetDog(); ` /** * Object of Police Dog is created with Dog Reference since * Upcasting is done automatically for us we don't have to worry * about it here even though we are extending PoliceDog with PetDog * since PetDog is extending Dog Java automatically upcast for us */ Dog obj3 = new PoliceDog(); } obj1.getType();
Печать
Normal Dog
Печать
Pet Dog
Печать
Police Dog
Понижающее значение должно выполняться программистом вручную
Когда вы пытаетесь вызвать
secretID();
метод, наobj3
который естьPoliceDog object
ссылка,Dog
который является суперклассом в иерархии, он выдает ошибку, посколькуobj3
у него нет доступа кsecretId()
методу. Чтобы вызвать этот метод, вам необходимо вручную отключить этот obj3, чтобыPoliceDog
который печатает
ID
Аналогичным образом для вызова
dogName();
метода вPetDog
классе необходимо обратное приведениеobj2
кPetDog
так obj2 отсчитываютсяDog
и не имеет доступ кdogName();
методеПочему так происходит автоматическое преобразование с повышением частоты, а с понижением - вручную? Видите ли, апкастинг никогда не подводит. Но если у вас есть группа различных собак и хотят их всех обратное приведение к их типу, то есть шанс, что некоторые из этих собак на самом деле различных типов , то есть,
PetDog
,PoliceDog
и процесс выходит из строя, путем метанияClassCastException
.Это причина, по которой вам нужно вручную понижать качество ваших объектов, если вы связали свои объекты с типом суперкласса.
источник
Я знаю, что этот вопрос задан довольно давно, но для новых пользователей этого вопроса. Пожалуйста, прочтите эту статью, в которой содержится полное описание повышения, понижения и использования оператора instanceof.
Нет необходимости делать апкастинг вручную, это происходит само по себе:
Mammal m = (Mammal)new Cat();
равноMammal m = new Cat();
Но понижающее преобразование всегда нужно делать вручную:
Cat c1 = new Cat(); Animal a = c1; //automatic upcasting to Animal Cat c2 = (Cat) a; //manual downcasting back to a Cat
Почему так происходит автоматическое преобразование с повышением частоты, а с понижением - вручную? Видите ли, апкастинг никогда не подводит. Но если у вас есть группа разных животных и вы хотите превратить их всех в кошку, то есть шанс, что некоторые из этих животных на самом деле являются собаками, и процесс завершается ошибкой из-за выброса ClassCastException. Здесь следует ввести полезную функцию под названием «instanceof» , которая проверяет, является ли объект экземпляром некоторого класса.
Cat c1 = new Cat(); Animal a = c1; //upcasting to Animal if(a instanceof Cat){ // testing if the Animal is a Cat System.out.println("It's a Cat! Now i can safely downcast it to a Cat, without a fear of failure."); Cat c2 = (Cat)a; }
Для получения дополнительной информации прочтите эту статью
источник
Лучше попробуйте этот метод апкастинга, это легко понять:
/* upcasting problem */ 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) { Animal animal = new Animal (); Dog dog = new Dog(); Animal ref; ref = animal; ref.callme(); ref = dog; ref.callme(); } }
источник
Может эта таблица поможет. Вызов
callme()
метода классаParent
или классаChild
. В принципе:источник
1.- Повышение качества.
Выполняя восходящее преобразование, вы определяете тег некоторого типа, который указывает на объект подтипа (тип и подтип можно назвать классом и подклассом, если вам удобнее ...).
Animal animalCat = new Cat();
Это означает, что такой тег animalCat будет иметь функции (методы) только типа Animal, потому что мы объявили его как тип Animal, а не как тип Cat.
Нам разрешено делать это «естественным / неявным / автоматическим» способом, во время компиляции или во время выполнения, в основном потому, что Cat наследует некоторые свои функции от Animal; например, move (). (По крайней мере, кошка - животное, не так ли?)
2.- Понижение.
Но что произойдет, если нам понадобится получить функциональность Cat из нашего тега типа Animal ?.
Поскольку мы создали тег animalCat, указывающий на объект Cat, нам нужен способ вызова методов объекта Cat из нашего тега animalCat довольно умным способом.
Такая процедура - это то, что мы называем Downcasting, и мы можем делать это только во время выполнения.
Время для кода:
public class Animal { public String move() { return "Going to somewhere"; } } public class Cat extends Animal{ public String makeNoise() { return "Meow!"; } } public class Test { public static void main(String[] args) { //1.- Upcasting // __Type_____tag________object Animal animalCat = new Cat(); //Some animal movement System.out.println(animalCat.move()); //prints "Going to somewhere" //2.- Downcasting //Now you wanna make some Animal noise. //First of all: type Animal hasn't any makeNoise() functionality. //But Cat can do it!. I wanna be an Animal Cat now!! //___________________Downcast__tag_____ Cat's method String animalNoise = ( (Cat) animalCat ).makeNoise(); System.out.println(animalNoise); //Prints "Meow!", as cats usually done. //3.- An Animal may be a Cat, but a Dog or a Rhinoceros too. //All of them have their own noises and own functionalities. //Uncomment below and read the error in the console: // __Type_____tag________object //Cat catAnimal = new Animal(); } }
источник
Родитель: Автомобиль
Ребенок: Фигу
Автомобиль c1 = новый Фигу ();
=====
Повышение качества: -
Метод: объект c1 будет ссылаться на методы класса (Figo - метод должен быть переопределен), потому что класс «Figo» определен как «новый».
Переменная экземпляра: объект c1 будет ссылаться на переменную экземпляра класса объявления («автомобиль»).
Когда класс объявления является родительским, а объект создается из дочернего, происходит неявное приведение типов, которое называется «апкастингом».
======
Понижающее значение: -
Фиг. F1 = (Фиг. //
Метод: объект f1 будет ссылаться на метод класса (фигу), поскольку исходный объект c1 создается с классом «фигу». но как только приведение вниз выполнено, методы, которые присутствуют только в классе «Фигу», также могут быть упомянуты переменной f1.
Переменная экземпляра: объект f1 не будет ссылаться на переменную экземпляра класса объявления объекта c1 (класс объявления для c1 - CAR), но при приведении вниз он будет ссылаться на переменные экземпляра класса Figo.
======
Использование: Когда объект относится к дочернему классу, а класс объявления - к родительскому, а дочерний класс хочет получить доступ к переменной экземпляра своего собственного класса, а не родительского класса, то это можно сделать с помощью «Downcasting».
источник
восходящее преобразование означает преобразование объекта в супертип, в то время как нисходящее преобразование означает преобразование в подтип.
В java апкастинг не нужен, так как он выполняется автоматически. И это обычно называется неявным приведением типов. Вы можете указать это, чтобы было понятно другим.
Таким образом, написание
или
приводит к точно такой же точке, и в обоих случаях будет выполняться
callme()
fromDog
.Вместо этого необходимо понижение, потому что вы определили
a
как объект Animal. В настоящее время вы знаете, что это aDog
, но у java нет никаких гарантий. На самом деле во время выполнения это может быть иначе, и Java выдаст ошибкуClassCastException
, если бы это произошло. Конечно, это не относится к вашему примеру. Если бы не броситьa
наAnimal
, Java не мог даже скомпилировать приложение , потому чтоAnimal
не имеет методcallme2()
.В вашем примере вы не можете достичь кода
callme()
изAnimal
сUseAnimlas
(потому чтоDog
переписывает его) , если метод не будет следующим:class Dog extends Animal { public void callme() { super.callme(); System.out.println("In callme of Dog"); } ... }
источник
Мы можем создать объект для Downcasting. В этом типе тоже. : вызов методов базового класса
Animal a=new Dog(); a.callme(); ((Dog)a).callme2();
источник