java - 内联初始化的最终成员变量不知何故为空

标签 java android member final

我的 Conversation 类中有以下代码:

private ConversationListener conversationListener = null;
private final Integer conversationListenerLock = 0;

public ConversationListener getConversationListener() {
    synchronized (conversationListenerLock) {
        return conversationListener;
    }
}

我现在有时会遇到以下异常:

java.lang.NullPointerException: Null reference used for synchronization (monitor-enter)
    at com.mobileoct.shared.data.Conversation.getConversationListener(Conversation.java:283)
    at com.mobileoct.android.colposcope.main.ConversationManager.loadConversationsForUser(ConversationManager.java:260)
    at com.mobileoct.android.colposcope.main.ConversationManager$1.run(ConversationManager.java:305)
    at android.os.Handler.handleCallback(Handler.java:739)                                    
    at android.os.Handler.dispatchMessage(Handler.java:95)                                    
    at android.os.Looper.loop(Looper.java:148)                                                
    at android.os.HandlerThread.run(HandlerThread.java:61)                                    

看来,不知何故conversationListenerLocknull。怎么可能呢?我如何在没有初始化 conversationListenerLock 值的情况下进入 Conversation 类的这个公共(public)的、非静态 方法? 我该如何解决才能避免这种情况发生?

(从堆栈跟踪可以清楚地看出,这是在 Android 上运行的,因此似乎是某个不确定的 Java 版本,非常接近 Java 7.something。)


编辑:回应评论中的一些问题:

我在运行 Android 6.0.1 的三星 Galaxy J5 (SM-J500H) 上运行此程序。 (我还没有在其他设备上运行它,但这是主要目标设备,所以这无关紧要)。

这个类的唯一构造函数是:

public Conversation(String sessionId, String name, String ownerId, String userId) {
    dataType = DATA_TYPE;
    this.setId(UUID.randomUUID().toString());
    this.setSessionId(sessionId);
    this.setName(name);
    this.setOwnerId(ownerId);
    this.setUserId(userId);
}

但是,这个类有时会被 Gson 实例化,如:

Conversation conversation = new GsonBuilder().create().fromJson(jsonString, Conversation.class);

(在 new GsonBuilder().create() 之间还有更多内容,但我很确定它不相关。)

我对不安全的出版了解不多,不知道这是否符合要求,但这似乎是一个可能的罪魁祸首。


编辑 #2 - 这里是“所有直接和间接从 ctor 调用的代码,以及所有其他字段的初始化程序”(一些从父类复制):

public static final String DATA_TYPE = "conversation";
private static final Class<?> s_postServlet = AddConversation.class;

protected String id;
private String sessionId;
private String name;
private String ownerId; // the user that created the conversation
private Boolean deleted = false;
private Date lastUpdated = new Date();
private User user;
private User owner;
private Session session;
private SortedSet<Collaborator> collaborators = new TreeSet<>();
private SortedSet<Message> messages = new TreeSet<>();
private Set<Notification> notifications = new HashSet<>();
private ConversationListener conversationListener = null;
private final Object conversationListenerLock = new Object();

// From parent class
protected String dataType;
protected Date timestamp = new Date();
protected String userId;


public Conversation(String sessionId, String name, String ownerId, String userId) {
    dataType = DATA_TYPE;
    this.setId(UUID.randomUUID().toString());
    this.setSessionId(sessionId);
    this.setName(name);
    this.setOwnerId(ownerId);
    this.setUserId(userId);
}

public void setId(String id) {
    this.id = id;
}

public void setSessionId(String sessionId) {
    this.sessionId = sessionId;
}

public void setName(String name) {
    this.name = name;
}

public void setOwnerId(String ownerId) {
    this.ownerId = ownerId;
}

// From parent class
public void setUserId(String userId) {
    this.userId = userId;
}

最佳答案

您永远不应该在 Java 中对整数进行同步。

由于您已将 Integer 设置为 0,conversationListenerLock 必须 引用缓存的 Integer 之一s,因为它在 -128 到 +127 的范围内。试图获得它的显示器是一个特别糟糕的主意。该对象不属于您,仅属于引用

(我建议您的 Java 平台正在显示诊断错误,以尝试处理您提出的问题,我认为这相当于您的 JVM 中的错误。)

根据经验,不要尝试在 Java 中Integer同步:JVM 保留缓存的权利任何 Integer 值;不仅仅是我已经说明的最小范围。

最简单的解决方法是编写

private final Object conversationListenerLock = new java.lang.Object();

关于java - 内联初始化的最终成员变量不知何故为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44823086/

相关文章:

java - 如何自动使用类的名称?

java - 如何以编程方式设置 TextView 的样式?

java - 私有(private)数据成员在某处神秘地改变(变空)

java - 在 eclipse 插件中使用 SWT

java - 通过 Web 服务将文件从 java 发送到 .net

java - 查找数组中可能存在的最大差异,其中较小的整数较早出现

c++ - 声明抽象类型的字段?更喜欢指针还是引用?

android camera2 handle 缩放

android - 旋转后重新创建 ViewModel;如果直接用 dagger2 注入(inject)

c++ - 如何从成员函数中获取 "simple"函数指针