对封闭 class 实例的内部 class 引用为空

Inner class reference to enclosing class instance is null

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

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 
        }
    }
}

在其他 class 中,我遍历了 Outer 实例的项目并调用 getInnerX() 给每个项目:

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

A NullPointerException 被扔进 getInnerX() 因为 Outer.thisnull.

我不知道怎么会这样。

编辑:

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

我正在使用 retrofit2 并且 Outer 对象是根据来自服务器的 json 响应创建的。

Outer 的项目属性具有 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)

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

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

最简单的解决方案是更改设计,摆脱内部 class(es)。或者,您可以注册并使用自定义解串器。下面的帖子中有示例。

相关帖子:

  • GSON does not deserialize reference to outer class
  • Is default no-args constructor mandatory for Gson?