Java 中的显式类型转换示例 [英] Explicit type casting example in Java

查看:20
本文介绍了Java 中的显式类型转换示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 http://www.javabeginner.com/learn-java/上遇到过这个例子java-object-typecasting 在它谈到显式类型转换的部分中有一个例子让我感到困惑.

I have come across this example on http://www.javabeginner.com/learn-java/java-object-typecasting and in the part where it talks about explicit type casting there is one example which confuses me.

例子:

class Vehicle {

    String name;
    Vehicle() {
        name = "Vehicle";
    }
}

class HeavyVehicle extends Vehicle {

    HeavyVehicle() {
        name = "HeavyVehicle";
    }
}

class Truck extends HeavyVehicle {

    Truck() {
        name = "Truck";
    }
}

class LightVehicle extends Vehicle {

    LightVehicle() {
        name = "LightVehicle";
    }
}

public class InstanceOfExample {

    static boolean result;
    static HeavyVehicle hV = new HeavyVehicle();
    static Truck T = new Truck();
    static HeavyVehicle hv2 = null;
    public static void main(String[] args) {
        result = hV instanceof HeavyVehicle;
        System.out.print("hV is an HeavyVehicle: " + result + "
");
        result = T instanceof HeavyVehicle;
        System.out.print("T is an HeavyVehicle: " + result + "
");
        result = hV instanceof Truck;
        System.out.print("hV is a Truck: " + result + "
");
        result = hv2 instanceof HeavyVehicle;
        System.out.print("hv2 is an HeavyVehicle: " + result + "
");
        hV = T; //Sucessful Cast form child to parent
        T = (Truck) hV; //Sucessful Explicit Cast form parent to child
    }
}

在最后一行中,T 被分配了引用 hV 并且类型转换为 (Truck),为什么在评论中说这是从父级到子级的成功显式转换?据我所知,强制转换(隐式或显式)只会更改对象的声明类型,而不是实际类型(它永远不会更改,除非您实际将新类实例分配给该对象的字段引用).如果已经为 hv 分配了一个 HeavyVehicle 类的实例,该类是 Truck 类的超类,那么如何将该字段类型转换为从 HeavyVehicle 类扩展的名为 Truck 的更具体的子类?

In the last line where T is assigned the reference hV and typecast as (Truck), why does it say in the comment that this is a Successful Explicit Cast from parent to child? As I understand casting (implicit or explicit) will only change the declared type of object, not the actual type (which shouldn't ever change, unless you actually assign a new class instance to that object's field reference). If hv was already assigned an instance of a HeavyVehicle class which is a super class of the Truck class, how can then this field be type cast into a more specific subclass called Truck which extends from the HeavyVehicle class?

我的理解是,强制转换的目的是限制对对象(类实例)的某些方法的访问.因此,您不能将对象转换为更具体的类,该类具有比对象实际分配的类更多的方法.这意味着该对象只能被转换为超类或与实际实例化它的类相同的类.这是正确的还是我错了?我还在学习,所以我不确定这是否是正确的看待事物的方式.

The way I understand it is that casting serves the purpose of limiting access to certain methods of an object (class instance). Therefore you can't cast an object as a more specific class which has more methods then the object's actual assigned class. That means that the object can only be cast as a superclass or the same class as the class from which it was actually instantiated. Is this correct or am I wrong here? I am still learning so I am not sure if this is the correct way of looking at things.

我也明白这应该是向下转换的一个例子,但是如果实际类型没有这个对象被向下转换到的类的方法,我不确定这实际上是如何工作的.显式转换是否会以某种方式改变对象的实际类型(不仅仅是声明的类型),因此该对象不再是 HeavyVehicle 类的实例,而是现在成为 Truck 类的实例?

I also understand that this should be an example of downcasting, but I am not sure how this actually works if the actual type doesn't have the methods of the class to which this object is being downcasted. Does explicit casting somehow change the actual type of object (not just the declared type), so that this object is no longer an instance of HeavyVehicle class but now becomes an instance of Truck class?

推荐答案

引用 vs 对象 vs 类型

对我来说,关键是理解对象与其引用之间的区别,或者换句话说,就是理解对象与其类型之间的区别.

The key, for me, is understanding the difference between an object and its references, or put in other words the difference between an object and its types.

当我们在 Java 中创建一个对象时,我们声明了它的真实本质,它永远不会改变(例如 new Truck()).但是 Java 中的任何给定对象都可能具有多种类型.其中一些类型显然是由类层次结构给出的,而另一些则不那么明显(即泛型、数组).

When we create an object in Java, we declare its true nature, which will never change (e.g. new Truck()). But any given object in Java is likely to have multiple types. Some of these types are obviously given by the class hierarchy, others are not so obvious (i.e. generics, arrays).

特别是对于引用类型,类层次结构规定了子类型规则.例如,在您的示例中,所有卡车都是重型车辆所有重型车辆都是车辆.因此,这种 is-a 关系的层次结构决定了一辆卡车具有多种兼容类型.

Specifically for reference types, the class hierarchy dictates the subtyping rules. For instance in your example all trucks are heavy vehicles, and all heavy vehicles are vehicles. Therefore, this hierarchy of is-a relationships dictates that a truck has multiple compatible types.

当我们创建一个 Truck 时,我们定义了一个引用";访问它.此引用必须具有这些兼容类型之一.

When we create a Truck, we define a "reference" to get access to it. This reference must have one of those compatible types.

Truck t = new Truck(); //or
HeavyVehicle hv = new Truck(); //or
Vehicle h = new Truck() //or
Object o = new Truck();

所以这里的关键是要认识到对对象的引用不是对象本身.正在创建的对象的性质永远不会改变.但是我们可以使用不同类型的兼容引用来访问对象.这是这里多态的特点之一.可以通过不同兼容"对象的引用访问同一对象.类型.

So the key point here is the realization that the reference to the object is not the object itself. The nature of the object being created is never going to change. But we can use different kinds of compatible references to gain access to the object. This is one of the features of polymorphism here. The same object may be accessed through references of different "compatible" types.

当我们进行任何类型的转换时,我们只是假设不同类型引用之间的这种兼容性的性质.

When we do any kind of casting, we are simply assuming the nature of this compatibility between different types of references.

向上或扩大参考转换

现在,有了 Truck 类型的引用,我们可以很容易地得出结论,它始终与 Vehicle 类型的引用兼容,因为所有卡车都是车辆.因此,我们可以向上转换引用,而无需使用显式转换.

Now, having a reference of type Truck, we can easily conclude that it's always compatible with a reference of type Vehicle, because all Trucks are Vehicles. Therefore, we could upcast the reference, without using an explicit cast.

Truck t = new Truck();
Vehicle v = t;

它也被称为 扩大引用转换,基本上是因为随着类型层次结构的上升,类型变得更通用.

It is also called a widening reference conversion, basically because as you go up in the type hierarchy, the type gets more general.

如果需要,您可以在此处使用显式强制转换,但这是不必要的.我们可以看到 tv 引用的实际对象是相同的.它是,并且永远是卡车.

You could use an explicit cast here if you wanted, but it would be unnecessary. We can see that the actual object being referenced by t and v is the same. It is, and will always be a Truck.

向下转换或缩小参考转换

现在,有了 Vechicle 类型的引用,我们不能安全地"得出结论,它实际上引用了 Truck.毕竟它也可能引用某种其他形式的 Vehicle.例如

Now, having a reference of type Vechicle we cannot "safely" conclude that it actually references a Truck. After all it may also reference some other form of Vehicle. For instance

Vehicle v = new Sedan(); //a light vehicle

如果您在代码中的某处发现 v 引用而不知道它引用的是哪个特定对象,则您无法安全地"争论它是否指向 TruckSedan 或任何其他类型的车辆.

If you find the v reference somewhere in your code without knowing to which specific object it is referencing, you cannot "safely" argument whether it points to a Truck or to a Sedan or any other kind of vehicle.

编译器很清楚它不能保证所引用对象的真实性质.但是程序员通过阅读代码,可以确定他/她在做什么.和上面的例子一样,你可以清楚地看到 Vehicle v 引用了一个 Sedan.

The compiler knows well that it cannot give any guarantees about the true nature of the object being referenced. But the programmer, by reading the code, may be sure of what s/he is doing. Like in the case above, you can clearly see that Vehicle v is referencing a Sedan.

在这些情况下,我们可以做一个低头.我们这样称呼它是因为我们要沿着类型层次结构向下移动.我们也称之为缩小参考转换.我们可以说

In those cases, we can do a downcast. We call it that way because we are going down the type hierarchy. We also call this a narrowing reference conversion. We could say

Sedan s = (Sedan) v;

这总是需要显式转换,因为编译器不能确定这是安全的,这就是为什么这就像问程序员,你确定你在做什么吗?".如果你对编译器撒谎,你会在运行时抛出一个 ClassCastException,当这段代码被执行时.

This always requires an explicit cast, because the compiler cannot be sure this is safe and that's why this is like asking the programmer, "are you sure of what you are doing?". If you lie to the compiler you will throw you a ClassCastException at run time, when this code is executed.

其他类型的子类型规则

Java 中还有其他子类型规则.例如,还有一个称为数字提升的概念,它可以自动强制表达式中的数字.喜欢在

There are other rules of subtyping in Java. For instance, there is also a concept called numeric promotion that automatically coerce numbers in expressions. Like in

double d = 5 + 6.0;

在这种情况下,由两个不同类型(整数和双精度)组成的表达式在计算表达式之前将整数向上转换/强制转换为双精度,从而得到双精度值.

In this case an expression composed of two different types, integer and double, upcasts/coerces the integer to a double before evaluating the expression, resulting in a double value.

您也可以进行原始的向上转换和向下转换.如在

You may also do primitive upcasting and downcasting. As in

int a = 10;
double b = a; //upcasting
int c = (int) b; //downcasting

在这些情况下,当信息可能丢失时需要显式转换.

In these cases, an explicit cast is required when information can be lost.

某些子类型规则可能不那么明显,例如在数组的情况下.例如,所有引用数组都是 Object[] 的子类型,但原始数组不是.

Some subtyping rules may not be so evident, like in the cases of arrays. For instance, all reference arrays are subtypes of Object[], but primitive arrays are not.

在泛型的情况下,特别是使用像 superextends 这样的通配符时,事情变得更加复杂.喜欢在

And in the case of generics, particularly with the use of wildcards like super and extends, things get even more complicated. Like in

List<Integer> a = new ArrayList<>();
List<? extends Number> b = a;
        
List<Object> c = new ArrayList<>(); 
List<? super Number> d = c;

其中b 的类型是a 类型的子类型.而d的类型是c的类型的子类型.

Where the type of b is a subtype of the type of a. And the type of d is a subtype of the type of c.

而且装箱和拆箱也受制于一些铸造规则(但在我看来,这也是某种形式的强制).

And also boxing and unboxing are subject to some casting rules (yet again this is also some form of coercion in my opinion).

这篇关于Java 中的显式类型转换示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆