【问题标题】:Java: accessing transient object fields inside classJava:访问类内的瞬态对象字段
【发布时间】:2010-12-15 11:14:02
【问题描述】:

必须通过一些代码来控制从类中的任何方法访问私有瞬态对象字段。最佳做法是什么?

private transient MyClass object = null;

内部get方法:

private MyClass getObject() {
    if (object == null)
        object = new MyClass();
    return object;
}
// use...
getObject().someWhat();

或“确保”方法:

private void checkObject() {
    if (object == null)
        object = new MyClass();
}
// use...
checkObject();
object.someWhat();

或者更聪明、更安全或更强大的东西?

【问题讨论】:

    标签: java object field transient


    【解决方案1】:

    瞬态字段在序列化时会丢失,但你只有在反序列化后才需要它们,所以你必须在 readObject 方法中将它们恢复为你需要的...

    【讨论】:

    • 谢谢,但我想让我的字段瞬态和延迟实例化(即使用惰性吸气剂)。我将其添加到问题中。
    【解决方案2】:

    必须发布有关瞬态的新答案,因为评论太长了。以下代码打印

    Before: HELLO   FOO BAR
    After:  HELLO   null    null
    
    
    public class Test {
    
    public static void main(String[] args) throws Exception {
    
        final Foo foo1 = new Foo();
        System.out.println("Before:\t" + foo1.getValue1() + "\t" + foo1.getValue2() + "\t" + foo1.getValue3());
        final File tempFile = File.createTempFile("test", null);
        // to arrange for a file created by this method to be deleted automatically
        tempFile.deleteOnExit();
        final FileOutputStream fos = new FileOutputStream(tempFile);
        final ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(foo1);
        oos.close();
        final FileInputStream fis = new FileInputStream(tempFile);
        final ObjectInputStream ois = new ObjectInputStream(fis);
        final Foo foo2 = (Foo) ois.readObject();
        ois.close();
        System.out.println("After:\t" + foo2.getValue1() + "\t" + foo2.getValue2() + "\t" + foo2.getValue3());
    
    }
    
    static class Foo implements Serializable {
    
        private static final long serialVersionUID = 1L;
        private String value1 = "HELLO";
        private transient String value2 = "FOO";
        private transient String value3;
    
        public Foo() {
            super();
            this.value3 = "BAR";
        }
    
        public String getValue1() {
            return this.value1;
        }
    
        public String getValue2() {
            return this.value2;
        }
    
        public String getValue3() {
            return this.value3;
        }
    }
    

    }

    【讨论】:

      【解决方案3】:

      最安全(和正常)的方式是直接初始化它:

      private transient MyClass object = new MyClass();
      

      或者使用构造函数

      public ParentClass() {
          this.object = new MyClass();
      }
      

      只有在 MyClass 的构造函数和/或初始化块正在做相当昂贵的事情,但它不是线程安全的情况下,getter 中的延迟加载(如您在示例中所做的那样)才有用。

      transient 修饰符没有任何区别。它只会在对象即将被序列化时跳过该字段。

      编辑:不再相关。正如其他人所证明的那样,它们确实不会在反序列化时重新初始化(虽然有趣的想法,它实际上只会在它们被声明为static 时才会发生)。我会继续使用延迟加载方法,或者在反序列化后直接通过它们的设置器重置它们。

      【讨论】:

      • 是的,但是在反序列化过程中,瞬态字段(除了readObject() 实现之外)被静默设置为null——这就是我想在我的问题中解决的问题。我应该将它添加到我的原始文本中。
      • 它们没有设置为null,它们被保留了它们的初始值。
      • @Tom:实际上它们被设置为类型默认值,因此对于 Object 为 null 或对于 int 例如为 0...
      • 正如汤姆所说。没什么可担心的。只需以正常方式处理它们即可。唯一的区别是它们在正常(反)序列化过程中从未被触及。
      • @BalusC:我刚刚发布了另一个答案,表明瞬态字段设置为类型默认值。实际上反序列化期间没有调用构造函数...
      猜你喜欢
      • 1970-01-01
      • 2011-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多