I understand that immutable means that it is an object that will not change state after it is instantiated. But in this line of code I dont see Final when the array values is declared.
Is this class immutable? Can anyone explain how to find out. Thanks
public class A {
private double[] values;
public double[] getValues(){
return values;
}
}
As other have written this object is considered to be mutable in its state. What it is immutable to is that you can not exchange the array it holds. But you can change the array's content (getValues()[0] = 10;).
To convert this to a immutable object you must use List instead of an array. With List you can use Collections' method unmodifiableList to convert a given list into a version you can savely expose to the outside. If the caller of getValues() uses add or remove on a unmodifiable list it will result into a UnsupportedOpertionException keeping your object save from being modified.
If you need to stick to arrays you need to provide a copy (System.arraycopy) or a clone (clone()) of the array.
Usually a object is considered to be immutable if you can not change its properties (including inherited properties from superclasses. This usually includes the properties values as well but this is a blurred definition.
For example if you have a class that holds a File instance which points to document file and this File instance can not be changed the class is considered to be immutable (the inforamtion it provides never changes) but the document it points to can be mutated and changed every time. So its a blurred line actually (remember in your example you can not change the array but the content of the array).
Yes the code pasted is not having any final keyword associated and has no immutable behavior.
Well i would like to bring forth some key guidelines related to writing immutable classes in java :
1.) Ensure the class cannot be overridden - make the class final, or use static factories and keep constructors private
2.) Make fields private and final
force callers to construct an object completely in a single step, instead of using a no-argument constructor combined with subsequent calls to setXXX methods (that is, avoid the Java Beans convention)
3.) Do not provide any methods which can change the state of the object in any way - not just setXXX methods, but any method which can change state
4.) If the class has any mutable object fields, then they must be defensively copied when they pass between the class and its caller
A a = new A();
a.getValues()[0] = 1.2;
This would work as long as values is not empty. You will however not be able to reassign values to a new array. That is: a.getValues() = new double[5]; will not work.
The class is not immutable, as I can change values, just not reassign it.
Here is a simple verification. the values are initialized to 1,2.
Using the getter and a reference, one is able to change the values inside the first item in the array after the object is created
public class A {
private double[] values;
public double[] getValues() {
return values;
}
public static void main(String[] args) {
A test = new A();
test.values= new double[]{1, 2};
double[] valuesref = test.getValues();
valuesref[0] = 10;
for (int i = 0; i < test.values.length; i++) {
System.out.println(test.values[i]);
}
}
}
This can be avoided if getValues() returns a copy of the array.
Related
I would like to know what is the best practice to return 'updated' ArrayList?
For example, if I am adding in a new element, it seems that whether if I did or did not specify the return type (see the addNewA() and addNewB()), the ArrayList in my main() method will still be 'updated' nonetheless.
Should I or should I not specify the return type?
Currently in my client program, most of the methods, I have specified it as void (no return type) and while the overall program still does works as intended, thought I would like to get this clarified and make the necessary changes if necessary.
public class MyClient
{
public static ArrayList<Person> addNewA(ArrayList<Person> myArray)
{
Person jack = new Person("jack", 24);
myArray.add(jack);
return myArray;
}
public static void addNewB(ArrayList<Person> myArray)
{
Person ben= new Person("ben", 19);
myArray.add(ben);
}
public static void main(String[] args)
{
ArrayList<Person> personArray= new ArrayList();
addNewA(personArray); // will return me an array size of 1
addNewB(personArray); // will return me an array size of 2
}
}
In a case like this, you should not return the list and should make your method void.
Different languages have different conventions, but one of Java's is that methods that operate by modifying their arguments (or the object they're called on) should not return values. Returning a value implies to someone using your code that a different object is being returned, since otherwise there is no use in returning an object the caller already has1. A method that is void, on the other hand, couldn't possibly be returning a copied-and-extended list, so it's very clear that it's intended to operate by modifying the list that you give it in the first place.
(By the way, you should also just use List<Person>, and you should pay attention to the warning you get about using new ArrayList() instead of new ArrayList<>().)
1 There is a specific exception to this, called the fluent builder pattern, but it's not easily confused with general code like this.
In java (and most high level strict type languages) Objects are passed by reference and primitives passed by value.
When using the new keyword you create an object.
While primitives (like int, char, double ect) are passed by value (meaning that a copy of the value of the variable will be sent to the invoked function), Object types are passed by reference, meaning that the actual original object is passed to the function.
To sum up - since you are using object here (ArrayList), you don't need a return type since the original object is changing.
I have an object which contains some package-private member variables and I'm adding them to a Google Sheets v4 ValueRange in another object. The current code looks a little bit like this:
List<List<Object>> data = new ArrayList<>();
...
/**
* Sets all the values in the ValueRange member variable
* #return the ValueRange object
*/
ValueRange requestBuilder() {
...
//For each case, add it to the value range
for (int i = 0; i < closedCases.size(); i++) {
data.add(
Arrays.asList(
closedCases.get(i).number,
closedCases.get(i).priority,
closedCases.get(i).firstResp,
closedCases.get(i).accName,
closedCases.get(i).subject,
closedCases.get(i).assigned,
closedCases.get(i).lastUpdated,
closedCases.get(i).daysOld,
closedCases.get(i).jiraCase
)
);
}
vr.setValues(data);
return vr;
}
The question that I'm seeking to answer is, is there any way to do Arrays.asList( closeCases.get(i) ) or add some kind of method on the case object to simply fill all that stuff in, rather than calling out each member variable in the Arrays.asList(). I'm also aware I can use a foreach, but would still need to use the same notation for adding items, which is what I'm trying to avoid.
In case anyone is interested, closedCases is just an ArrayList of an object with some strings and doubles in it.
You somehow need to specify what fields go into this list, in what order. If you want to capture all fields, you could use reflection to iterate over the object (potentially choosing declared, not inherited fields, and potentially choosing only package-private fields), as described here.
But that is not the idiomatic way to do it in Java.
Can you change the definition of the "object which contains some package-private member variables" so that instead it has a Map with key-value pairs?
You could add a List field in the object that is held by closedcases and call that field from inside the loop.
For instance, say the object is Foo,
Inside foo, create a field:
ArrayList<String> allFields = new ArrayList<String>{number. priority …… };
Method:
public ArrayList<String> getAll() {
return allFields;
}
And from inside the loop, just do
data.add(closedCases.get(i).getAll());
If the fields are not just string, you could create different arraylist that holds different types of object, which will increase the list again but could be substantially less that what you gave us.
I always use constuctor only for attributes of one object.
But i thin when i wrote this :
public Predmet(int esp,int obaveze,int cena){
this.cena=cena;
this.obaveze=obaveze;
this.esp=esp;
List j = new ArrayList();
j.add(8);
this.nesto=(int) j.get(0);
}
where are stored this ArrayList,does it part of object,or is on stack and have reference to array in heap?
The ArrayList is created on the heap and only referenced by the local variable j from the stack here. After the execution of the constructor it will be eligible for garbage collection.
Constructor is working very similar the way methods work. At runtime, anything you define inside constructor/method are called local variables. Their scope will end as soon as execution hits the end of the constructor/method. After consturctor, your list will be eligible for GC. However, this.nesto will still get value 8 as its primitive type.
First, please don't use single variable names! This is bad practice and makes files harder to read. Using a more descriptive name helps to promote code readability.
The way that List j is created, it only exists in the scope of the constructor. After your constructor, List j is no longer accessible. If you wanted it to be accessible after the constructor, have a field for the object. For example:
public class Example {
private int specialNumber;
private List<Integer> numberList;
/**
* Constructs a new Example Object
*/
public Example(int exampleNum){
// specialNumber can be accessed from a Getter method (getSpecialNumber)
this.specialNumber = exampleNum;
this.numberList = new ArrayList<Integer>();
this.numberList.add(exampleNum);
// numberList is a field of this Example now
List<Integer> disappearingList = new ArrayList<Integer>();
disappearingList.add(exampleNum);
// After this method finishes, disappearingList will be gone
}
// disappearingList is no longer accessible
/**
* Gets this Example's specialNumber value
* #return int this.specialNumber
*/
public int getSpecialNumber(){
return this.specialNumber;
}
/**
* Gets this Example's numberList
* #return List<Integer> this.numberList
*/
public List<Integer> getNumberList(){
return this.numberList;
}
}
There is probably a way to hook into some of the Java cleaning methods and pull it out, but that will get a little messy. If you want to be able to create an Object inside another Object, and use it after the constructor, it must be saved as a field.
I'm getting this error when running checkstyle on my code for the following lines:
#Override
public String[] getDescriptions() {
return DESCRIPTIONS;
}
but DESCRIPTIONS IS NOT mutable. It's defined as:
private static final String[] DESCRIPTIONS = new String[NUM_COLUMNS];
static {
// In a loop assign values to the array.
for (int i = 0; i < NUM_COLUMNS; ++i) {
DESCRIPTIONS[i] = "Some value";
}
}
This is the complete error message:
"Returning a reference to a mutable object value stored in one
of the object's fields exposes the internal representation of
the object. If instances are accessed by untrusted code, and
unchecked changes to the mutable object would compromise security
or other important properties, you will need to do something
different. Returning a new copy of the object is better approach
in many situations."
Related Question: Link
Arrays and some collections are not immutable in the sense that their content still remains mutable.
Immutability in Java only concerns object's reference assignment, not its deep content.
Try this:
#Override
public String[] getDescriptions() {
return Arrays.copyOf(DESCRIPTIONS, DESCRIPTIONS.length);
}
BTW, caution to java naming convention.. : descriptions, not DESCRIPTIONS
The reference variable is final so you cannot assign another array to DESCRIPTIONS. However, the object itself is mutable (arrays are always mutable), final or not. If you return the reference, then you lose control over the contents your variable, violating encapsulation.
You would need either to return a copy of the array, or don't return the array at all, providing a method to get a specific element of the array instead, if that's good enough.
I think that a final reference to an array of enums should be immutable.
The uniqueness and singularity of enums is enforced by the JVM, so I believe it is safe to say that they are immutable.
A final reference cannot be changed, so the reference is immutable.
But ... what about the array? Might it still be possible to subvert the array that contains the enum references?
I have a list of enums that correspond to database columns. These column names and their associated data do not change, so ... I would like to have the list as a class variable like so:
static final List<MetaData<Client>> C_COLUMNS =
DataTables.CLIENTS.getTableColumnsAsEnums();
where CLIENTS is the DataTable enum for which a list of column enums is being generated. The method that does this follows:
public <T extends DB> List<MetaData<T>> getTableColumnsAsEnums() {
Class<? extends MetaData> cls = this.columnsEnumToken();
return new ArrayList(Arrays.<MetaData<T>>asList(cls.getEnumConstants())); }
Am I right? This ought to become part of a multi-threaded design, and so I am concerned about the way that making this critical list of static data would render by app very vulnerable ... if it actually were mutable.
But ... what about the array? Might it still be possible to subvert the array that contains the enum references?
Yes. All arrays in Java are mutable, irrespective of how you declare the variable that holds the reference to the array.
If you want to avoid this "risk", then you must not expose the array; i.e. you need to declare it as private. You could then do one (or more) of the following:
Define a static method that will create and return a copy of the array. (Probably not the best option here ...)
Define a static get(int) method that returns the ith element of the array.
Wrap the array in a list (using Arrays.asList) and create an unmodifiable wrapper for it (using Collections.unmodifiableList).
If you want to get the public <T extends DB> List<MetaData<T>> getTableColumnsAsEnums() to return an immutable List you need to use Collections.unmodifiableList()
Also when you are using an unmodifiable list you don't have to worry about the internal array because the toArray method will return an copy of the internal array, not a reference to the internal array itself. This is true for all the Collections.
The REFERENCE is immutable, the content of that reference is not, that's just how things work.
So the following won't work
public enum TheEnum {
//......
}
final TheEnum[] arr = new TheEnum[5];
var = new TheEnum[6];
but this will work
public enum TheEnum {
OPTION_ONE;
//......
}
final TheEnum[] arr = new TheEnum[5];
var[1] = TheEnum.OPTION_ONE;