我对在Java中强制转换对象的含义感到困惑。
假设你有...
Superclass variable = new Subclass object();
(Superclass variable).method();
这里发生了什么?变量类型改变了,还是变量内的对象发生了变化?非常困惑。
可以看一下这个示例:
public class A {
//statements
}
public class B extends A {
public void foo() { }
}
A a=new B();
//To execute **foo()** method.
((B)a).foo();
假设你有一个父类 Fruit 和子类 Banana,并且你有一个方法 addBananaToBasket()。
该方法不会接受例如葡萄等其他水果,所以您需要确保将香蕉添加到篮子中。
因此:
Fruit myFruit = new Banana();
((Banana)myFruit).addBananaToBasket();
⇐ 这就是所谓的类型转换(casting)
你所提到的例子在Java中被称为向上转型。
它创建一个具有指向其的超类变量的子类对象。
变量不会改变,它仍然是超类的变量,但是它指向子类的对象。
例如,假设你有两个类Machine和Camera; Camera是Machine的子类。
class Machine{
public void start(){
System.out.println("Machine Started");
}
}
class Camera extends Machine{
public void start(){
System.out.println("Camera Started");
}
public void snap(){
System.out.println("Photo taken");
}
}
Machine machine1 = new Camera();
machine1.start();
如果您执行上述语句,它将创建一个Camera类的实例,并使用指向它的Machine类引用。所以,现在的输出将是“Camera Started”。
这里的要点是所有的相机都是机器,因为Camera是Machine的子类,但并非所有Machines都是Cameras。因此,您可以创建一个子类对象,并将其指向超类引用,但您不能要求超类引用执行子类对象的所有函数(在我们的示例中machine1.snap()
无法编译)。超类引用仅能访问已知于超类的函数(在我们的示例中machine1.start()
)。您无法要求机器引用拍摄快照。:)
abstract class Animal{
public abstract void move();
}
class Shark extends Animal{
public void move(){
swim();
}
public void swim(){}
public void bite(){}
}
class Dog extends Animal{
public void move(){
run();
}
public void run(){}
public void bark(){}
}
...
void somethingSpecific(Animal animal){
// Here you don't know and may don't care which animal enters
animal.move(); // You can call parent methods but you can't call bark or bite.
if(animal instanceof Shark){
Shark shark = (Shark)animal;
shark.bite(); // Now you can call bite!
}
//doSomethingSharky(animal); // You cannot call this method.
}
...
void doSomethingSharky(Shark shark){
//Here you cannot receive an Animal reference
}
这个方法只能通过传递鲨鱼引用来调用。因此,如果您有一个动物(且它深层次上是一只鲨鱼),您可以像这样调用它:
Animal animal...
doSomethingSharky((Shark) animal)
底线是,当你不关心父对象的实现时,你可以使用父引用,并使用转型将Child用作特定对象时,通常更好。它将是完全相同的对象,但是您的引用知道它,如果您不对其进行转换,则您的引用将指向相同的对象,但无法确定它将是什么类型的Animal,因此只允许您调用已知的方法。
超类变量 = 新的子类对象();
这只是创建了一个子类类型的对象,但将其分配给超类类型。所有子类的数据都被创建等等,但变量不能访问子类的数据/函数。换句话说,您无法调用任何特定于子类的方法或访问数据,只能访问超类的内容。
然而,您可以将超类变量转换为子类,并使用其方法/数据。
public class A {
public void printFromA(){
System.out.println("Inside A");
}
}
public class B extends A {
public void printFromB(){
System.out.println("Inside B");
}
}
public class MainClass {
public static void main(String []args){
A a = new B();
a.printFromA(); //this can be called without typecasting
((B)a).printFromB(); //the method printFromB needs to be typecast
}
}
class Animal{
public void walk(){
}
}
class Cat extends Animal{
@Override
public void walk(){
}
public void speak(){
}
public void main(String args[]){
Animal a=new Cat();
//a.speak(); Compile Error
// If you use speak method for "a" reference variable you should downcast. Like this:
((Cat)a).speak();
}
}
强制类型转换是必要的,以便告诉编译器你正在调用子类而不是父类方法。因此,它总是向下转型。但是,如果该方法已经在父类中定义并在子类中重写,则不需要进行任何转换。以下是一个例子:
class Parent{
void method(){ System.out.print("this is the parent"); }
}
class Child extends Parent{
@override
void method(){ System.out.print("this is the child"); }
}
...
Parent o = new Child();
o.method();
((Child)o).method();
((Subclass) variable).method()
。这将把variable
强制转换为Subclass
(这是一个安全的类型转换),然后在其上执行method()
,假设method()
是在Superclass
中未定义的方法。 - Melv