CodeGym /Java 博客 /随机的 /引用类型的扩大和缩小
John Squirrels
第 41 级
San Francisco

引用类型的扩大和缩小

已在 随机的 群组中发布
你好!在过去的课程中,我们讨论了转换原始类型。让我们简要回顾一下讨论的内容。 引用类型的扩大和缩小 - 1我们将基本类型(在本例中为数字类型)想象成嵌套的玩偶,它们的大小根据它们占用的内存量而变化。您会记得,在现实生活和 Java 编程中,将较小的玩偶放入较大的玩偶中都很简单。

public class Main {
   public static void main(String[] args) {
       int bigNumber = 10000000;
       short smallNumber = (short) bigNumber;
       System.out.println(smallNumber);
   }
}
这是一个自动转换或加宽 的例子。它会自动发生,因此您无需编写额外的代码。最后,我们并没有做任何不寻常的事情:我们只是将一个较小的娃娃放入一个较大的娃娃中。如果我们试图反其道而行之,将较大的俄罗斯套娃放入较小的套娃中,那就另当别论了。你不能在现实生活中做到这一点,但在编程中你可以。但有一个细微差别。如果我们尝试将 an 放入变量intshort,事情就不会那么顺利了。毕竟short变量只保存了16位的信息,而an却int占据了32位!结果,传递的值被扭曲。编译器会给我们一个错误('伙计,你在做一些可疑的事情!'). 但是,如果我们明确指出要将我们的值转换为的类型,它将继续执行操作。

public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
这就是我们在上面的例子中所做的。该操作已执行,但由于该short变量只能容纳 32 个字节中的 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();
   }
}
您认为控制台上会显示什么?会调用类的方法还是类introduce的方法?在继续阅读之前尝试证明你的答案是正确的。这就是结果! 我是宠物 为什么我们得到那个?一切都很简单。我们有一个父变量和一个后代对象。通过写作, PetAnimal

Animal animal = new Pet();
我们扩大了一个Pet引用并将其分配给一个Animal变量。与原始类型一样,引用类型在 Java 中会自动扩展。您不需要编写额外的代码来实现它。现在我们有一个分配给父引用的后代对象。结果,我们看到方法调用是在子类上进行的。如果您仍然不完全理解此代码为何有效,请用通俗易懂的语言重写它:

Animal animal = new DomesticatedAnimal();
这个没有问题吧?想象一下这是真实的生活,参考只是一张写有“动物”的纸质标签。如果你把那张纸贴在任何宠物的项圈上,一切都会正确。毕竟,任何宠物都是动物!相反的过程——将继承树向下移动到后代——正在缩小:

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!
   }
}
编译器产生错误!但为什么? 因为您正试图将父对象分配给后代引用。 换句话说,你正在尝试做这样的事情:

DomesticatedAnimal domesticatedAnimal = new Animal();
好吧,如果我们明确指定我们试图转换成的类型,也许一切都会起作用? 这对数字有效——让我们试一试吧!:)

public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
线程“main”中的异常 java.lang.ClassCastException: Animal cannot be cast to Pet 错误!编译器这次没有对我们大喊大叫,但我们以异常结束。我们已经知道原因:我们试图将父对象分配给后代引用。但是为什么你不能那样做呢? 因为不是所有的动物都是家养动物。 您创建了一个Animal对象并试图将其分配给一个Pet变量。土狼也是一个Animal,但它不是Pet。换句话说,当你写

Pet pet = (Pet) new Animal();
new Animal()可以代表任何动物,不一定是宠物!当然,您的Pet pet变量仅适用于存储宠物(及其后代),而不适用于任何类型的动物。ClassCastException这就是为什么为在转换类时发生错误的情况创建特殊的 Java 异常的原因。让我们再次回顾它以使事情更清楚。父引用可以指向子类的实例:

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 = new Pet();
但在最后一个例子中,它是一个Animal对象:

Pet pet = (Pet) new Animal();
您不能将祖先对象分配给后代变量。你可以做相反的事情。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION