Java Top.

开始使用Spring 5和Spring Boot 2,通过学习春天课程:

>>查看课程

1.概述

Java类型系统由两种类型组成:原语和引用。

中介绍了基元转换本文,我们将专注于在此投用的参考文献,了解Java如何处理类型的类型。

进一步阅读:

Java泛型基础

快速介绍Java泛型的基础知识。

Java instanceof运算符

了解Java金宝搏官网188be中的instanceof运算符

2.原始与参考

虽然原始转换和参考可变铸件可能看起来相似,但它们非常不同的概念

在这两种情况下,我们都在将一种类型“转变”为另一种类型。但是,简单来说,原始变量包含它的值,原始变量的转换意味着它的值发生不可逆的变化:

双倍mydouble = 1.1;int myint =(int)mydouble;assertnotequals(mydouble,myint);

在上述示例中的转换之后,变量是1,我们无法恢复原来的价值1.1从中。

参考变量是不同的;引用变量只引用一个对象,而不包含对象本身。

并施放参考变量不会触摸它引用的对象,但仅以另一种方式标记此对象,扩展或缩小与之合作的机会。向上转换缩小了该对象可用的方法和属性的列表,向下转换可以扩展它。

参考就像对对象的遥控器。遥控器具有更多或更少的按钮,具体取决于其类型,对象本身存储在堆中。当我们进行铸造时,我们更改遥控器的类型,但不要改变对象本身。

3.向上转型

从子类到超类的铸造称为扫掠。通常,编译器隐式地执行acccasting。

向上转换与继承密切相关——Java中的另一个核心概念。通常使用引用变量来引用更特定的类型。每次我们这样做的时候,隐含的向上转换就会发生。

为了展示upcasting让我们定义一个动物类:

public class Animal {public void eat(){//…}}

现在让我们延伸动物:

公共类猫延伸动物{public voideat(){// ...} public void meow(){// ...}}

现在我们可以创建一个对象类并将其分配给类型的参考变量:

Cat Cat = new Cat();

我们也可以把它赋值给类型引用变量动物:

动物=猫;

在上面的赋值中,会发生隐式的向上转换。我们可以明确地这样做:

动物=(动物)猫;

但没有必要进行显式投射继承树。编译器知道是一个动物并且不显示任何错误。

注意,该引用可以引用声明类型的任何子类型。

使用浮动,我们已经限制了可用的方法数量实例,但没有改变实例本身。现在我们不能做任何特定的猫 -我们不能调用喵()在这一点动物变量。

虽然对象是对象,调用喵()会导致编译器错误:

/ / animal.meow ();对于动物类型,meow()方法是未定义的

调用喵()我们需要沮丧动物,我们稍后会这样做。

但现在我们将描述给我们发升的原因。由于越来越多,我们可以利用多态性。

3.1。多态性

定义另一个子类动物, 一种类:

公共级狗延长动物{public voideat(){// ...}}

现在我们可以定义喂养()这种方法对待所有的猫和狗就像动物:

公共类动物食物{公共空白饲料(名单<动物>动物){asimes.foreach(动物 - > {Animal.eat();});}}

我们不希望AnimalFeeder关心哪些金宝搏官网188be动物名单上有- a吗或者。在喂养()方法都是动物

对象中添加特定类型的对象时,将发生隐式上转换动物列表:

List animals = new ArrayList<>();动物.ADD(新猫());动物.ADD(新狗());新的AnimalFeeder () .feed(动物);

我们添加猫和狗,他们是俯卧撑动物毫无地键入。每个是一个动物和每一个人是一个动物。他们多态。

顺便说一下,所有Java对象都是多态,因为每个对象都是一个目的至少。我们可以指定一个实例动物到参考变量目的类型和编译器不会报错:

对象对象=新动物();

这就是为什么我们创建的所有Java对象都有目的例如,具体方法,ToString()

向上转换到接口也很常见。

我们可以创建接口,使实施它:

公共界面mew {public void meow();}公共类猫延伸动物实施MEW {public voideat(){// ...} public void meow(){// ...}}

现在对象也可以升高到:

mew mew = new cat();

是A.,上推是合法的,是隐式的。

因此,是A.,动物,目的, 和。在我们的示例中,可以将它赋值给所有四种类型的引用变量。

3.2。压倒一切的

在上面的例子中,吃()覆盖方法。这意味着虽然吃()的变量上调用动物类型,通过在真实对象上调用的方法完成工作 - 猫和狗:

公共空缺饲料(列表<动物>动物){asimes.foreach(动物 - > {Animal.eat();});}

如果我们在类中添加一些日志记录,我们就会看到的年代,的方法被调用:

Web  -  2018-02-15 22:48:49,354 [主要]信息Com.bael金宝搏188体育dung.cesting.cat  - 猫正在吃网站 -  2018-02-15 22:48:49,363 [主要]信息com.baeldung.cesting.dog- 狗正在吃饭

总结:

  • 如果对象与变量相同类型,则引用变量可以指代对象,或者是亚型
  • 向上转型发生隐式
  • 所有的Java对象都是多态的,可以被视为上转换的超类型对象

4.沮丧

如果我们想使用类型的变量,该怎么办?动物调用仅对。可用的方法班级?这是悲伤的。这是从超类到子类的铸造。

让我们举个例子:

动物动物=新猫();

我们知道动物变量是指的。我们想调用s喵()方法动物。但编译器抱怨说喵()方法对于该类型不存在动物

打电话给喵()我们应该沮丧动物:

((Cat)动物).meow ();

内括号及其包含的类型有时被称为强制转换操作符。注意,还需要外部括号来编译代码。

让我们重写上一个AnimalFeeder的例子喵()方法:

公共类动物食物{公共空白饲料(名单<动物>动物){asimal.foreach(动物 - > {Animal.eat();如果(动物案例猫){((猫)动物).meow();}});}}

现在我们可以访问所有可用的方法班级。查看日志以确保喵()其实叫:

Web  -  2018-02-16 18:13:45,445 [主要]信息Com.Bael金宝搏188体育dung.cesting.Cat  - 猫正在吃网站 -  2018-02-16 18:13:45,454 [主要]信息Com.baeldung.cesting.Cat- 喵web  -  2018-02-16 18:13:45,455 [主要]信息Com.baeldung金宝搏188体育.casting.dog  - 狗正在吃

请注意,在上面的例子中,我们试图只向下转换那些真正的实例对象。为此,我们使用运算符instanceof.

4.1。instanceof.操作符

我们经常使用instanceof.操作符来检查对象是否属于特定类型:

if (animal instanceof Cat) {((Cat) animal).喵();}

4.2。classcastException.

如果我们没有检查类型instanceof.操作员,编译器不会抱怨。但在运行时,会有一个例外。

为了证明这让我们删除了instanceof.来自上面代码的操作员:

public void uncheckedFeed(List animals){动物。forEach(animal -> {animal.eat();((Cat)动物).meow ();});}

此代码没有问题编译。但如果我们试图运行它,我们将看到一个例外:

java.lang.ClassCastException: com.金宝搏188体育baeldung.casting.Dog不能被转换为com.金宝搏188体育baeldung.cesting.cat.

这意味着我们试图转换一个对象,它是进入A.实例。

classcastException'如果我们衰落的类型不匹配真实对象的类型,则始终抛出运行时。

注意,如果我们尝试向下转换为不相关的类型,编译器不会允许这样做:

动物的动物;String s = (String) animal;

编译器说“不能从动物施放到字符串”。

对于编译的代码,这两种类型都应该是相同的继承树。

让我们总结一下:

  • 衰退是必要的,以便访问特定于子类的成员
  • 沮丧是使用铸造算子完成的
  • 为了安全地降下一个对象,我们需要instanceof.操作符
  • 如果实际对象与向下转换的类型不匹配,则classcastException.将在运行时抛出

5.投()方法

使用方法来施放对象的另一种方法:

public void whenDowncastToCatWithCastMethod_thenMeowIsCalled(){动物动物=新的猫();if (Cat.class. isinstance (animal)) {Cat Cat = Cat.class.cast(animal);cat.meow ();}}

在上面的例子中,投() 和isInstance ()方法代替强制转换和instanceof.算子相应地。

这很常见投()isInstance ()具有泛型类型的方法。

让我们创建AnimalFeedergeneric 班级喂养()根据类型参数的值,“喂食”只有一种类型的动物 - 猫或狗的方法:

公共类动物反射率为 {私人类类型;公共动物redergeneric(类类型){this.type = type;公共列表 Feed(list <动物>动物){list 列表= new arraylist ();动物返回清单;}}

喂养()方法检查每个动物,并只返回那些是T

请注意,实例也应该传递给泛型类,因为我们不能从类型参数获得它T。在我们的示例中,我们在构造函数中传递它。

让我们做T等于并确保该方法只返回猫:

@Test公共void当ParmeterCat_thenonlycatsfed(){list <动物>动物= new arraylist <>();动物.ADD(新猫());动物.ADD(新狗());AnimalFeedergeneric  Catfeeder = New AnimalFeedergeneric (Cat.Class);列表 fedanimals = catfeeder.feed(动物);asserttrue(fedanimals.size()== 1);asserttrue(fedanimals.get(0)_ _猫);}

六,结论

在这个基础教程中,我们已经探讨了什么是翘曲,悲伤,如何使用它们以及这些概念如何帮助您利用多态性。

与始终一样,本文的代码可用在github上

Java底部

开始使用Spring 5和Spring Boot 2,通过学习春天课程:

>>查看课程
评论在本文上关闭!