Like the code shows, as variable x is substituted to list, when the new instance of ListNode is substituted to x.next, it is reflected on both x and list(refer to the comment 1). I think this is because x refers to list.
However, when the new instance is substituted to x, it is reflected on only x, not list(refer to the comment 2).
Could you explain why this happens?
public class Sample {
public static void main(final String[] args) {
final ListNode list = new ListNode(0, null);
ListNode x = list;
//1.ListNode new instance is substituted for both x and list as x refers to list
x.next = new ListNode(1, null);
//2.ListNode new instance is substituted only for x, not list
x = new ListNode(1, null);
}
}
class ListNode {
int data;
ListNode next;
ListNode(final int data, final ListNode next) {
this.data = data;
this.next = next;
}
}
https://github.com/indrabasak/Books/blob/master/Head%20First%20Java%2C%202nd%20Edition.pdf
Read chapter 3 "Primitives and references" from this book. Your life will become much easier.
Unlike other languages like C++, most Java variables (except primitives) are references to Objects. So, after:
ListNode x = list;
both x and list reference the same object (x == list). Any modification you'll do (like changing the x.next field) will apply to both variables.
However, you can always change the object x is referencing (but not list, since it is final) and you do it with:
x = new ListNode(1, null);
After that x != list.
You can test with a primitive type (like int) to see what changes.
Related
I have the following class:
class Node<T extends Comparable<T>> {
and this is the constructor am using:
Node(T data, int h) {
this.tower = new ArrayList<Node<T>>(Collections.nCopies(h, data));
this.data = data;
}
Why is it giving me the following error:
The constructor ArrayList<Node<T>>(Collections.nCopies(h, data)) is undefined
You are building an ArrayList that is meant to contain Node<T> but you are supplying to the constructor a List<T> (and not List<Node<T>>), you probably want
Node(T data, int h) {
this.tower = new ArrayList<Node<T>>(Collections.nCopies(h, new Node<T>(data)));
this.data = data;
}
Collections.nCopies is probably not what you want, as it will not actually create copies of the object itself, but only of the reference to it. Which means, changing the value of one of these nodes changes all, which is likely not what you want. If it isn't, then here's your solution:
Node(T data, int h) {
this.tower =
IntStream.range(0, h) // these two lines do
.mapToObj((ignore)->data) // what Collections.nCopies does
.map(Node::new) // but here we're creating unique objects
.collect(Collectors.toList());
this.data = data;
}
This way, each node is a separate object, but they all have the same initial value.
I know that java does not support pass by reference. But still is there any possibility to implement it in any other ways if not directly as in C/C++?
Nope. You can't do it. It's not something you can "implement". It's a fundamental aspect of the language.
If what you're trying to do is to have a "reference" to a primitive value which you can pass around, so you can modify the primitive's value inside methods and have the changes be visible outside said methods...
... just pass an array containing the primitive, like this:
// By value
int value = 1;
changeValue(value); // changes value to 5
System.out.println(value); // prints 1
// By "reference"
int[] reference = {1};
changeValue(reference); // changes value inside "reference" to 5
System.out.println(reference[0]); // prints 5
// Methods
void changeValue(int value) { value = 5; }
void changeValue(int[] reference) { reference[0] = 5; }
Bear in mind that this is not "pass by reference". Java is not passing a reference to the value, Java is passing the value of the array's reference.
You can read Is Java "pass-by-reference" or "pass-by-value"? for a better discussion about this.
Pass-by-value was by design: f(x) will maybe alter the internals of the value of x, but x will not get another value. _For instance you cannot assign null to x inside f, using the formal parameter of f.
There is the possibility of in-out parameters which in java can be done by the function's result:
insertInNodes is such a method.
public class SortedLinkedList<T extends Comparable<T>> {
private static class Node { ... }
Node head;
int size;
public void insert(T data) {
head = insertInNodes(head, data);
}
private Node insertInNodes(Node node, T data) {
if (node == null || data.compareTo(node.data) < 0) {
++size;
return new Node(data, node);
}
if (data.compareTo(node.data) > 0) {
node.next = insertInNodes(node.next, data);
}
return node;
}
}
Pass-by-reference needs to either fake it: pass a container object and then the component is actually a reference. For instance an array with one element or a wrapper class like Atomic<String>.
Pass-by-reference in a more pure form could be realized by passing a getter and setter of the wanted "variable."
public void insert(T data) {
insertInNodes(this::getHead, this::setHead, data);
// Or insertInNodes(() -> head, (n) -> head = n, data);
}
private void insertInNodes(Supplier<Node> getter, Consumer<Node> setter, T data) {
if (getter.get() == null || data.compareTo(getter.get().data) < 0) {
++size;
setter.apply(new Node(data, getter.get()));
}
if (data.compareTo(node.data) > 0) {
// insertInNodes(() -> node.next, (n) -> node.next = n, data);
// or
insertInNodes(node::setNext, node::getNext, data);
}
return node;
}
Is this usable? No, only in specific use-cases.
I am pretty new to java and getting confused with the below code:
public class NewNode {
NewNode next = null;
int data;
public NewNode(int data) {
this.data = data;
}
public void addToNode(int data){
NewNode n = this;
System.out.println(n);
NewNode newlyCreated = new NewNode(data);
}
}
but even after changing the addToNode method as below:
public void addToNode(int data){
NewNode newlyCreated = new NewNode(data);
NewNode n = this;
System.out.println(n);
}
The output of n doesn't change . If,this keyword refers to the current instance of the object then shouldn't newlyCreatedNode be the output in the second scenario.Please help....
According to the doc tutorials:
Within an instance method or a constructor, this is a reference to the current object — the object whose method or constructor is being called.
So in both example this refers to the object you call addToNode() on. The fact that you create an object within the method is irrelevant. So:
public void addToNode(int data){
NewNode n = this; //Refers to the object this method is called on
System.out.println(n);
NewNode newlyCreated = new NewNode(data); //Creates a random object
}
public void addToNode(int data){
NewNode newlyCreated = new NewNode(data); //Creates a random object
NewNode n = this; //Refers to the object this method is called on
System.out.println(n);
}
this is the current instance i.e. the instance that invokes the addNode method.
Thus when you create a new Node by NewNode newlyCreated = new NewNode(data); it just creates a new Node locally. The current instance(i.e. this) remains the same.
Your output will change if you do this.data = data i.e. changing the data field of current instance
EDIT: Also you need to override the toString method to print NewNode otherwise it'll print default Object's toString method
Okay, take a look at this piece of code. Let me try to give you a simpler example.
Assume that we have a class like this:
class A {
int data;
void printData() {
System.out.println(this.data);
}
}
And then you create two instances of A like this:
A a1 = new A(); a1.data = 10;
A a2 = new A(); a2.data = 12;
So there are now two objects a1 and a2 which are of the A type.
Now let's call the printData() method on them. How would you do it?
a1.printData();
a2.printData();
Now look at the first print call, it is happening on the a1 object. So now control goes into the printData method, where the this will resolve to a1, so this.data will be same as a1.data from outside.
Now in the second call, yes you get it right. It is being invoked on a2 object, so inside the method printData, a2 will be assigned to this.
This is what it means when they say that this resolves to the current object.
Got it now?
I have written a code -
// Node Class
class aNode {
// Node Contents
int NodeInt;
char NodeChar;
// constructor
aNode() {
}
aNode(int x, char y) {
NodeInt = x;
NodeChar = y;
}
}
class MainClass {
static aNode node = new aNode();
public static void main(String[] args) {
node = null;
function(node);
if (node == null) {
System.out.println("Node is null");
}
}
static void function(aNode x) {
if (x == null) {
System.out.println("Node is null");
}
x = new aNode(5, 'c');
System.out.println(x.NodeInt);
System.out.println(x.NodeChar);
}
}
I expected the output to be -
Node is null
5
c
but when the program returns to main, the value of node is set to null again. So I get the output to be -
Node is null
5
c
Node is null
Please help me modify the code to get desired output. Any help will be appreciated!
You should know, that aNode node and aNode x are references to different objects. It is one of Java features - passing only by value. It mean, that when you are calling
function(node);
you are not passing node reference to method function(...), you are creating new reference to the same object. But in line
x = new aNode(5,'c');
you are setting reference x to new object. So, node still references to null and x references to new aNode.
To get more about passing params in Java, read next article.
Reference data type parameters, such as objects, are also passed into
methods by value. This means that when the method returns, the
passed-in reference still references the same object as before.
However, the values of the object's fields can be changed in the
method, if they have the proper access level.
Real pass-by-reference is impossible in Java. Java passes everything by value, including references..
So you have to slightly change your code to get the desired output:
class aNode{
//Node Contents
int NodeInt;
char NodeChar;
//constructor
aNode(){
}
aNode(int x, char y){
NodeInt = x;
NodeChar = y;
}
}
class JavaApplication8{
static aNode node = new aNode();
public static void main(String[] args){
node = null;
node=function(node);
if(node == null){
System.out.println("Node is null");
}
}
static aNode function(aNode x){
if(x == null)
{
System.out.println("Node is null");
}
x = new aNode(5,'c');
System.out.println(x.NodeInt);
System.out.println(x.NodeChar);
return x;
}
}
Output:
Node is null
5
c
You are passing a static object, but in the method function(), you are not changing the value of object node. You are changing the value of other object only. So in main, the value of node s null only.
In general, this is because Java passes a copy of the reference to the aNode object to your method. Changing this reference will not change the original reference.
Inside function(), x is simply a local variable. When you reassign a reference in Java, you are modifying the content of the reference itself, not the one of the referred object. There's no way in Java to pass the address-of an object. If you want such a behavior, you can try with a generic class like Wrapper
What is a copy constructor?
Can someone share a small example that can be helpful to understand along with defensive copying principle?
Here's a good example:
class Point {
final int x;
final int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
Point(Point p) {
this(p.x, p.y);
}
}
Note how the constructor Point(Point p) takes a Point and makes a copy of it - that's a copy constructor.
This is a defensive copy because the original Point is protected from change by taking a copy of it.
So now:
// A simple point.
Point p1 = new Point(3,42);
// A new point at the same place as p1 but a completely different object.
Point p2 = new Point(p1);
Note that this is not necessarily the correct way of creating objects. It is, however, a good way of creating objects that ensures that you never have two references to the same object by accident. Clearly this is only a good thing if that is what you want to achieve.
Copy constructors one often sees in C++ where they are needed for partly hidden, automatically invoked operations.
java java.awt.Point and Rectangle come to mind; also very old, mutable objects.
By using immutable objects, like String, or BigDecimal, simply assigning the object reference will do. In fact, due to the early phase of Java after C++, there still is a
silly copy constructor in String:
public class Recipe {
List<Ingredient> ingredients;
public Recipe() {
ingredients = new ArrayList<Ingredient>();
}
/** Copy constructor */
public Recipe(Recipe other) {
// Not sharing: ingredients = other.ingredients;
ingredients = new ArrayList<>(other.ingredients);
}
public List<Ingredient> getIngredients() {
// Defensive copy, so others cannot change this instance.
return new ArrayList<Ingredient>(ingredients);
// Often could do:
// return Collections.immutableList(ingredients);
}
}
On request
Leaking class with copy constructor:
public class Wrong {
private final List<String> list;
public Wrong(List<String> list) {
this.list = list; // Error: now shares list object with caller.
}
/** Copy constructor */
public Wrong(Wrong wrong) {
this.list = wrong.list; // Error: now shares list object with caller.
}
public List<String> getList() {
return list; // Error: now shares list object with caller.
}
public void clear() {
list.clear();
}
}
Correct class with copy constructor:
public class Right {
private final List<String> list;
public Right(List<String> list) {
this.list = new ArrayList<>(list);
}
public Right(Right right) {
this.list = new ArrayList<>(right.list);
}
public List<String> getList() {
return new ArrayList<>(list);
}
public List<String> getListForReading() {
return Collections.unmodifiableList(list);
}
public void clear() {
list.clear();
}
}
With testing code:
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
Collections.addAll(list1, "a", "b", "c", "d", "e");
Wrong w1 = new Wrong(list1);
list1.remove(0);
System.out.printf("The first element of w1 is %s.%n", w1.getList().get(0)); // "b"
Wrong w2 = new Wrong(w1);
w2.clear();
System.out.printf("Size of list1 %d, w1 %d, w2 %d.%n",
list1.size(), w1.getList().size(), w2.getList().size());
List<String> list2 = new ArrayList<>();
Collections.addAll(list2, "a", "b", "c", "d", "e");
Right r1 = new Right(list2);
list2.remove(0);
System.out.printf("The first element of r1 is %s.%n", r1.getList().get(0)); // "a"
Right r2 = new Right(r1);
r2.clear();
System.out.printf("Size of list2 %d, r1 %d, r2 %d.%n",
list2.size(), r1.getList().size(), r2.getList().size());
}
Which gives:
The first element of w1 is b.
Size of list1 0, w1 0, w2 0.
The first element of r1 is a.
Size of list2 4, r1 5, r2 0.
Copy constructor in java can be used when you need to clone an object
class Copy {
int a;
int b;
public Copy(Copy c1) {
a=c1.a;
b=c1.b;
}
}
In java when you give Copy c2=c1; simply creates a reference to the original object and not the copy so you need to manually copy the object values.
See this:
Why doesn't Java have a copy constructor?
Copy Constructor in Java
This is where you create a new object, by passing an old object, copying its values.
Color copiedColor = new Color(oldColor);
instead of :
Color copiedColor = new Color(oldColor.getRed(),
oldColor.getGreen(), oldColor.getBlue());
A copy constructor is used to create a new object using the values of an existing object.
One possible use case is to protect original object from being modified while the copied object can be used to work upon.
public class Person
{
private String name;
private int age;
private int height;
/**
* Copy constructor which creates a Person object identical to p.
*/
public person(Person p)
{
person = p.person;
age = p.age;
height = p.height;
}
.
.
.
}
Related to defensive copy here is a good read