为什么要使用对象来实例化一个类?Java

3

我正在为Java SE7认证复习,做过这些考试的人都知道它们使用的一些代码示例有多么荒谬。故意编写难以理解的代码。 最近我看到很多像这样编写的代码:

Object obj=new Animal();

这有什么好处呢?我知道这是有效的代码,但这是否只是像考试中很多代码一样永远不会使用的东西?如果不是,那么何时以及为什么会这样做呢?

5
你会使用这样的代码的唯一原因是为了展示Java中的多态性。在任何实际应用中,使用这样的代码需要进行大量的类型转换。 - npinti
这不是一个真实世界中的模式(或者在非常罕见的情况下)。它取决于该行之后的内容。比如我们看到一个 obj.toString(),输出会是什么?毕竟这是一道考试题,用来检查某人是否理解了相关概念。 - PeterMmm
1
这是针对只涉及对象方面的情况而言的。例如将对象序列化(存储)到磁盘上等操作。在 List<String> list = new ArrayList<>(); 这个例子中,根据契约来看,它是很有意义的,而不是从实现角度出发。 - Joop Eggen
或者是反编译器的输出?如果剩下的所有obj用法只是作为方法参数,无论如何都会被强制转换为对象(例如作为Hashtable值传递)。 - Gus
同时,在实际代码中,你经常会看到像 List x = new ArrayList(); 这样的东西,这样你就不需要在整个类中传递特定的实现类型。类似的概念也适用,可能是因为考试代码没有使用更复杂的层次结构,所以更简单易懂。 - Artur Biesiadowski
这是一份多项选择测试,其中包含关于奇怪代码的奇怪问题,测试您对语言边缘情况的了解。意图并不是让您从这些代码中学习。 - zapl
4个回答

5

这说明ObjectAnimal的基类(父类)。

换句话说,即使你没有写下

public class Animal extends Object {
}

编译器增加了“extends Object”,因为所有类都扩展了Object
这适用于Java语言中的所有类,虽然这个例子在教学目的上不是很好,但在某些方面上,这是一个一般的测试你是否理解了这样的概念。很可能你不会在常规开发中使用此技术。

1
请注意,您并没有真正使用 Object 进行实例化,而是将 Animal 的引用作为 Object 进行捕获。也许您已经知道了这一点,只是表述不够清晰。 - Edwin Buck

2
这并不是无用的东西。它展示了Java类型系统允许您在类型为Object的变量中存储任何对象,而不仅仅是使用new Object()直接实例化的对象,这是最简单的可以证明它的例子。
每个对象都是Object类的子类。它演示了当您声明一个变量的类型为某种类型时,您可以将其放置在那里,不仅仅是该确切类型(例如您的示例中的Object),还可以是任何子类型(例如您的示例中的Animal)。
虽然使用所有对象的基类可能似乎没有用处,但更复杂的类层次结构可能会更好地证明它。
假设您有更多的Animal子类:DogCatHamster。现在假设您还有许多DogCatHamster的子类(如果有任何不同种类的仓鼠)。
public class Animal { // implicitly extends Object
    // ...
}
public class Dog extends Animal {
    // ...
}
public class Cat extends Animal {
    // ...
}
public class Hamster extends Animal {
    // ...
}
public class Hamster extends Animal {
    // ...
}
Labrador extends Dog {
    // ...
}
// etc.

现在,如果你想把一个Animal存储到变量中,你可以这样写:
Animal animal = new Cat();

或者:

Animal animal = new Labrador();

现在,来自您问题的确切代码:
Object obj = new Animal();

可以在几个不同的方面发挥作用:

如果您想确保使用 Object 类公开的接口而不是继承链中后来添加的内容。

您也可以拥有例如 5 只狗的数组:

Dog[] dogs = new Dogs[5];

这里可以放置狗,但不能放置猫或仓鼠。

您可以拥有一个动物数组,可以放置任何动物,但不能放置其他对象,例如数字:

Animal[] animals = new Animals[5];

为什么要有这样的数组呢?举个例子,如果你的Animal类有一个getName方法,那么你就可以随时运行:

animals[2].getName();

无论有哪种动物都可以。但是如果 Dog 类有一个方法 bark(),而 Cat 类没有它,那么你将无法运行:

animals[2].bark();

即使在animals数组的该索引下确实存储了一个Dog实例,也需要进行显式转换才能调用它的方法,因为编译器不知道运行时该数组中会有什么 - 它只能保证那里会有一些动物,所以你只能调用对于所有动物都适用的方法。

这可能听起来很愚蠢,但你会发现它确实在许多地方使用。例如,在GUI编程中,您可以拥有一个滚动面板,在其中可以放置任何组件,如按钮或文本字段,但不能放置任何对象,这正是由该机制保证的 - 例如,JPanel对象具有一个add()方法,它接受Component类的组件,但这些组件不必使用new Component()创建,而可以是例如JLabel或另一个JPanel。


1
我不明白这个回答如何解决问题。如果使用Object[],也许我可以发挥想象力,但在目前的形式下,它实际上并没有真正回答问题。 - Polygnome
我同意Polygnome所说的,问题明确说明了为什么示例要转换为Object,而不是转换的原理或用途。 - tringel
@Polygnome,感谢您的评论。我已经更新了我的答案。 - rsp
@tringel 很好的建议。我更新了我的答案,使其更加清晰。如果您有更多建议,请告诉我。谢谢。 - rsp

1

这基本上是动态绑定.. Object obj = new Animal(); 这意味着您正在为Animal类创建对象,并将其地址存储在引用变量obj中.. Object obj表示您只能通过animal类对象访问对象类的函数.... 让我们通过一个小程序来理解

class Object
{
    void fun()
    {
        System.out.println("hello");
    }
}

class Animal extends Object
{
    void fun1()
    {
        System.out.println("hi");
    }

    public static void main(String args[])
    {
        Object obj = new Animal();
        obj.fun();
    }
}

输出-你好


0

如果使用obj变量不依赖于它是一个Animal,那么这将非常有用。例如,假设您将新对象传递给使用toString()打印它的函数。那么obj的确切类别并不重要,代码说明了这一点。


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