Ниже приведены жесткие требования к неизменяемому объекту.
final
но объект все еще может быть изменен, т. е. private final Date imStillMutable
). Вы должны сделать defensive copies
в этих случаях. Обоснование создания класса final
очень тонкое и часто упускается из виду. Если его конечные люди могут свободно расширять ваш класс, переопределить поведение public
или protected
, добавить изменчивые свойства, а затем предоставить их подкласс в качестве замены. Объявив класс final
, вы можете убедиться, что этого не произойдет.
Чтобы увидеть проблему в действии, рассмотрите приведенный ниже пример:
public class MyApp{
/**
* @param args
*/
public static void main(String[] args){
System.out.println("Hello World!");
OhNoMutable mutable = new OhNoMutable(1, 2);
ImSoImmutable immutable = mutable;
/*
* Ahhhh Prints out 3 just like I always wanted
* and I can rely on this super immutable class
* never changing. So its thread safe and perfect
*/
System.out.println(immutable.add());
/* Some sneak programmer changes a mutable field on the subclass */
mutable.field3=4;
/*
* Ahhh let me just print my immutable
* reference again because I can trust it
* so much.
*
*/
System.out.println(immutable.add());
/* Why is this buggy piece of crap printing 7 and not 3
It couldn't have changed its IMMUTABLE!!!!
*/
}
}
/* This class adheres to all the principles of
* good immutable classes. All the members are private final
* the add() method doesn't modify any state. This class is
* just a thing of beauty. Its only missing one thing
* I didn't declare the class final. Let the chaos ensue
*/
public class ImSoImmutable{
private final int field1;
private final int field2;
public ImSoImmutable(int field1, int field2){
this.field1 = field1;
this.field2 = field2;
}
public int add(){
return field1+field2;
}
}
/*
This class is the problem. The problem is the
overridden method add(). Because it uses a mutable
member it means that I can't guarantee that all instances
of ImSoImmutable are actually immutable.
*/
public class OhNoMutable extends ImSoImmutable{
public int field3 = 0;
public OhNoMutable(int field1, int field2){
super(field1, field2);
}
public int add(){
return super.add()+field3;
}
}
На практике очень часто встречается вышеупомянутая проблема в средах зависимости Injection. Вы явно не создаете экземпляры, а ссылка суперкласса, которую вы даете, может фактически быть подклассом.
Отказ в том, что для того, чтобы сделать твердые гарантии о неизменности, вы должны пометить класс как final
. Это подробно описано в Эффективная Java Джошуа Блоха и явно указано в спецификации для модели памяти Java .
Как только вы определили нужную глубину для всех томов, пусть это будет D, вы можете создать экземпляр изображения (называемого том , когда D> 1) размеров W x H x D, для каждого объема у вас есть.
Затем вы можете заполнить каждый такой объем, пиксель за пикселем, отображая положение пикселя на исходный объем и извлекая значение пикселя, интерполируя значения в соседних пикселях.
Например, пиксель (i_x, i_y, i_z) в новом томе будет отображаться в точке (i_x, i_y, i_z ') старого тома. Одним из самых простых методов интерполяции является линейная интерполяция: значение (i_x, i_y, i_z) является средневзвешенным значением значений (i_x, i_y, floor (i_z ')) и (i_x, i_y, floor (i_z') + 1).
Если вам просто нужно добавить нули к вашим данным, чтобы получить ту же глубину, вот способ сделать это: