Is there a difference in this syntax? - java

I would like to know if in both cases the MyObject object is created. And if not, why do both cases work just fine?
MyObject[] abcd = new MyObject[8];
abcd[0] = MyObject();
String str = abcd[0].someMethod();
and
MyObject[] abcd = new MyObject[8];
String str = abcd[0].someMethod();
I know that in the first example, a MyObject array is created with 8 elements and stored in the reference variable of that array called abcd. I have an array of MyObject references but no actualy MyObject objects. So I create these objects and the first object is stored in array 0.
In the second example.. is it the same thing, just shorter code?
*EDITED: Forgot to add [] I apologize. *

Assuming you meant
MyObject[] abcd = new MyObject[8];
abcd[0] = new MyObject();
String str = abcd[0].someMethod();
this will work fine.
The second version will throw a NullPointerException unless someMethod happens to be static. In that case Java does not rely on an instance to be created for the static method to be invoked.

It is not the same thing: when you create an array (and it should be declared as a MyObject[], not a MyObject), you just create a "placeholder", you do not create individual items in the array. And when an array is created, its elements are null at first, or whatever zero is for the different primitive types.
And in your first example, you should do new MyObject(), MyObject() alone will not work (except if there is a method by the name MyObject() in the current class which... returns an instance of class MyObject. Talk about confusion).
As a result, your second code will throw a NullPointerException (unless, as #Reimeus mentions in his answer, .someMethod() is a static method of class MyObject).

MyObject abcd = new MyObject[8];
abcd[0] = MyObject();
String str = abcd[0].someMethod();
this fragment does not compile it should be like
MyObject [] abcd = new MyObject[8];
abcd[0] = new MyObject();
String str = abcd[0].someMethod();
In this case you are creating the array and putting one element at the index 0.
In your second case :
MyObject abcd = new MyObject[8];
String str = abcd[0].someMethod();
it also doesn't compile, it should be
MyObject []abcd = new MyObject[8];
String str = abcd[0].someMethod();
and you will have a NullPointerException as abdc[0] is not initialized.
(you created the array, but didn't put any element in it).

abcd[0] = MyObject();
This is not valid Java syntax; looks more like C++. You need
abcd[0] = new MyObject();
In Java an object is never the immediate value of a variable or an array element. Without that line, each array element is just null, so you won't be able to call any methods on it without getting NullPointerException.
In case your someMethod is static, what the line abcd[0].someMethod() actually compiles into is just
MyObject.someMethod();
The compiler ignores everything but the static type of the expression abcd[0], which is MyObject. This is a special case of Java semantics.

Related

Polymorphism. Problems with copy arrays

Empleado[] empleados = new Empleado[3];
empleados[0] = new Empleado("Alfredo", 20000, 2020, 6, 01);
empleados[1] = new Empleado("Alejandro", 21000, 2020, 7, 04);
empleados[2] = new Jefatura("Laura", 25000, 2010, 3, 6);
Jefatura jefeRRHH = (Jefatura) empleados[3]; // CASTEO
jefeRRHH.setIncentivo(1000);
Why is it that when i set the incentive for jefeRRHH, empleados[2] is changed? I thought if jefeRRHH was modified this didn't affect the array empleados.
I mean, when I walk the vector with a foreach loop, empleados[2] give me back with the incentive applied.
package poo;
public class test {
public static void main(String[] args) {
String Nombre = "José";
int j = 1;
String[] nombres = new String[1];
nombres[0] = Nombre;
int a = j;
Nombre= "Maria";
System.out.println(Nombre);
System.out.println(nombres[0]);
j=2;
System.out.println(j);
System.out.println(a);
}
}
Why isn't the same thing here?
When I declare the new variables I'm not assigning addresses, I'm assigning copies, right?
The following will hold true for all Objects in Java.
Assuming a simple class:
public class Foo {
}
When you then instantiate an object of class Foo, you will actually allocate memory on heap, construct a Foo-Object and retrieve the adress to this location, which will then be stored in the object variable:
Foo f = new Foo(); // f points to a Foo-Object
So, instead of copying the actual object, the reference will be copied...
Foo farr[] = new Foo[1]; // create array with a capacity of 1
Foo f = new Foo(); // f now holds the adress to an actual Foo-Object
farr[0] = f; // farr[0] now holds the adress to the SAME Foo-Object
Here is a nice article about references and objects,
and here is a nice answer as follow-up-reading
Furthermore there are primitive datatypes and String-literals.
Primitive datatypes are always simply copied, whatever happens. So there will never be the case, where you change one primitive variable and another one changes.
Strings on the other hand are a bit trickier. They are objects wrapped around a char[], and therefore are (as already stated by others here) immutable and share a so called String constant pool. Modifying a String will therefore result in a new String with the result, and the original String remains unmodified.
You probably have a typo in the code, you should reference the element with index 2 here:
Jefatura jefeRRHH = (Jefatura) empleados[3]; // CASTEO
So, you create a new object with
new Jefatura("Laura", 25000, 2010, 3, 6);
and store a reference to it in the element of the empleados array with index 2. Then you say that jefeRRHH will be another reference to the same object. Now you have two references pointing at the same object. Think about them like different names (or nicknames if you like) of the same person. When you access/modify the object using any of the references you change the same object, so the changes are visible through any other names/references.

Using the keyword "new" in a return statement

I have never seen the keyword "new" used in a return statement and my understanding of new is that it creates a new object. And "new" used in this context Practice permutation = new Practice(); is that it creates a new object called permutation. And permutation is a reference to some memory address. So maybe, return new String(content) is return a memory address? So my question is, what does new used in this context actually mean? I apologize for my noob question...
import java.util.Arrays;
public class Practice {
public String sort(String s) {
char[] content = s.toCharArray();
Arrays.sort(content);
return new String(content);
}
public static void main(String[] args){
Practice permutation = new Practice();
System.out.println(permutation.sort("hello"));
}
}
return new String(content); means it creates a new string object with the content you have passed. It's similar to
String str = new String(content)
return str;
When using the keyword new you shouldn't associate it with any assignment operator. What the new keyword does, in laymans terms, is it creates a reference to a new instance of the specified class and returns it. So when you put the statement
new Object();
That statement is completely valid and it is returning a new reference to an Object class. The only thing is that the reference doesn't get set to anything because there is no operator performing on it. So when you have
Object myObj = new Object();
The reference comes from the new Object() statement and the equals operator sets it equal to the myObj variable. So now, if you understand that, when you have
return new Object();
The reference comes from the new Object() statement again and the return keyword takes that reference and returns it out of the method that you're in.
Your theory is correct, but your understanding of variables is a little off (in a very common way...) An object never has a name; it exists independently of any variables referring to it1. Practice permutation = new Practice(); does three things:
It creates a new Practice object
It creates a new variable that may refer to a Practice object
It makes the variable actually refer to the new object
Note that permutation is not the name of the object; it is the name of the variable, and the variable refers to the object. You can create several variables that refer to the same object, and you can create an object that is not referred to by anything - and the latter is what happens in return new.
1Whether there are any references to an object actually does have an effect, as an unreferenced object may be garbage collected - but that is a more advanced topic.
This:
return new String(content);
Is (logically) identical to this:
String result = new String(content);
return result;
It just skips the step of storing the value in a variable and returns it directly. There's nothing different happening, a new object is being instantiated and an object is being returned.
return new String(content);
does 3 things:
1) In creates String object somewhere in memory
2) In creates pointer (or reference) to it in this stack of you current thread
3) It returns this reference to the caller.
The same as
s = new String(content);
return s;

Is it safe to re-use variables inside a method?

I have an array of type string which I want to re-use inside a method.
I need to pass it to a function which returns a subset of the elements of array passed. To capture the returned array from function, should I declare a new string array or can I safely re-use same array that was holding the unfiltered array to hold filtered array ??
Also clarify that, when I pass a variable like array to a function does it creates a new space for the array in the heap each time I pass it as parameter to further functions or just it uses the same space in the heap & just passes the reference? I guess in case of array it passes just the reference but in case of simple variables it allocates new space on stack, right?
EDIT: Thanks you all for the great answers and explanations!!
Please also clarify whether that if I am reusing the array, would I be required to set the null at the position when I end the subset of array ? (Actually the subset of my array is not directly calculated from the array but some other calulations, so I would be required to manually set the null otherwise the older elements of the list would be visible, right??)
when I pass a variable like array to a function does it creates a new space for the array in the heap each time I pass it as parameter to further functions or just it uses the same space in the heap & just passes the reference
Java is entirely pass by value, but with arrays and object types, the value being passed is a reference (pointer) to the actual object, which is not duplicated. So when you pass an array into a function, only the reference to the array is copied; the array itself isn't. That's why if a function modifies the contents of an array, the code calling the function sees the modifications.
Example:
// A method that changes the first entry in an array
void changeArray(String[] theArray) {
theArray[0] = "Updated";
}
// A method that uses the above
void someMethod() {
String[] foo = new String[3];
foo[0] = "Original 0";
foo[1] = "Original 1";
foo[2] = "Original 2";
this.changeArray(foo); // `changeArray` receives a *copy* of the reference
// held in `foo`; both references point to the same
// array
System.out.println(foo[0]); // Prints "Updated"
}
Passing a reference into a method is exactly like assigning it to another reference variable:
String[] foo = new String[3]; // Create a new aaray, assign reference to `foo` variable
String[] bar = foo; // Copy the reference into `bar` as well
foo[0] = "Hi there"; // Use the reference in `foo` to assign to the first element
System.out.println(bar[0]); // Use the reference in `bar`, prints "Hi there"
Essentially, references are values (numbers) that tell the JVM where the data for an object is. So even when we copy a reference (because Java is entirely pass-by-value, the value of the reference is passed to the function), it still points to the same memory as the original.
Since the reference is passed into the function by value, the function can't change the calling code's reference:
// A method that assigns a new reference; the calling code sees no change
void changeReference(String[] theArray) {
theArray = new String[1]; // Now we're not using the caller's object anymore
theArray[0] = "I was changed";
}
// A method that uses the above
void someMethod() {
String[] foo = new String[3];
foo[0] = "Original 0";
foo[1] = "Original 1";
foo[2] = "Original 2";
this.changeReference(foo);
System.out.println(foo[0]); // Prints "Original 0", our reference wasn't changed
}
You'll note that this is exactly how primitives are treated:
void whatever(int a) {
a = 5;
}
void someMethod() {
int foo;
foo = 3;
whatever(foo);
System.out.println(foo); // Prints 3, of course, not 5
}
...and in fact, object references (as opposed to objects) are primitives.
...should I declare a new string array or can I safely re-use same array that was holding the unfiltered array to hold filtered array
You can safely re-use it if that's appropriate within the scope of your function. It may be more appropriate to declare a new variable (e.g., filteredThingy), but that's a matter of style and will depend on the situation.
You probably can by it is very bad style and is very error prone and is very unsafe for future modifications.
Here is the example.
public void foo(String[] args) {
// do something with array.
args = new String[] {"a", "b"}; // reuse of the array.
// more code.
for (Sring s : args) {
// what will this loop get"?
// The answer is: a, b
// but will you remember this fact in a month if "more code" above is 50 lines long?
}
}
Passing objects is essentially passing references. E.g., your array will only exist in one place in memory when passing it between functions. Here's a runnable example illustrating that.
If you like you can reuse the same array in your routine. Note that changes made to that array will be visible to all objects sharing the same reference to that array. If that's not desirable then you must declare a new array.
String parentArray = {"S","B","R"};
// no need to use new operator to hold subSetArray.
String subSetArray = returnSubSet(parent);
public String[] returnSubSet(String[] _parent)
{
return Arrays.copyOfRange(_parent,1,2);
}
, when I pass a variable like array to
a function does it creates a new space
for the array in the heap each time I
pass it as parameter to further
functions or just it uses the same
space in the heap & just passes the
reference?
Answer
1. Object in Java are Pass by reference by value
2. when you pass an array to a function , a _parent variable will be created in stack and it points to the same Array Object in heap.
UPDATES: Primitive example
int global_scope_variable=10;
setValue(global_scope_variable);
public void setValue(int val)
{
// val is visible only within this method.
System.out.println(val); // output is 10
val=20;
System.out.println(val); // output is 20
System.out.println(global_scope_variable); // output is 10
}

How to find length of a string array?

I am having a problem with the following lines where car is a String array which has not been initialized/has no elements.
String car [];
System.out.println(car.length);
What is a possible solution?
Since car has not been initialized, it has no length, its value is null. However, the compiler won't even allow you to compile that code as is, throwing the following error: variable car might not have been initialized.
You need to initialize it first, and then you can use .length:
String car[] = new String[] { "BMW", "Bentley" };
System.out.println(car.length);
If you need to initialize an empty array, you can use the following:
String car[] = new String[] { }; // or simply String car[] = { };
System.out.println(car.length);
If you need to initialize it with a specific size, in order to fill certain positions, you can use the following:
String car[] = new String[3]; // initialize a String[] with length 3
System.out.println(car.length); // 3
car[0] = "BMW";
System.out.println(car.length); // 3
However, I'd recommend that you use a List instead, if you intend to add elements to it:
List<String> cars = new ArrayList<String>();
System.out.println(cars.size()); // 0
cars.add("BMW");
System.out.println(cars.size()); // 1
Well, in this case the car variable will be null, so dereferencing it (as you do when you access car.length) will throw a NullPointerException.
In fact, you can't access that variable at all until some value has definitely been assigned to it - otherwise the compiler will complain that "variable car might not have been initialized".
What is it you're trying to do here (it's not clear to me exactly what "solution" you're looking for)?
String car [];
is a reference to an array of String-s. You can't see a length because there is no array there!
This won't work. You first have to initialize the array. So far, you only have a String[] reference, pointing to null.
When you try to read the length member, what you actually do is null.length, which results in a NullPointerException.
Since you haven't initialized car yet so it has no existence in JVM(Java Virtual Machine) so you have to initialize it first.
For instance :
car = new String{"Porsche","Lamborghini"};
Now your code will run fine.
INPUT:
String car [];
car = new String{"Porsche","Lamborghini"};
System.out.println(car.length);
OUTPUT:
2
As all the above answers have suggested it will throw a NullPointerException.
Please initialise it with some value(s) and then you can use the length property correctly. For example:
String[] str = { "plastic", "paper", "use", "throw" };
System.out.println("Length is:::" + str.length);
The array 'str' is now defined, and so it's length also has a defined value.
I think you are looking for this
String[] car = new String[10];
int size = car.length;
In Java, we declare a String of arrays (eg. car) as
String []car;
String car[];
We create the array using new operator and by specifying its type:-
String []car=new String[];
String car[]=new String[];
This assigns a reference, to an array of Strings, to car.
You can also create the array by initializing it:-
String []car={"Sedan","SUV","Hatchback","Convertible"};
Since you haven't initialized an array and you're trying to access it, a NullPointerException is thrown.

Which object will be garbage collected?

I wish to confirm which scenario will cause a Garbage Collection on the object myObj:
Scenario 1
ArrayList arList = new ArrayList();
while(someCondition)
{
myObj = new MyObect(); // a custom object
arList.add(myObj);
}
Scenario 2
ArrayList arList = new ArrayList();
while(someCondition)
{
myObj = new MyObect(); // a custom object
arList.add(myObj);
myObj=null;
}
Does explicitly setting an object as null improves garbage collection behavior or will be it same when I reset the object using the new constructor ?
You don't specify the scope of myObj and its important. If its a local variable it almost certainly doesn't matter. If its an instance variable then that could be a long-lived and unnecessary reference in which case setting to null will be useful.
Update: given the updated information that myObj is local to the method, it will be of zero value to set it to null at the end of each iteration of the loop. Consider this example:
public void process(String text) {
String[] lines = text.split("\n");
List<MyObject> list = new ArrayList<MyObject>();
Object myObj;
for (String line : lines) {
myObj = new MyObject(line);
list.add(myObj);
// 1. set myObj = null here
}
list = null; // 2
// 3. do some other stuff
}
public class MyObject {
private final String line;
public MyObject(String line) {
this.line = line;
}
}
Now in this example, let's say that at step 3, it took a long time. Say 10 minutes. During that 10 minutes myObj is pointing to the last line processed. Doesn't sound like a problem? Well it could be. The way substrings work in Java is that they reference the original string. So if you do:
String s = ... // 100 megabytes
String s2 = s.substring(100, 101);
you're actually keeping the entire 100MB in memory because s2 references s.
So in the function I have above, myObj references a line which references the entire file. Changing step 1 to myObj = null; would actually help that because this reference is preventing the object being garbage collected.
Note: step 2 is important here because if you didn't nullify the list all the references would exist anyway.
You just need to think about how references work. An object won't be garbage collected while a reference to it exists. This means clearing long-lived references and keeping variables scoped as tightly as possible. The correct solution for the above is:
for (String line : lines) {
Object myObj = new MyObject(line);
...
}
and then myObj is scoped inside the loop so as soon as the loop ends or another iteration begins it has gone out of scope, which is much better.
Setting it to null will have no effect, since the object is still reachable via arList.
That is, your MyObect instances will live at least as long as arList.
EDIT: Based on your comment, it does sound like myObj is longer-lived. In that case, set it to null after the end of your loop.
I think that this is the root of your misunderstanding.
hmm.. but I don't wish to keep 2 copies of myObj , one in arList and one in the original variable. How can I flush myObj once I add it to arLsit ?
You do NOT "keep two copies of myObj". In your examples, there is only ever one "copy" of each MyObject instance created by the loop. The sequence is:
You create a MyObject instance, assigning its reference to myObj.
You add the reference to the instance to the ArrayList that arList refers to.
You assign null to the reference in myObj.
Note that adding the reference to the list does NOT create a copy of the MyObject instance. It simply means that that you have the reference in two places instead of
one. And when you assign the null you once again have the reference in just one place.
The other thing to note is that assigning null to something will never CAUSE the garbage collector to run. All it does is to (explicitly) remove a potential copy of a reference from consideration the next time the garbage collector is run.
Finally, if we assume that the scoping is as follows, then the line C will have no discernible effect ... unless either line A or line B triggers a garbage collection.
{
MyObject myObj;
ArrayList arList = new ArrayList();
while (someCondition) { // A
myObj = new MyObect(); // B
arList.add(myObj);
myObj = null; // C
}
}
Because it is in a while, myObj is always overwritten (the reference). So in Scenario 1 only one object (the last added in arList) will not be null.
It would be better if you declare it in the while statement:
while(someCondition)
{
MyObect myObj = new MyObect(); // a custom object
arList.add(myObj);
}

Categories

Resources