Java中的对象转换

61

我对在Java中强制转换对象的含义感到困惑。

假设你有...

Superclass variable = new Subclass object();
(Superclass variable).method();

这里发生了什么?变量类型改变了,还是变量内的对象发生了变化?非常困惑。


1
请提供一个实际的例子。在这种情况下,我很难理解你在说什么。 - Joe Phillips
7
你发布的不是有效的Java代码。我认为你的意思是 ((Subclass) variable).method()。这将把variable强制转换为Subclass(这是一个安全的类型转换),然后在其上执行method(),假设method()是在Superclass中未定义的方法。 - Melv
10个回答

84

可以看一下这个示例:

public class A {
  //statements
}

public class B extends A {
  public void foo() { }
}

A a=new B();

//To execute **foo()** method.

((B)a).foo();

6
谢谢。所以,最初你不能访问子类中的方法,因为你只能使用超类的方法。如果我理解正确,你将变量强制转换为子类类型,以便可以访问其内容? - user658168
@AVD 如果方法foo()被覆盖了怎么办?你还需要进行强制类型转换吗? - Atieh
@Atieh - 不是的。这个问题是关于类型转换的。 - KV Prajapati
这是最不正确的答案,该告诉我们如何做。 - TheExorcist

55

假设你有一个父类 Fruit 和子类 Banana,并且你有一个方法 addBananaToBasket()。

该方法不会接受例如葡萄等其他水果,所以您需要确保将香蕉添加到篮子中。

因此:

Fruit myFruit = new Banana();
((Banana)myFruit).addBananaToBasket(); ⇐ 这就是所谓的类型转换(casting)


16

你所提到的例子在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())。您无法要求机器引用拍摄快照。:)


而且,调用 machine1.start() 将调用 Camera.start(),因为调用 new Camera() 覆盖了 Machine 的 start() 方法。 - Shane Sepac

7
有时您可能希望接收一个父引用作为参数,而在内部您可能想要执行特定于子项的操作。
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.
}

...

在上述方法中,您可以传递Shark或Dog,但是如果您有以下情况怎么办:
void doSomethingSharky(Shark shark){
 //Here you cannot receive an Animal reference
}

这个方法只能通过传递鲨鱼引用来调用。因此,如果您有一个动物(且它深层次上是一只鲨鱼),您可以像这样调用它:

Animal animal...
doSomethingSharky((Shark) animal)

底线是,当你不关心父对象的实现时,你可以使用父引用,并使用转型将Child用作特定对象时,通常更好。它将是完全相同的对象,但是您的引用知道它,如果您不对其进行转换,则您的引用将指向相同的对象,但无法确定它将是什么类型的Animal,因此只允许您调用已知的方法。


2
这是一个很好的解释,似乎没有引起任何关注? - Mike Williamson

6

超类变量 = 新的子类对象();
这只是创建了一个子类类型的对象,但将其分配给超类类型。所有子类的数据都被创建等等,但变量不能访问子类的数据/函数。换句话说,您无法调用任何特定于子类的方法或访问数据,只能访问超类的内容。

然而,您可以将超类变量转换为子类,并使用其方法/数据。


3
子类可以重写超类的函数,这样可以访问其数据/函数。 - Melv

4
假设你有一个超类 Class A 和一个子类 Class B。
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 
    }
}

2
在这个例子中,你的超类变量告诉子类对象去实现超类的方法。这是Java对象类型转换的情况。在这里,method()函数最初是超类的方法,但是超类变量无法访问子类对象中不存在于超类中的其他方法。

2
例如,您有一个动物超类和猫子类。假设您的子类拥有speak()方法。
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();
  }

}

他们为什么不直接写成 "Cat a = new Cat()" 呢? - john k

1
在某些情况下,我们无法为集合或智能对象中存在的元素或对象提供保证, 在检索时必须执行类型转换,否则会出现编译时错误。
数组始终是类型安全的,即我们可以保证数组中存在的元素的类型。 为了实现类型安全,我们必须使用类型转换。

-2

强制类型转换是必要的,以便告诉编译器你正在调用子类而不是父类方法。因此,它总是向下转型。但是,如果该方法已经在父类中定义并在子类中重写,则不需要进行任何转换。以下是一个例子:

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();  

这两个方法调用都会打印出:"这是子类"。

2
不是用Java的话,你做不到。-1 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接