This question already has answers here:
Why can I edit the contents of a final array in Java?
(9 answers)
Closed 8 years ago.
I am confused. I tried using
final String usr;
and trying to change its value never worked, but when I used an array final String[] usr = {"", ""};, it worked. I even accessed it from this
sgnup.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
user[0] = sUsr.getText();
}
});
I find it very confusing because my understanding of final is that a variable declared with final and add a value to it, the value never changes. But why did an array with final work? I can even set a text to one of those arrays.
Yes, because you don't change the reference of usr but what it contains. final block you from doing something like usr = new String[5]; (change the usr to another array) but the content of the array can be changed without problems.
final String[] a = new String[5];
a = new String[3]; // illegal
final String[] a = new String[5];
a[0] = "Hello"; // legal, i don't change a but what is inside a[0]
In Java, a variable of any object type (including any array) actually is a reference to an object, not the object itself. When you declare a variable to be final, it means that the reference will not change, meaning that the object it references will always be the same object. However, if the internal state of the object can still change without the final modifier, then adding final won't prevent the internal state of the referenced object from changing. In particular for a final array, the array reference itself cannot be reassigned, but the array elements can still change.
In your situation, you can avoid using an array by simply eliminate the final modifier from the String variable.
Related
I know that writing a lambda in Java 8 to use a variable requires final type, but why can a variable of final array type be modified?
public static void main(String[] args) {
final String[] prefix = {"prefix_"};
String suffix = "_suffix";
List<Integer> list = Arrays.asList(1005, 1006, 1007, 1009);
List<String> flagList = list.stream().map(param -> {
prefix[0] = "NoPrefix_";
String flag = prefix[0] + param + suffix;
return flag;
}).collect(Collectors.toList());
System.out.println(flagList);
System.out.println(prefix[0]);
}
result:
[NoPrefix_1005_suffix, NoPrefix_1006_suffix, NoPrefix_1007_suffix, NoPrefix_1009_suffix]
NoPrefix_
So a final array means that the array variable which is actually a reference to an object, cannot be changed to refer to anything else, but the members of the array can be modified
refer below link for more information.
https://www.geeksforgeeks.org/final-arrays-in-java/
As per description
for example
final String[] arr = new String[10];
list.stream().map(ele -> {
arr[0] = ele.getName(); // this will work as you are updating member of array
arr = new String[5]; // this will not work as you are changing whole array object instead of changing member of array object.
}).collect(Collectors.toList());
the same thing happen when you use any final collection there.
why can a variable of final array type be modified?
It can't, even though it looks like it can.
The declaration is below, which defines "prefix" as an array:
final String[] prefix
First, edit the code to include two println() calls right after the declaration, like this:
final String[] prefix = {"prefix_"};
System.out.println("prefix: " + prefix);
System.out.println(prefix[0]);
And at the end, add a second println() next to the one you already had, like this:
System.out.println("prefix: " + prefix);
System.out.println(prefix[0]);
If you run that code, you'll see that the object hashCode when printing prefix will be the same object each time. The thing that changes then is not what "prefix" references – that remains the same, it's the same array as before. Instead, what you're doing is changing something inside the array, which is different from the array itself.
Here are the relevant lines from a local run showing that the object reference remains the same, but the value for "prefix[0]" changes:
prefix: [Ljava.lang.String;#5ca881b5
prefix_
prefix: [Ljava.lang.String;#5ca881b5
NoPrefix_
If we try to assign an entirely new array to "prefix", then the compiler will show an error – it knows "prefix" was defined as final.
prefix = new String[]{"new"};
cannot assign a value to final variable prefix
If you're looking for a way to prevent changes to the data, and if it's possible to use a List (instead of an array), you could use
Collections.unmodifiableList():
Returns an unmodifiable view of the specified list. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.
I'm getting a NullPointerException with the following Java code:
static String s[],t[],temp;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
s[0]=jTextField2.getText();
jTextField3.setText("The input string is: "+s[0]);
temp=jTextField1.getText();
t=temp.split(" ");
jTextField3.setText("The input string is: "+t[0]);
}
This code keeps giving me java.lang.NullPointerException. What is wrong with my code???
I also tried this way:
static String s[],t[],temp;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
temp=jTextField2.getText();
s[0]=temp;
jTextField3.setText("The input string is: "+s[0]);
temp=jTextField1.getText();
//t=temp.split(" ");
//jTextField3.setText("The input string is: "+t[0]);
}
And also jTextField3.setText("The input string is: "+t); doesn't work with t declared just as static String t. in the text field it shows some exception again.
You're declaring your array, but you're never initializing it, and so when you try to access the array items, for instance like so, s[0], a NPE will be thrown since s is null.
You need to assign the array to an array object like so:
// SIZE is an int constant that is the size of the array you desire.
String[] s = new String[SIZE];
Side notes:
You likely should not declare any of these variables as static, and doing so suggests that the program design could be improved.
I have to wonder if you are using parallel arrays to hold your data. If so, consider creating a new class to hold each "row" of data's information, and then using an ArrayList of this type of class.
Edit
You state:
But I dunno the size initially. Can I use String[temp.length];???
You could initialize your arrays to a large size, one that's likely to be larger than you expect to need, however an even better solution is to not use arrays at all (directly) but rather use ArrayLists which behave sort-of kind-of like arrays of variable size.
int LENGTH = 10;
static String s[] = new String[LENGTH];
static String t[] = new String[LENGTH];
In SCJP book i get a point by Kathy Sierra that their is no final object in java. There are only final reference variable in java.
But i think objects of string class are final. As once initialized their state can not change.
Now question is that the objects of string class are final or not.
If they are not than how the objects of string class are immutable.
Thanks
But i think objects of string class are final. As once initialized their state can not change.
No, they're not final in the Java sense. They're immutable, but final relates purely to variables/data members, not objects.
Here's an example:
final String a = "foo";
String b = "bar";
b = "updated bar"; // Compiles and works, `b` (the variable) can be changed
a = "updated foo"; // Won't compile, you're not allowed to change the `a` variable
final is about whether a "variable"'s value can be changed, not about whether the state of an object can be changed.
Here's an example with a final variable referring to a mutable object:
final Map a = new HashMap();
a.add("foo", "bar"); // Works; we're not changing `a`, we're changing the state
// of the object `a` refers to
And just to take objects out of it entirely:
final int a = 5;
a = 6; // Won't compile, because we aren't allowed to change `a`
First you have to read this:
http://en.wikipedia.org/wiki/Final_(Java)
Because in Java final keyword can be used in several different context.
String class is immutable, it means that after creation state of this object cannot be changed and is also declared as final which means it can't be subclassed.
You would have to post the chapter (please don't, by the way) to fully give the context, but I can distinguish the two concepts further for you.
final is a keyword in java that applies, in your case, to a reference variable. That means that once the object is instantiated, that variable cannot be assigned to a different object, i.e., if you do:
final String[] stringArray = new String[8];
you can never do anything again like this:
stringArray = new String[2];//stringArray is final and cannot be reassigned
This doesn't indicate however that if the contents of stringArray are not able to be changed. You can do:
stringArray[3] = "Hey!";
And it will compile just fine. This shows you that just the reference cannot be reassigned to anything else; we're only talking the reference here.
When they say String is immutable, they are talking about the String constant pool. In the string constant pool there is a collection of strings that have been created in memory that are stored for reuse. If you say, for example:
String tempString1 = "yo";
String tempString2 = "yo";
You only created 1 string object in the string constant pool (a special part of memory where strings go) and assigned it to two different reference variables. If you do:
tempString2 = "hey";
String tempString3 = "yo";
you have only created 1 new object again, "hey", in the string constant pool. tempString1 only changed what it was pointing to, and tempString3 is reusing "yo" that has already been created.
If you do this because you're nuts about Java:
tempString1 = tempString2 + tempString3;
String tempString4 = tempString2 + tempString3;
String tempString5 = tempString2 + tempString3;
You have only created 1 more string "heyyo". "yo" "hey" and "heyyo" are the only strings in the String constant pool.
Any operation you do will not change "hey" and "yo" in the string constant pool, even though you may change output to appear like those strings have changed.
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 years ago.
public class StackOverFlow {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("A");
al.add("B");
markAsNull(al);
System.out.println("ArrayList elements are "+al);
String str = "Hello";
markStringAsNull(str);
System.out.println("str "+ str);
}
private static void markAsNull(ArrayList<String> str){
str.add("C");
str= null;
}
private static void markStringAsNull(String str){
str = str + "Append me";
str = null;
}
}
This outputs:
ArrayList elements are [A, B, C]
str Hello
In the case of ArrayList, the added elements are getting retrieved.
In case of String the method call has no effect on the String being passed. What exactly is the JVM doing? Can anyone explain in detail?
In the case of Arraylist string objects the added elements are getting retrived. In case of String the method call has no effect on the String being passed.
It happens cause Java is Pass-by-Value and Strings are immutable
When you call
markAsNull(ArrayList<String> str)
The a new reference by name str is created for the same ArrayList pointed by al. When you add an element on str it gets added to same object. Later you put str to null but the object has the new values added and is pointed by a1.
When you call
markStringAsNull(String str)
{
str = str + "Append me";
// ...
}
The line str = str + "Append me"; creates a new String object by appending the given string and assignes it to str. but again it is just reference to actual string which now pointing to newly created string. (due to immutablity) and the original string is not changed.
The markXAsNull methods are setting the local references to be null. This has no effect on the actual value stored at that location. The main method still has its own references to the values, and can call println using those.
Also, when doing the string concatenation, toString() is being called on the Object, and that is why the ArrayList is outputted as a list of its values in brackets.
From the Book: SCJP - Sun Certified Programmer for Java 6 Study Guide (Katty Sierra - Bert Bates) Chapter 3 Objective 7.3 - Passing Variables Into Methods
Java is actually pass-by-value for all variables running within a single
VM. Pass-by-value means pass-by-variable-value. And that means, pass-by-copy-ofthe-
variable!
The bottom line on pass-by-value: the called method can't change the caller's
variable, although for object reference variables, the called method can change the
object the variable referred to. What's the difference between changing the variable
and changing the object? For object references, it means the called method can't
reassign the caller's original reference variable and make it refer to a different object,
or null. For example, in the following code fragment,
void bar() {
Foo f = new Foo();
doStuff(f);
}
void doStuff(Foo g) {
g.setName("Boo");
g = new Foo();
}
reassigning g does not reassign f! At the end of the bar() method, two Foo objects
have been created, one referenced by the local variable f and one referenced by
the local (argument) variable g. Because the doStuff() method has a copy of the
reference variable, it has a way to get to the original Foo object, for instance to call
the setName() method. But, the doStuff() method does not have a way to get to
the f reference variable. So doStuff() can change values within the object f refers
to, but doStuff() can't change the actual contents (bit pattern) of f. In other
words, doStuff() can change the state of the object that f refers to, but it can't
make f refer to a different object!
Java follows passby value concept ( there is no pass by reference in java ) . So when you pass a string to the function it sends a "copy of reference" to that string to the function. So even if you set the variable to null in the function, when it returns to the caller it refers its original value only. That's why original string has no effect.
In case of Arraylist, copy of reference refers to the original Arraylist (which is also the same in case of string). But when you add something into ArrayList, it refers to the original object and so that you can see the effect. ( try in method arraylist=new ArrayList(), your original arraylist will remain as it is).
In case of string, when you do
str=str + "abc";
Java creates a new String object which will have reference to string "xyzabc" ( e.g. str="xyz") and "xyz" will be eligible for the garbage collection. But as "xyz" is still having an variable which refers to it it ( original string) will not be garbage collected. But as soon as the function call gets over "xyzabc" goes for garbage collection.
Summary of the discussion is, as long as an reference refers to the same object you can make changes in the function, but when you try to change the reference ( str=str+"abc") you are refering to the new object in the method so that your original object will remain as it is.
In Java, you may create one object, and referenced by multiple pointers. Calling a mutator method on any pointer will effectively modify the sole object, thus updating all other references.
But if you call variable assignment statements on a reference, only that pointer will be changed, since it doesn't do any object side work (this is the best I could explain...).
Passing an object to a parameter will effectively copy the reference, resulting in a single object, with two pointers - one global, and the other local.
One more point, since String is immutable, you'll actually get a new object, that is distinct from the original (from the fact that you have to say a = a + "a"), that's why it won't modify the original string.
The following code in Java uses a final array of String.
final public class Main {
public static final String[] CONSTANT_ARRAY = {"I", "can", "never", "change"};
public static void main(String[] args) {
for (int x = 0; x < CONSTANT_ARRAY.length; x++) {
System.out.print(CONSTANT_ARRAY[x] + " ");
}
}
}
It displays the following output on the console.
I can never change
If we try to reassign the declared final array of type String, we cause an error:
final public class Main {
public static final String[] CONSTANT_ARRAY = {"I", "can", "never", "change"};
public static void main(String[] args) {
CONSTANT_ARRAY={"I", "can", "never", "change"}; //Error - can not assign to final variable CONSTANT_ARRAY.
for (int x = 0; x < CONSTANT_ARRAY.length; x++) {
System.out.print(CONSTANT_ARRAY[x] + " ");
}
}
}
Error: cannot assign to final variable CONSTANT_ARRAY.
However, the following code works:
final public class Main {
public static final String[] CONSTANT_ARRAY = {"I", "can", "never", "change"};
public static void main(String[] args) {
CONSTANT_ARRAY[2] = "always"; //Compiles fine.
for (int x = 0; x < CONSTANT_ARRAY.length; x++) {
System.out.print(CONSTANT_ARRAY[x] + " ");
}
}
}
It displays
I can always change
This mean that we could manage to modify the value of the final array of type String. Can we modify the entire array in this way without violating the immutable rule of final?
final in Java affects the variable, it has nothing to do with the object you are assigning to it.
final String[] myArray = { "hi", "there" };
myArray = anotherArray; // Error, you can't do that. myArray is final
myArray[0] = "over"; // perfectly fine, final has nothing to do with it
Edit to add from comments: Note that I said object you are assigning to it. In Java an array is an object. This same thing applies to any other object:
final List<String> myList = new ArrayList<String>():
myList = anotherList; // error, you can't do that
myList.add("Hi there!"); // perfectly fine.
You are misinterpreting the final implementation. final applies to the array object reference, which means once it is initiated, the reference can never change but the array its self can be populated. "Its not violating the rules" you have specified only one rule about the reference change which is working accordingly. If you want the values should also never change you should go for Immutable lists i.e
List<String> items = Collections.unmodifiableList(Arrays.asList("I", "can", "never", "change"));
You can only make it so the array reference can't be changed. If you want the elements to be unable to be changed, you need to use an unmodifiable collection of some kind.
When you declare an array as final, you can change the elements in the array, however you cannot change the reference of this array.
final only guarantees immutability of primitives. And also guarantees that a variable is assigned only once. If an object is mutable you can change the content of it event it defined as final. You may check immutable collections for your needs. Such as Collections.unmodifiableList()
http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#unmodifiableList(java.util.List)
The reference to the array object is final (can not change e.g. in case you would attempt to associate a different Java array object (instance of String[]) to the same final variable...you'd get a compile time error).
BUT the fields of the final array object in your example are not final, and so you can modify their value. ...while the Java object you created, CONSTANT_ARRAY, after receiving an initial value, will have that value "forever" == until the JVM stops. :) It will be the same String Array instance "forever".
Final variables in Java are not a big deal, just spend some time to digest the topic/idea carefully. :-)
I suggest to all of those who are uncertain to meditate over this page, for example:
https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4
Let me cite the respective part:
"Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object.
This applies also to arrays, because arrays are objects; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array."
The value of the variable CONSTANT_ARRAY cannot change. That variable contains a (reference to an) array. However, the contents of the array can change. Same thing happens when you declare any kind of final variable that is not a simple scalar type (e.g. an object).
Be careful how you name your variables. :-) Calling it a CONSTANT_ARRAY doesn't make the contents of the array unchangeable.
Here's a good reference: The final word on final
When a variable is declared with the final keyword, its value can’t be modified, essentially, a constant. This also means that you must initialize a final variable. If the final variable is a reference, this means that the variable cannot be re-bound to reference another object, but the internal state of the object pointed by that reference variable can be changed i.e. you can add or remove elements from the final array or final collection.
final int[] res;
int[] res1;
int[] res2 = new int[1];
res2[0]=20;
res1=res2;
res1=res2;//no error
System.out.println("res1:"+res1[0]);
res = res2;//only once
//res = res2;//error already initialised
res2[0]=30;
System.out.println("res:"+res[0]);
output::
res1:20
res:30