This was a question on an exam. Luckily I picked the right answer, but I still can't see why it's right.
Consider this program:
class D {
protected C c;
public D(C c) {
this.c = new C(c);
}
public C getC() {
return c;
}
public void setC(C c) {
this.c = c;
}
}
class C {
protected String s;
public C(String s) {
this.s = s;
}
public C(C c) {
this(c.s);
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public static void main(String[] args) {
C c1 = new C("1");
C c2 = new C("2");
D[] d = {
new D(c1), new D(c1), new D(c2), new D(c2)
};
d[0] = d[3];
c1.setS("3");
String r = "";
for (D i: d) {
r += i.getC().getS();
}
System.out.println(r);
}
}
It'll print 2122. I would expect 2322 however (I'm clearly wrong when you run the code). My reasoning behind that:
In the third line of the main method, four instances of D get initialized.
The constructor of D makes a new instance of C. An instance of C has a String variable which points somewhere to a spot in the memory. Now the instance variable c, let's call it c3, of the object in d[1] has a instance variable (type String), let's call it s3, pointing to the same memory as the String s1, variable of c1.
So when we change s1, I'd expect the value of s3 also to change, since it's pointing to the same spot in the memory.
On a side note, if you change the constructor of D, see below, you'll get 2322 instead. Which I'd expect, since now the variable c3 in d[1] is pointing directly towards the memory location of c1.
public D(C c) {
this.c = c;
}
My thoughts so far on the explanation (could be wrong):
When initializing the instance variable s1/s3, new String objects get made (so far I assumed they were pointing towards "1" in the String pool, since the constructor of C makes it look that way)
When changing s1, it's pointer will be redirected towards "3" in the String pool. Rather than "1" becoming "3" in the pool.
Could anyone explain this behaviour? What are the errors in my (faulty) reasoning?
This is not related to String pooling at all. Main answer: Is Java "pass-by-reference" or "pass-by-value"?
That's because D creates a new instance of C based on C#c. This mean that the instance of D#c is not the same instance as parameter C passed in constructor D, thus modifying that instance won't affect the current instance in D#c.
Re explaining all this in nice terms.
Here's what you're testing:
class Surprise {
String item;
public Surprise(String item) {
this.item = item;
}
//this is called copy constructor
//because you receive an object from the same class
//and copy the values of the fields into the current instance
//this way you can have a "copy" of the object sent as parameter
//and these two object references are not tied by any mean
public Surprise(Surprise another) {
//here you just copy the value of the object reference of another#item
//into this#item
this.item = another.item;
}
}
class Box {
Surprise surprise;
public Box(Surprise surprise) {
//here you create a totally new instance of Surprise
//that is not tied to the parameter surprise by any mean
this.surprise = new Surprise(surprise);
}
public static void main(String[] args) {
Surprise surprise1 = new Surprise("1");
Surprise surprise2 = new Surprise("2");
Box[] boxes = {
new Box(surprise1),
new Box(surprise1),
new Box(surprise2),
new Box(surprise2)
};
boxes[0] = boxes[3];
//you update surprise1 state
//but the state of Box#surprise in the boxes that used surprise1
//won't get affected because it is not the same object reference
surprise1.item = "3";
//print everything...
System.out.println("Boxes full of surprises");
//this code does the same as the printing above
for (Box box : boxes) {
System.out.print(box.surprise.item);
}
System.out.println();
}
}
Related
I am trying to create an alias for a object variable in Java so that I can change one and have it affect the other. For example, in this snippet, I expect "b" to be printed out. Instead I get "a".
String s = new String("a");
String t = s;
t = new String("b");
System.out.println(s); // Prints "a".
I thought that non-primitive types in Java were able to be referenced and "tied" together like this.
No, it never works like that. Variables, fields etc. cannot be "bound" in Java.
Your variables can contain "a link to a value" in a variable, but you cannot have a "link to another variable".
This means that in your case s and t initially hold the link to the same value, but they don't know about each other. When you assign a new string to t, the value of the old string does not change (and s still references the old value). It's just the reference in `t
String is not good example, because this is immutable. You have to look at using object instances and object reference. One object instance could have multiple object references.
class Decorator {
private String str;
public Decorator(String str) {
this.str = str;
}
public void setStr(String str) {
this.str = str;
}
public String getStr() {
return str;
}
}
Decorator s = new Decorator("a"); // s - is a reference to Decorator
System.out.println(s.getStr()); // prints "a"
Decorator t = s; // t - is an another reference to existed Decorator (two references for one instance)
t.setStr("b");
// references s and t both point to one Decorator instance
System.out.println(s.getStr()); // prints "b"
System.out.println(t.getStr()); // prints "b"
You might be looking for something like this:
StringWrapper sw = new StringWrapper(new String("a"));
StringWrapper tw = sw;
tw.setS(new String("b"));
System.out.println(sw.getS()); // Prints b
class StringWrapper {
private String s;
public StringWrapper(String s) {
this.s = s;
}
private String getS() {
return s;
}
private void setS(String s) {
this.s = s;
}
}
(You can replace new StringWrapper(new String("a")) with new StringWrapper("a"). I added new String so it looks more like your example. Same goes for new String("b").)
Upcasting is allowed in Java, however downcasting gives a compile error.
The compile error can be removed by adding a cast but would anyway break at the runtime.
In this case why Java allows downcasting if it cannot be executed at the runtime?
Is there any practical use for this concept?
public class demo {
public static void main(String a[]) {
B b = (B) new A(); // compiles with the cast,
// but runtime exception - java.lang.ClassCastException
}
}
class A {
public void draw() {
System.out.println("1");
}
public void draw1() {
System.out.println("2");
}
}
class B extends A {
public void draw() {
System.out.println("3");
}
public void draw2() {
System.out.println("4");
}
}
Downcasting is allowed when there is a possibility that it succeeds at run time:
Object o = getSomeObject(),
String s = (String) o; // this is allowed because o could reference a String
In some cases this will not succeed:
Object o = new Object();
String s = (String) o; // this will fail at runtime, because o doesn't reference a String
When a cast (such as this last one) fails at runtime a ClassCastException will be thrown.
In other cases it will work:
Object o = "a String";
String s = (String) o; // this will work, since o references a String
Note that some casts will be disallowed at compile time, because they will never succeed at all:
Integer i = getSomeInteger();
String s = (String) i; // the compiler will not allow this, since i can never reference a String.
Using your example, you could do:
public void doit(A a) {
if(a instanceof B) {
// needs to cast to B to access draw2 which isn't present in A
// note that this is probably not a good OO-design, but that would
// be out-of-scope for this discussion :)
((B)a).draw2();
}
a.draw();
}
I believe this applies to all statically typed languages:
String s = "some string";
Object o = s; // ok
String x = o; // gives compile-time error, o is not neccessarily a string
String x = (String)o; // ok compile-time, but might give a runtime exception if o is not infact a String
The typecast effectively says: assume this is a reference to the cast class and use it as such. Now, lets say o is really an Integer, assuming this is a String makes no sense and will give unexpected results, thus there needs to be a runtime check and an exception to notify the runtime environment that something is wrong.
In practical use, you can write code working on a more general class, but cast it to a subclass if you know what subclass it is and need to treat it as such. A typical example is overriding Object.equals(). Assume we have a class for Car:
#Override
boolean equals(Object o) {
if(!(o instanceof Car)) return false;
Car other = (Car)o;
// compare this to other and return
}
We can all see that the code you provided won't work at run time. That's because we know that the expression new A() can never be an object of type B.
But that's not how the compiler sees it. By the time the compiler is checking whether the cast is allowed, it just sees this:
variable_of_type_B = (B)expression_of_type_A;
And as others have demonstrated, that sort of cast is perfectly legal. The expression on the right could very well evaluate to an object of type B. The compiler sees that A and B have a subtype relation, so with the "expression" view of the code, the cast might work.
The compiler does not consider the special case when it knows exactly what object type expression_of_type_A will really have. It just sees the static type as A and considers the dynamic type could be A or any descendant of A, including B.
In this case why Java allows downcasting if it cannot be executed at the runtime?
I believe this is because there is no way for the compiler to know at compile-time if the cast will succeed or not. For your example, it's simple to see that the cast will fail, but there are other times where it is not so clear.
For instance, imagine that types B, C, and D all extend type A, and then a method public A getSomeA() returns an instance of either B, C or D depending on a randomly generated number. The compiler cannot know which exact run-time type will be returned by this method, so if you later cast the results to B, there is no way to know if the cast will succeed (or fail). Therefore the compiler has to assume casts will succeed.
# Original Poster - see inline comments.
public class demo
{
public static void main(String a[])
{
B b = (B) new A(); // compiles with the cast, but runtime exception - java.lang.ClassCastException
//- A subclass variable cannot hold a reference to a superclass variable. so, the above statement will not work.
//For downcast, what you need is a superclass ref containing a subclass object.
A superClassRef = new B();//just for the sake of illustration
B subClassRef = (B)superClassRef; // Valid downcast.
}
}
class A
{
public void draw()
{
System.out.println("1");
}
public void draw1()
{
System.out.println("2");
}
}
class B extends A
{
public void draw()
{
System.out.println("3");
}
public void draw2()
{
System.out.println("4");
}
}
Downcast works in the case when we are dealing with an upcasted object.
Upcasting:
int intValue = 10;
Object objValue = (Object) intvalue;
So now this objValue variable can always be downcasted to int because the object which was cast is an Integer,
int oldIntValue = (Integer) objValue;
// can be done
but because objValue is an Object it cannot be cast to String because int cannot be cast to String.
Downcasting is very useful in the following code snippet I use this all the time. Thus proving that downcasting is useful.
private static String printAll(LinkedList c)
{
Object arr[]=c.toArray();
String list_string="";
for(int i=0;i<c.size();i++)
{
String mn=(String)arr[i];
list_string+=(mn);
}
return list_string;
}
I store String in the Linked List.
When I retrieve the elements of Linked List, Objects are returned. To access the elements as Strings(or any other Class Objects), downcasting helps me.
Java allows us to compile downcast code trusting us that we are doing the wrong thing.
Still if humans make a mistake, it is caught at runtime.
Consider the below example
public class ClastingDemo {
/**
* #param args
*/
public static void main(String[] args) {
AOne obj = new Bone();
((Bone) obj).method2();
}
}
class AOne {
public void method1() {
System.out.println("this is superclass");
}
}
class Bone extends AOne {
public void method2() {
System.out.println("this is subclass");
}
}
here we create the object of subclass Bone and assigned it to super class AOne reference and now superclass reference does not know
about the method method2 in the subclass i.e Bone during compile time.therefore we need to downcast this reference of superclass to subclass reference so as the resultant reference can know about the presence of methods in the subclass i.e Bone
To do downcasting in Java, and avoid run-time exceptions, take a reference of the following code:
if (animal instanceof Dog) {
Dog dogObject = (Dog) animal;
}
Here, Animal is the parent class and Dog is the child class.
instanceof is a keyword that is used for checking if a reference variable is containing a given type of object reference or not.
Downcasting transformation of objects is not possible.
Only
DownCasting1 _downCasting1 = (DownCasting1)((DownCasting2)downCasting1);
is posible
class DownCasting0 {
public int qwe() {
System.out.println("DownCasting0");
return -0;
}
}
class DownCasting1 extends DownCasting0 {
public int qwe1() {
System.out.println("DownCasting1");
return -1;
}
}
class DownCasting2 extends DownCasting1 {
public int qwe2() {
System.out.println("DownCasting2");
return -2;
}
}
public class DownCasting {
public static void main(String[] args) {
try {
DownCasting0 downCasting0 = new DownCasting0();
DownCasting1 downCasting1 = new DownCasting1();
DownCasting2 downCasting2 = new DownCasting2();
DownCasting0 a1 = (DownCasting0) downCasting2;
a1.qwe(); //good
System.out.println(downCasting0 instanceof DownCasting2); //false
System.out.println(downCasting1 instanceof DownCasting2); //false
System.out.println(downCasting0 instanceof DownCasting1); //false
DownCasting2 _downCasting1= (DownCasting2)downCasting1; //good
DownCasting1 __downCasting1 = (DownCasting1)_downCasting1; //good
DownCasting2 a3 = (DownCasting2) downCasting0; // java.lang.ClassCastException
if(downCasting0 instanceof DownCasting2){ //false
DownCasting2 a2 = (DownCasting2) downCasting0;
a2.qwe(); //error
}
byte b1 = 127;
short b2 =32_767;
int b3 = 2_147_483_647;
// long _b4 = 9_223_372_036_854_775_807; //int large number max 2_147_483_647
long b4 = 9_223_372_036_854_775_807L;
// float _b5 = 3.4e+038; //double default
float b5 = 3.4e+038F; //Sufficient for storing 6 to 7 decimal digits
double b6 = 1.7e+038;
double b7 = 1.7e+038D; //Sufficient for storing 15 decimal digits
long c1 = b3;
int c2 = (int)b4;
//int 4 bytes Stores whole numbers from -2_147_483_648 to 2_147_483_647
//float 4 bytes Stores fractional numbers from 3.4e−038 to 3.4e+038. Sufficient for storing 6 to 7 decimal digits
float c3 = b3; //logic error
double c4 = b4; //logic error
} catch (Throwable e) {
e.printStackTrace();
}
}
}
I will tell you why this happened. First of all you have to understand how JVM supports when we assign parent class into the child class using downcasting, because of reference . For example consider in the following code.
A is the super type any class that extends from it and can store the reference B class.
A a =new B();
When you assign a reference variable into the child class jvm will understand that since A can store the reference of B class that is why you can do it.
B b=(B)b;
The reason which is called compile time error and why you couldn't directly assign Parent class into the Child class because there is not any extends relationship. Note that casting only occurring with the key which is called extends, that is why you receive the compile time error.
Another reason which is called ClassCastException by the runtime because of jvm it directly accept the rule which is okay I accept that it is true but jvm after that will understand that by the runtime it is not store any referance of Child class when code was writing by the programmer who write coding in the syntax .
I'm using three objects: StringBuilder, Integer, and testobject - that are passed to a method to change its state.
As expected, the StringBuilder and testobject points to the same object and the state is change but it does not work for Integer object.
class testobject{
int x = 1;
}
public class test{
public static void main(String[] args){
StringBuilder s1 = new StringBuilder("String");
go(s1);
System.out.println(s1);
Integer s2 = new Integer("20");
go1(s2);
System.out.println(s2);
testobject s3 = new testobject();
go2(s3);
System.out.println(s3.x);
}
static void go(StringBuilder s1){
s1.append("Builder");
}
static void go1(Integer s2){
s2 = 1;
}
static void go2(testobject s3){
s3.x = 5;
}
Result:
StringBuilder
20
5
ExpectedResult:
StringBuilder
1
5
Look at your three methods:
static void go(StringBuilder s1){
s1.append("Builder");
}
static void go1(Integer s2){
s2 = 1;
}
static void go2(testobject s3){
s3.x = 5;
}
In go and go2, you're making a modification to the object that the parameter value refers to.
In go1, you're changing the value of the parameter variable itself. That's very different, and because Java always uses pass-by-value, that change isn't seen by the caller.
It's important to understand that objects aren't passed to the methods at all. Instead, references are. The value of s1, s2 and s3 are all references. If you think of the variables as like pieces of paper, each piece of paper has a house address on it, which was copied from a piece of paper declared in main.
The method bodies of go and go2 are like visiting the house whose address is on the piece of paper, and painting the front door. If you then visit the houses using the original pieces of paper, you still see the new colours on the front doors.
The method body of go1 is like scribbling out the address written on the piece of paper, and writing a new one on there instead. That doesn't make any change to a house, nor does it change the original piece of paper.
If the argument you want to pass is an object instead a of primitive type, then Java treats pass by object as pass by value, because Java supports a pass-by-value concept.
Here a and p are the same reference:
public class ObjPass {
int value;
public static void main(String[] args) {
ObjPass p = new ObjPass();
p.value = 5;
System.out.println("Before calling: " + p.value);
increment(p);
System.out.println("After calling: " + p.value);
}
public static void increment(ObjPass a){
a.value++;
}
}
Output:
Before calling: 5
After calling: 6
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
ArrayList<String> constraints_list=new ArrayList<String>();
public void setConstraints(ArrayList<String> c)
{
c = constraints_list;
constr = true;
}
i want to make ArrayList c to be ArrayList constraint_list...
how to do that?
It's not totally clear to me what you want to do. However, object references are passed by value in Java, so setting the value of c (as in your code) won't work. The typical way to set c from an instance variable is to write a getter rather than a setter:
public ArrayList<String> getConstraints() {
return constraints_list;
}
You can then say:
ArrayList<String> c = getConstraints();
If on the other hand, you are trying to do the opposite (set constraints_list from the passed in parameter), then your assignment is the wrong way round:
public void setConstraints(ArrayList<String> c) {
constraints_list = c;
constr = true;
}
You should also consider whether it's better to make a copy of the list, in which case you could do:
public void setConstraints(ArrayList<String> c) {
constraints_list = new ArrayList<String>(c);
constr = true;
}