【问题标题】:Cannot access an Object Reference instantiated by a sibling class无法访问由同级类实例化的对象引用
【发布时间】:2015-04-02 05:29:02
【问题描述】:

我有一个抽象类,它声明了许多对象引用,特别是一个 JLabel。我有两个类都扩展了该类。其中一个孩子实例化了 JLabel 并调用了它的几个方法。该类兄弟尝试调用 JLabel 上的 setText 方法,我得到一个 NullPointerException(实例化它的兄弟在另一个之前调用。)

我曾认为所有孩子都引用内存中的同一个对象,因此会修改同一个对象,但显然我错了。我该如何解决这个问题?

这是我的意思的一个例子:

public class BlahDriver 
{
    public static void main(String[] args) 
    {
        BlahChildOne blah = new BlahChildOne();
        BlahChildTwo blah2 = new BlahChildTwo();
    }
}
public abstract class Blah 
{
    protected JLabel label;
}
public class BlahChildOne extends Blah
{
    public BlahChildOne()
    {
        label = new JLabel();
    }
}
public class BlahChildTwo extends Blah
{
    public BlahChildTwo()
    {
        label.setText("Fred");
    }
}

尝试 setText 时,我在 BlahChildTwo 处收到 NullPointerException。

【问题讨论】:

  • 似乎没有必要显示任何代码,因为这是一个概念性问题,但我想我可以写一些
  • 代码是必要的,因为new 的使用决定了如何在堆上创建对象。你如何做你所说的你所做的会有很大的不同。
  • BlahChildTwo 调用 Blah 的构造函数,它从不实例化 JLabel。这意味着当您说label.setText() 时,label 为空。 “我以为所有的孩子都在内存中引用同一个对象”是错误的。

标签: java inheritance nullpointerexception abstract-class


【解决方案1】:

所以,blah 定义了一个名为 label 的实例字段,但没有对其进行初始化

public abstract class Blah 
{
    protected JLabel label;
}

BlahChildOneBlah 初始化 label

public class BlahChildOne extends Blah
{
    public BlahChildOne()
    {
        label = new JLabel();
    }
}

BlahChildTwo 没有从Blah 初始化label,所以它仍然是null...

public class BlahChildTwo extends Blah
{
    public BlahChildTwo()
    {
        label.setText("Fred");
    }
}

BlahChildOneBlahChildTwo 在它们之间都不共享信息(它们通过从Blah 继承而具有共性,但实际信息是各自拥有的)。

把它想象成同卵双胞胎,他们可能有共同点,但仅仅因为一个生病,并不意味着另一个会,他们是自己独立的实例。

如果您想在班级之间共享信息,则应考虑提供对班级的引用以及您要共享的信息,例如...

public class BlahChildTwo extends Blah
{
    public BlahChildTwo(Blah blah)
    {
        label = blah.label;
        label.setText("Fred");
    }
}

但我真的很想看到一个如此激烈的用例......

为什么static 被认为是不好的

假设...

public abstract class Blah 
{
    protected static JLabel label;
}

现在在您的代码中,您可以执行类似...

BlahChildOne bco = new BlahChildOne();
add(bco.label); // It the label to the screen...
BlahChildTwo bct = new BlahChildTwo();

好的,到目前为止,一切都很好。现在想象一下,在您的代码中的其他地方,您确实...

BlahChildOne bco = new BlahChildOne();
BlahChildTwo bct = new BlahChildTwo();

...但是为什么屏幕没有更新?因为Blah#label 不再指向您之前添加到屏幕的JLabel,所以您丢失了该引用。

这在调试器中很难找到,即使您知道要查找的内容,因为没有责任,任何扩展 Blah 的类都可以创建 JLabel 的新实例并将其分配给 @987654344 @。

【讨论】:

  • 感谢您的出色回答和所有信息。如果在第二次创建新的 bco 和 bct 对象之后执行“add(bco.label);”会怎样?再次,它会工作吗?不是说这是最好的做事方式,但它会奏效吗?
  • @Khaines0625 前提是您知道先删除前一个实例。再次,这里的问题是问责制,您无法控制谁可能(意外或以其他方式)更改对label的引用...
  • @MadProgrammer - 强项。说得通。我不应该只是盲目地建议“静态”,对吧? :-)
【解决方案2】:

朋友,你一定是object oriented programming的新手。

类是对象的模板。当您实例化一个类(即new Child())时,会在堆上分配内存以存储该对象的实例变量。包含对象变量的内存仅用于该对象。每次创建对象时,它在单独的内存空间中都有自己的实例变量。

【讨论】:

  • 好吧,我了解到多个对象引用可以指向内存中的同一个空间,但对于继承来说还是很新的,所以我不确定它是如何工作的。我才上第二学期的课。
【解决方案3】:

这一行protected JLabel label; 不创建 Object ,它只是引用变量,所以当两个类都扩展时 Abstract class 。两个类都有自己独立的引用变量副本

BlahChildTwo 有他自己的 JLabel 引用变量副本,它没有被实例化,这就是你面临NullPointerException

的原因

现在来回答你的问题

I had thought that all children refer to the same object in memory and wouldthus modify the same object but apparently I'm wrong. How can I getaround this?

是的,如果这是一个对象而不是引用变量

,那么所有的孩子都会引用同一个对象

【讨论】:

    【解决方案4】:

    所有孩子都引用同一个对象。每个子对象都将是一个新对象,它将拥有在父对象中声明的所有引用的自己的副本以及在其自身中声明的所有引用的副本。

    如果您想在类之间访问相同的引用,请尝试在父类中设置为static

    【讨论】:

    • @Khaines0625 考虑到您不知道static 关键字的实际作用,请注意副作用。
    • 不,不要使用静态!显然,两个子类都从 Blah 扩展,label 将是 null,除非它被初始化......
    • 真的,@MadProgrammer。他需要确保始终首先调用初始化静态引用的函数。
    • 将其设为静态意味着 JLabel 对象在某种程度上是在所有子类之间共享的,对吗?我对 JLabel 所做的任何更改都会在所有孩子中看到吗?这就是我需要的。
    • 这是个人的挑剔:static 很危险,尤其是在基于 UI 的环境中(我猜它可以在任何地方造成同样多的混乱)。如果确实需要共享信息,请将第一类的引用传递给第二类,然后您可以获得对标签的引用并在那里进行您需要的修改......但这让我想知道为什么第二类需要从Blah 扩展,但这可能是未共享的实现细节
    猜你喜欢
    • 2023-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    相关资源
    最近更新 更多