【问题标题】:Inner class reference to enclosing class instance is null对封闭类实例的内部类引用为空
【发布时间】:2016-04-27 23:07:36
【问题描述】:

我有一个类,它有一个内部类和一个内部实例的集合:

public class Outer {

    private List<Inner> items = new ArrayList<Inner>(); 

    ... 

    public List<Inner> getItems(){
        return this.items;
    }

    public int getOuterX() {
        ...
    }
    ...

    public class Inner {
        ... 
        public int getInnerX(){     
            return Outer.this.getOuterX(); // this line throws the exception 
        }
    }
}

在其他类中,我遍历 Outer 实例的项目并为每个项目调用 getInnerX()

for (Outer.Inner item : outer.getItems()) {
    item.getInnerX();
}

NullPointerException 被抛出到 getInnerX() 中,因为 Outer.thisnull

我不知道这是怎么发生的。

编辑:

我正在准备@Sotirios Delimanolis 要求的示例,但我无法重现该错误。 所以这是我没有包括在问题中的东西。

我正在使用retrofit2Outer 对象是基于来自服务器的json 响应创建的。

Outer 的 item 属性有 GSon 转换器的注解:

@SerializedName("items")
@Expose
private List<Inner> items = new ArrayList<Inner>(); 

Outer 没有定义构造函数,Inner 也没有。

这是堆栈跟踪:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String 
com.example.server_comunication.datatypes.OrderResponse$Order.getStatus()' on a null object reference
      at com.example.server_comunication.datatypes.OrderResponse$Order$Supply.forPlacement(OrderResponse.java:408)
      at com.example.server_comunication.datatypes.OrderResponse$Order$Supply.getRemaining(OrderResponse.java:423)
      at com.example.uiHelpers.UIFactoryPanels.drawPanelSuppliesEditor(UIFactoryPanels.java:142)
      at com.example.OrderFragment.onCreateView(OrderFragment.java:85)
      at android.app.Fragment.performCreateView(Fragment.java:2053)
      at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:894)
      at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
      at android.app.BackStackRecord.run(BackStackRecord.java:833)
      at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1452)
      at android.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:483)
      at android.support.v13.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:145)
      at android.support.v4.view.ViewPager.populate(ViewPager.java:1177)
      at android.support.v4.view.ViewPager.populate(ViewPager.java:1025)
      at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1545)
      at android.view.View.measure(View.java:17430)
      at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:727)
      at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:463)
      at android.view.View.measure(View.java:17430)
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5463)
      at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:668)
      at android.support.design.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:735)
      at android.view.View.measure(View.java:17430)
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5463)
      at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
      at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
      at android.view.View.measure(View.java:17430)
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5463)
      at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
      at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)
      at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)
      at android.view.View.measure(View.java:17430)
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5463)
      at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
      at android.view.View.measure(View.java:17430)
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5463)
      at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436)
      at android.widget.LinearLayout.measureVertical(LinearLayout.java:722)
      at android.widget.LinearLayout.onMeasure(LinearLayout.java:613)
      at android.view.View.measure(View.java:17430)
      at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5463)
      at android.widget.FrameLayout.onMeasure(FrameLayout.java:430)
      at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2560)
      at android.view.View.measure(View.java:17430)
      at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2001)
      at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1166)
      at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1372)
      at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1054)
      at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5779)
      at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
      at android.view.Choreographer.doCallbacks(Choreographer.java:580)
      at android.view.Choreographer.doFrame(Choreographer.java:550)
      at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)

【问题讨论】:

  • @daniel 我认为android 是相关的。这在没有字节码操作的普通 Java 中是不可能的。 Android中的某些东西可能会导致这种情况。巴勃罗,你能提供一个minimal reproducible example吗?
  • @SotiriosDelimanolis 好点,回滚。
  • @SotiriosDelimanolis,我正在研究这个例子。就像我发布的一样,我无法重现错误(我简化了太多),所以我正在添加相关的新信息。谢谢。
  • 可能OuterClass.this 是无辜的,NPE 发生在getOuterX() 内部?
  • 请提供堆栈跟踪,以便我们停止猜测。将其编辑到您的问题中。

标签: java android nullpointerexception inner-classes gson


【解决方案1】:

Retrofit 使用 Gson 和 Gson 秘籍。 (在撰写本文时)它使用sun.misc.Unsafe 类以allocateInstance 实例化您的类。这完全跳过了任何构造函数。

对于内部类,any declared constructor will implicitly declare its first parameter as the enclosing type to represent the enclosing class' instance。 Gson 无法创建该封闭类的实例,但即使创建了,也没关系。 Gson 完全跳过构造函数,将隐含的 Outer.this 引用保留为 null

最简单的解决方案是更改您的设计,摆脱内部类。或者,您可以注册并使用自定义反序列化程序。下面的帖子中有示例。

相关帖子:

【讨论】:

  • 非常感谢。我使用内部类来匹配来自服务器的 json 结构数据。我会像你说的那样改变我的设计。
猜你喜欢
  • 1970-01-01
  • 2015-05-21
  • 2012-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多