1

Вот мой пример кода:экстернализовать конечный экземпляр переменной

public class ExternalizableClass implements Externalizable 
{ 
    final int id; 

    public ExternalizableClass() 
    { 
    id = 0; 
    } 

    public ExternalizableClass(int i) 
    { 
    id = i; 
    } 

    @Override 
    public void writeExternal(ObjectOutput out) throws IOException 
    { 
    out.writeInt(id); 
    } 

    @Override 
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException 
    { 
    id = in.readInt(); 
    } 

    @Override 
    public String toString() 
    { 
    return "id: " + id; 
    } 
} 

Это не может компилироваться, так как id = in.readInt(); дает Error:(36, 5) java: cannot assign a value to final variable id. Однако я могу думать о реальных случаях использования, когда неизменяемое поле, такое как id, должно быть экстернализировано, в то время как мы также хотим сохранить его неизменность.

Итак, как правильно решить эту проблему?

+0

Не могли бы вы инкапсулировать это поле в классе, а затем создать экземпляр указанного класса при чтении данных? Помимо этого, на самом деле не имеет смысла повторно инициализировать конечную переменную экземпляра после того, как экземпляр был сконструирован; вот в чем смысл «final» –

+1

@VinceEmigh Но в этом случае я не повторно инициализирую объект. Это экстернализация, поэтому я хочу сохранить obj в файл и перестроить его для последующего использования. – OneZero

+0

Я знаю, но если вам действительно нужно, чтобы поле было окончательным, вы не достигнете этого, если вам нужно инициализировать поле, используя экстернализацию. Вы всегда можете создавать новый объект при чтении, а затем разыскивать объект при записи. Или вы можете переключиться на «Serializable»: «* Я подозреваю, что вам будет трудно получить значимую выгоду от Externalizable с помощью современной JVM. *" - http://stackoverflow.com/a/818093/2398375 –

ответ

-1

Функция чтения не имеет смысла с идеей конечного поля, потому что любое значение, которое оно было инициализировано, должно быть его значением навсегда. Функция чтения не должна его изменять.

Объекты, объекты, инициализированные конструктором public ExternalizableClass(int i), не могут читать новое значение - если они могут тогда их значение id не является окончательным. Единственный способ, которым я мог это сделать, - заставить конструктор по умолчанию инициализировать «непрочитанный» экземпляр, позволяющий вам позже называть его. Это, однако, требует удаления окончательного модификатора и работы вокруг него. Итак, это будет выглядеть так:

public class ExternalizableClass implements Externalizable 
{ 
    private int id; 
    private boolean initted; 

    int getId(){ 
     return id; 
    } 

    public ExternalizableClass(int i, boolean initted){ 
     id = i; 
     this.initted = initted; 
    } 

    public ExternalizableClass(){ 
     this(0, true); //Default instances can't be changed 
    } 

    public ExternalizableClass(int i) 
    { 
    this(i, true); //Instances from this constructor can't be changed either 
    } 

    @Override 
    public void writeExternal(ObjectOutput out) throws RuntimeException, IOException 
    { 
    if(! initted) 
     throw new RuntimeException("Can't write unitialized instance, " + this); 
    out.writeInt(id); 
    } 

    @Override 
    public void readExternal(ObjectInput in) throws RuntimeException, IOException, ClassNotFoundException 
    { 
    if(initted) 
     throw new RuntimeException("Can't Read into already initialized object ," + this); 
    id = in.readInt(); 
    initted = true; 
    } 

    @Override 
    public String toString() 
    { 
    if(initted) return "id: " + id; 
    else return "No id"; 
    } 
} 
+0

'readExternal()' является методом экземпляра и должен возвращать 'void'. – OneZero

+0

Ах, забыл, что он должен был все еще соответствовать заголовкам метода интерфейса. Я удалю этот ответ. – Mshnik

+0

Ваш обновленный ответ все еще не кажется правильным. В вашем ответе предполагается, что конструктор по умолчанию не будет использоваться, кроме экстернализации. Однако в реальных ситуациях конструктор по умолчанию может также использоваться, поэтому использование 'initted' является ошибочным. – OneZero