对于类变量,向上强制转换和向下强制转换的区别是什么

对于类变量,向上强制转换和向下强制转换的区别是什么?

例如,在下面的程序类 Animal 只包含一个方法,但 Dog 类包含两个方法,然后我们如何将 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();
}
}
328640 次浏览

向上铸造是铸造到一个超类型,而向下铸造是铸造到一个子类型。向上转换总是允许的,但是向下转换涉及到类型检查并且可以抛出 ClassCastException

在您的例子中,从 DogAnimal的转换是向上转换,因为 Dog是-a Animal。通常,只要两个类之间存在 is-a 关系,就可以进行向上转换。

下跌将是这样的:

Animal animal = new Dog();
Dog castedDog = (Dog) animal;

基本上,您所做的就是告诉编译器您知道对象 真的的运行时类型。编译器将允许转换,但仍将插入运行时健全性检查,以确保转换是有意义的。在这种情况下,可以进行强制转换,因为在运行时 animal实际上是 Dog,尽管 animal的静态类型是 Animal

然而,如果你这样做:

Animal animal = new Animal();
Dog notADog = (Dog) animal;

你会得到 ClassCastException。原因是因为 animal的运行时类型是 Animal,所以当您告诉运行时执行强制转换时,它会看到 animal实际上不是 Dog,因此抛出 ClassCastException

要调用超类的方法,可以执行 super.method()或者执行向上转换。

要调用子类的方法,必须执行向下转换。如上所示,这样做通常会冒 ClassCastException的风险; 但是,在执行强制转换之前,可以使用 instanceof操作符检查对象的运行时类型,这样就可以防止 ClassCastException:

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;
}

从引入 模式匹配的 Java16开始,可以更简洁地表示下载:

Animal animal = getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal?
if (animal instanceof Dog castedDog) {
// now castedDog is available here as in the example above
}

向上转换意味着将对象转换为超类型,而向下转换意味着将对象转换为子类型。

在 java 中,向上转换是不必要的,因为它是自动完成的。它通常被称为隐式铸造。您可以指定它,使其他人清楚。

因此,写作

Animal a = (Animal)d;

或者

Animal a = d;

导致完全相同的点,并且在两种情况下都将从 Dog执行 callme()

相反,向下转换是必要的,因为您将 a定义为 Animal 的对象。目前你知道它是一个 Dog,但是 java 不能保证它是。实际上,在运行时它可能是不同的,Java 会抛出一个 ClassCastException,这会发生吗。当然,这不是您的样例示例的情况。如果不将 a强制转换为 Animal,那么由于 Animal没有 callme2()方法,Java 甚至无法编译应用程序。

在您的示例中,您不能从 UseAnimlas到达 Animalcallme()代码(因为 Dog覆盖了它) ,除非该方法如下所示:

class Dog extends Animal
{
public void callme()
{
super.callme();
System.out.println("In callme of Dog");
}
...
}

最好尝试一下这种方法,它很容易理解:

/* 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();
}
}


孩子: 菲戈
汽车 c1 = 新菲戈() ;

=====
上传:-
方法: 对象 c1将引用类的方法(Figo-Method 必须重写) ,因为类“ Figo”是用“ new”指定的。
实例变量: 对象 c1将指声明类别(“ Car”)的实例变量。

当 Declaration 类是父类并且对象是子类创建的时候,就会发生隐式转换,这就是“向上转换”。

======
令人沮丧的是:-
图 f1 = (图) c1;//
方法: 对象 f1将引用类的方法(Figo) ,因为初始对象 c1是用类“ Figo”创建的。但是一旦向下转换完成,只存在于类“ Figo”中的方法也可以被变量 f1引用。
实例变量: 对象 f1不会引用对象 c1声明类的实例变量(c1的声明类是 CAR) ,但是向下强制转换会引用类 Figo 的实例变量。

======
使用: 当对象是子类,声明类是 Parent,子类想要访问它自己类的实例变量,而不是父类的时候,可以使用“向下转换”。

向上转换和向下转换是 Java 的重要组成部分,它允许我们使用简单的语法来构建复杂的程序,并且给了我们很大的优势,比如多态性或者对不同的对象进行分组。Java 允许将子类类型的对象视为任何超类类型的对象。这就是所谓的向上延伸。向上转换是自动完成的,而向下转换必须由程序员 手动完成,我会尽我最大的努力来解释为什么会这样。

向上类型转换和向下类型转换不同于从一个向另一个转换原语,我相信当程序员开始学习向下类型转换对象时,这就是造成很多混乱的原因。

多态性: 默认情况下,Java 中的所有方法都是虚方法。这意味着在继承中使用任何方法都可以被重写,除非该方法被声明为 final 或 static

您可以看到下面的例子如何 getType();的工作根据对象(狗,宠物,警犬)类型。

假设你有三只狗

  1. 狗-这是超级班。

  2. 宠物狗-宠物狗延伸狗。

  3. 警犬-警犬延伸宠物狗。

    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

  obj2.getType();

指纹 Pet Dog

 obj3.getType();

指纹 Police Dog

下载需要由程序员手动完成

当您尝试调用 obj3上的 secretID();方法时,它是 PoliceDog object,但是被引用到 Dog,它是层次结构中的一个超类,它会抛出错误,因为 obj3不能访问 secretId()方法

  ( (PoliceDog)obj3).secretID();

打印 ID

以类似的方式调用 PetDog类中的 dogName();方法,您需要将 obj2向下转换为 PetDog,因为 objec2被引用到 Dog,并且不能访问 dogName();方法

  ( (PetDog)obj2).dogName();

为什么会这样呢? 向上转换是自动的,而向下转换必须是手动的? 好吧,你看,向上转换永远不会失败。 但是如果你有一组不同的狗,并且想把它们都降级为 a,那么有可能,其中一些狗实际上是不同类型的,比如,PetDogPoliceDog,通过抛出 ClassCastException,进程失败了。

如果已经将对象引用到超类类型,那么这就是需要使用 手动下拉你的对象的原因。

注意: 这里通过引用意味着你不会改变你的对象的内存地址,当你向下转换它的时候,它仍然是相同的,你只是把它们分组到特定的类型,在这种情况下 Dog

我知道这个问题很久以前就问过了,但是对于这个问题的新用户来说。 请阅读这篇文章,其中包含完整的说明向上铸造,向下铸造和使用 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
    

Why is that so, that upcasting is automatical, but downcasting must be manual? Well, you see, upcasting can never fail. But if you have a group of different Animals and want to downcast them all to a Cat, then there's a chance, that some of these Animals are actually Dogs, and process fails, by throwing ClassCastException. This is where is should introduce an useful feature called "instanceof", which tests if an object is instance of some Class.

 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;
}

更多信息请阅读 这篇文章

下调和上调情况如下:
enter image description here

向上转换 : 当我们想要将 Sub 类转换为 Super 类时,我们使用向上转换(或扩展)。它是自动发生的,不需要显式地执行任何操作。

强制转换 : 当我们想要将一个 Super 类强制转换为 Sub 类时,我们使用 下降(或者缩小) ,而 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

自动装箱对阵铸造

我们可以创建对象到 Downcast。在这个类型中也可以: 调用基类方法

Animal a=new Dog();
a.callme();
((Dog)a).callme2();

也许这张桌子有用。 调用类 Parent或类 Childcallme()方法。 作为一个原则:

UPCASTING —— > 躲藏

压抑-> 启示

enter image description here

enter image description here

enter image description here

1.-上传。

做一个向上转换,定义了某种类型的标记,它指向子类型的对象(类型和子类型可以被称为 class 和 subclass,如果你觉得更舒服的话...)。

Animal animalCat = new Cat();

这意味着这样的标记 animalCat 将只具有 Animal 类型的功能(方法) ,因为我们将其声明为 Animal 类型,而不是 Cat 类型。

我们可以在编译时或运行时以“自然/隐式/自动”的方式进行此操作,这主要是因为 Cat 从 Animal 继承了一些功能; 例如 move ()。(至少,猫是一种动物,不是吗?)

2. 下行。

但是,如果我们需要从我们的动物类型标签中获得 Cat 的功能,会发生什么呢。

因为我们已经创建了指向 Cat 对象的 animalCat 标记,所以我们需要一种方法来调用 Cat 对象方法,从我们的 animalCat 标记以一种聪明漂亮的方式。

这样的过程就是我们所说的“向下转换”,我们只能在运行时执行。

下面是一些代码:

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();
        

}


}