JavaRush /Java 博客 /Random-ZH /引用类型的扩展和收缩

引用类型的扩展和收缩

已在 Random-ZH 群组中发布
你好!在之前的一讲中,我们讨论了原始类型的转换。让我们简单回忆一下我们正在谈论的内容。 引用类型的扩展和收缩 - 1我们根据原始类型(在本例中为数字)占用的内存量将它们表示为嵌套娃娃。您还记得,无论是在现实生活中还是在 Java 编程中,将较小的嵌套娃娃放入较大的嵌套娃娃中都是很简单的。
public class Main {
   public static void main(String[] args) {
        short smallNumber = 100;
        int bigNumber =  smallNumber;
        System.out.println(bigNumber);
   }
}
这是自动转换或扩展 的示例。它会自行发生,因此无需编写额外的代码。最后,我们并没有做任何不寻常的事情:我们只是将一个较小的嵌套娃娃放入一个较大的嵌套娃娃中。如果我们反其道而行之,将一个大的俄罗斯套娃放入一个较小的俄罗斯套娃中,那就是另一回事了。这在生活中是做不到的,但是在编程中却可以做到。但有一点需要注意。如果我们尝试将一个值int放入变量中short,则不会那么容易。毕竟,变量只能容纳 16 位信息short,但值却int需要 32 位!结果,传输的值将会失真。编译器会给我们一个错误(“伙计,你正在做一些可疑的事情! ”),但是如果我们明确指定我们将值转换为什么类型,它仍然会执行这样的操作。
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
在上面的例子中,我们就是这样做的。操作已完成,但由于short32 位中只有 16 位适合该变量,因此最终值被扭曲,结果我们收到了数字-27008。此操作称为显式转换或缩小

引用类型的扩展和收缩示例

现在我们将讨论相同的操作,但不适用于基本类型,而是适用于对象和引用变量!这在 Java 中是如何工作的?其实很简单。有些对象彼此不相关。假设它们不能显式或自动地相互转换是合乎逻辑的:
public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Dog();//error!

   }

}
当然,我们会得到一个错误。这些类彼此不相关,我们也没有编写一个从一个类到另一个类的“转换器” CatDog从逻辑上讲,我们无法做到这一点:编译器不知道如何在这些对象之间进行转换。如果物体相互连接那就是另一回事了!如何?首先,使用继承。让我们尝试创建一个带有继承的小型类系统。我们将有一个代表动物的通用类:
public class Animal {

   public void introduce() {

       System.out.println("i'm Animal");
   }
}
如您所知,动物有家养动物和野生动物:
public class WildAnimal extends Animal {

   public void introduce() {

       System.out.println("i'm WildAnimal");
   }
}

public class Pet extends Animal {

   public void introduce() {

       System.out.println("i'm Pet");
   }
}
以狗为例——一只家狗和一只土狼:
public class Dog extends Pet {

   public void introduce() {

       System.out.println("i'm Dog");
   }
}





public class Coyote extends WildAnimal {

   public void introduce() {

       System.out.println("i'm Coyote");
   }
}
我们的类故意是最原始的,以使它们更容易被感知。我们这里并不真正需要字段,一种方法就足够了。让我们尝试运行以下代码:
public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
你认为控制台会输出什么?introducePet或类方法会起作用吗Animal?在继续阅读之前尝试证明你的答案是正确的。这就是结果! 我是 Pet 为什么答案是这样的?这很简单。我们有一个父变量和一个子对象。通过写:
Animal animal = new Pet();
我们扩展了引用类型Pet并将其对象存储在变量中Animal。与原始类型一样,Java 中引用类型的扩展是自动完成的。无需为此编写额外的代码。现在我们有一个子对象附加到父引用,结果我们看到该方法在子类上被调用。如果您仍然不完全理解这段代码的工作原理,请用简单的语言重写它:
Животное животное = new ДомашнееЖивотное();
这没有问题,对吧?想象一下这是现实生活,本例中的链接是一个简单的纸质标签,上面写着“动物”。如果你把这样一张纸贴在任何宠物的项圈上,一切都会好起来的。任何宠物仍然是动物!相反的过程,即沿着继承树向下移动到继承人,是一个缩小范围:
public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
正如您所看到的,这里我们明确指出我们要将对象转换为哪个类。以前我们有一个变量WildAnimal,现在有Coyote,它沿着继承树向下移动。从逻辑上讲,如果没有明确指示,编译器不会跳过此类操作,但如果您在括号中指定类型,则一切都会起作用。 引用类型的扩展和收缩 - 2 让我们看另一个更有趣的例子:
public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal();//error!
   }
}
编译器会抛出错误!是什么原因? 事实上,您正在尝试将父对象分配给子变量。 换句话说,你想要这样做:
ДомашнееЖивотное домашнееЖивотное = new Животное();
但如果我们明确指出我们试图转换的类型,我们就会成功吗?数字看起来很有效,让我们试试吧!:)
public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
线程“main”中出现异常 java.lang.ClassCastException:动物无法转换为 Pet 错误!这次编译器没有抱怨,但结果我们收到了一个异常。我们已经知道原因:我们正在尝试将父对象分配给子变量。事实上,为什么不能这样做呢? 因为并非所有动物都是宠物。 您创建了一个对象Animal并尝试将其分配给一个变量Pet。但是,例如,土狼也是家畜Animal,但它不是。Pet换句话说,当你写:
Pet pet = (Pet) new Animal();
new Animal()任何动物都可以 在那里,而且不一定是家养的!当然,你的变量Pet pet只适合存储宠物(及其后代),而不适合所有人。因此,对于这种情况,Java 中创建了一个特殊的异常——ClassCastException转换类时出错。让我们再说一遍,以便更清楚。父变量(引用)可以指向后代类的对象:
public class Main {

   public static void main(String[] args) {

       Pet pet =  new Pet();
       Animal animal = pet;

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
例如,我们在这里不会有任何问题。我们有一个Pet由链接指向的对象Pet。然后一个新的链接开始指向同一个对象Animal。之后我们将其转换animalPet. 顺便问一下,我们为什么要这样做?上次我们有一个例外!因为这次我们的原始对象是Pet pet
Pet pet =  new Pet();
在前面的示例中,它是一个对象Animal
Pet pet = (Pet) new Animal();
后代变量不能分配给祖先对象。相反,你可以做到。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION