I come up with the scenario & can't understand the logic behind it ? I understood the first one only, rest two unable to understand ? Please explain how internally it work?
public class Test {
public static void main(String[] args) {
String s = "Karan";
Object o = "Karan";
System.out.println(s.equals(o)); // True
System.out.println(o.equals(s)); // True
System.out.println(s == o); // True
}
}
String s = "Karan" this is a String object referred by a String reference.
Object o = "Karan" this is a String object referred by an Object reference. Super class can refer to object of sub-class.
For both s.equals(o) and o.equals(s) the underlying objects equal() is called, since the objects are of type String (even if reference 'o' is of type Object) String's equals is called which compares the value of the string which are equal. That is what you got true as result.
s == o compares the object reference of s and o. They were created using double quote which uses the String pool, creates the object once and refers it again. So both s and o are exactly same String object. This makes == return true.
There is a difference between the static type of an object and the dynamic type of a variable.
The static type is the type known at compile time. For Object o = "Karan";, the static type is the one at the left of o, i.e. Object. Now, one could ask why that is the case since at compile-time, it can be inferred that o is a String. Well if we consider something like
Object o;
if (someCondition) {
o = "Karam";
} else {
o = new StringBuffer();
}
then we cannot know whether o is a String or a StringBuffer, thus its static type is Object (since o is defined as Object).
The dynamic type is the type at runtime. In the example above, after the if-statement has been executed, o is either a String or a StringBuffer, but not both and nothing else. In your example, the dynamic type of Object o = "Karan"; is String.
When variables are compared through equals(...), they must have the same dynamic type in order for the comparison to return true (notice that this property is necessary, but not sufficient). Since o in your example is, in fact, a String AND the content is equal to s, s.equals(o) == o.equals(s) == true.
As to why s == o returns true: the question is answered in this post.
Related
This question already has answers here:
Parentheses around data type?
(5 answers)
Closed 7 years ago.
I'm new to Java, and am reading a Java book; at one point it talks about when you may want to override the built in function, equals(). For instance, if an object has a variable ID, and two objects have the same ID, you may want them to be considered to be equal. It gave example code which looks more or less like:
public boolean equals(Object obj) {
if((obj != null) && (obj instanceof myClass)) {
myClass object1 = (myClass)obj;
if(this.ID == object1.ID) {
return true;
}
}
return false;
}
I don't fully understand what's going on in the third line. I'm unsure about why it's necessary and you can't just compare obj.ID and this.ID in the if() statement. My guess is that it's because obj is just declared as a generic object which may not have an ID, so you need to create a new object, object1 which is of the correct class to look at the ID.
Am I correct here? What exactly is going on in that line?
In your code Object obj is a reference to an Object. The code at this point makes no assumptions about which type of Object it is.
When you do
myClass object1 = (myClass) obj;
you are casting the type of the reference to an object which this will either succeed because it is an instance of that type or fail throwing ClassCastException.
This creates a new reference but the underlying object is unchanged by this, nor is it copied.
Note: the obj != null check is redundant as null is not an instanceof of any class, nor does it trigger an exception. i.e.
Object o = null;
boolean b = o instanceof Object; // always false, never throws an exception.
A shorter version of this method could read.
public boolean equals(Object obj) {
if(obj instanceof myClass) {
myClass object1 = (myClass)obj;
return ID == object1.ID;
}
return false;
}
or even
public boolean equals(Object obj) {
return obj instanceof myClass && ID == ((myClass) obj).ID;
}
In Java 8 you could write
public boolean equals(Object obj) {
return Optional.ofNullable(obj)
.filter(o - > o instanceof myClass)
.map(o -> (myClass) o)
.filter(m -> ID == m.ID)
.isPresent();
}
On the 3rd line, no object is being created.
The first thing you need to understand about java is that there are primitives like int, char, double and objects, which are everything else, and objects are always accessed by reference.
So, Object obj is a reference to objects of type Object, and at runtime it will be referring to some object.
Then, further down, when you say myClass object1 you are not creating any object; you are just declaring a variable called object1 which will be referring to objects of type myClass. But there is no object yet.
So, when you say myClass object1 = (myClass)obj; you are assigning the reference obj to the reference object1. And since it would normally be invalid to make an assignment between different types, you are using a type cast (the (myClass) part) to tell the compiler that you know what you are doing, and you are sure that obj will be pointing to an object of type myClass at that point. So, the compiler allows you to make the assignment.
After the assignment, both obj and object1 are pointing to the same object, but the usefulness of object1 now is that you can view this object as an object of type myClass, so you can access its members.
Your guess is almost correct: obj is declared to have type Object and Object can be anything, a String for example, it does not have to have the member named ID, so, you can't just look at it to compare. So, the code you quoted first check if the obj is of the same type (if it isn't, then you know it does not equal), and then (on the line you are asking about) casts it to that type.
I said, your guess was almost correct, because you suggested that a new object of type myClass is created. This is not true. The assignment myClass object1 = (myClass)obj; does not create any new objects, it merely makes a new variable object1 refer to to the same object referred by obj, and tells the compiler that it should now know that that object is actually of type myClass.
Yes. The third line is inside an if statement that says obj instanceof myClass. At that point you know that it is of type myClass. Assuming myClass has an ID like in your code then you know that both objects have ID properties and you can use those for comparison.
Research the term "Object Casting".
the obj instanceof myClass is making sure that obj is the same type as this. Now we know it is safe to cast and Object obj into a myClass object1
The test for null is not needed, because instanceof is false for nulls.
Just use:
if (obj instanceof myClass) {
Otherwise, your code is fine, assuming ID is a primitive (especially, not a String).
Why is second SOP showing output as true here, I was hoping it would display false like first SOP ?
public class reflect1 {
public static void main(String[] args) {
Reflect1A obj1 = new Reflect1A();
Reflect1A obj2 = new Reflect1A();
System.out.println(obj1 == obj2);
Class c1 = obj1.getClass();
Class c2 = obj2.getClass();
System.out.println(c1 == c2);
}
}
class Reflect1A {
}
From the Java Language Specification
The method getClass returns the Class object that represents the class of the object.
A Class object exists for each reference type. It can be used, for
example, to discover the fully qualified name of a class, its members,
its immediate superclass, and any interfaces that it implements.
Since both your objects are of type Reflect1A, they both return the same Class object.
You would get the same object by doing
Class<?> clazz = Class.forName("com.example.Reflect1A")
System.out.println(c1 == clazz); // true
(though this is not necessarily required by all classloaders.)
The values of obj1 and obj2 refer to different objects - when you use == in Java and both operands are references, the result is to compare whether those references refer to the exact same object. In this case you've got two different objects, so the references are not the same.
However, they're both of the same class, so that's why c1 == c2 is true.
The first line prints false because it is a different instance of the same class.
The second line prints true because it is the same class type. There is a obscure gotcha here to be aware of, if you're in a multiple classloader environment, e.g. an application server like JBoss, or OSGI etc, it is possible for two class instances to not be equal
An object is equal (==) only to itself. So clearly both getClass() statements are returning the same Class object
Because obj1 and obj2 are different instances (first check is false) of the same type (class - second check is true).
https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#getClass%28%29
why did you expect to return false?
The operator == compares the references in which the objects are created by default
Obj1 and Obj2 are of same type class Reflect1. For these objects are equal only when compared like this obj1.equal(obj2).
While the class type of obj1 and obj2 are the same == operation will be true.
I am studying Overriding hashCode() and equals(Object obj) methods of Object class.
body of equals(Object obj) method in Object class is :
public boolean equals(Object obj) {
return (this == obj);
}
and hashCode() is native :
public native int hashCode();
I have a class Test with overrided equals(Object obj) and hashCoe() :
public class Test {
public static void main(String[] args){
Test t1 = new Test();
Test t2 = new Test();
System.out.println("t1 toString() : " + t1.toString());
System.out.println("t1, Hex value of hashcode : " + Integer.toHexString(t1.hashCode()));
System.out.println("t2 toString() : " + t2.toString());
System.out.println("t2, Hex value of hashcode : " + Integer.toHexString(t2.hashCode()));
System.out.println(t1.equals(t2));
}
#Override
public int hashCode() {
return 999; //hard coded value is just for testing
}
#Override
public boolean equals(Object obj) {
return (this == obj);
}
}
Output of my Code is :
t1 toString() : demo.Test#3e7
t1, Hex value of hashcode : 3e7
t2 toString() : demo.Test#3e7
t2, Hex value of hashcode : 3e7
false //why it is false
why equals(Object obj) returns false in this case if both objects toString() returns the same reference ID (hashcode) [I am not sure if it compares hashcode or not].
What does == operator actually compare in case of objects?
in this answer, answerer said that == that is, it returns true if and only if both variables refer to the same object, if their references are one and the same.
How does it know that the variables refer to the same object???
How does it know that the variables refer to the same object?
Because the values of the variables are the same references. (Your variables are t1 and t2. The values of those variables are references. Those references are used as a way of navigating to objects, basically.)
Suppose you and I both have pieces of paper with a house's street address on (that's my usual analogy for "variables with references"). How do we check whether they refer to the same house? We see whether the address is the same.
There are some potential twists here, as in some cases the form of the reference may not be the same between two expressions, but that's the basic idea.
(Note that just because I've used "address" in the analogy, that doesn't mean a Java reference is always a memory address. It's "a way of navigating to an object", that's all. It may or may not just be an address.)
From the JVM specification section 2.2:
The Java Virtual Machine contains explicit support for objects. An object is either a dynamically allocated class instance or an array. A reference to an object is considered to have Java Virtual Machine type reference. Values of type reference can be thought of as pointers to objects. More than one reference to an object may exist. Objects are always operated on, passed, and tested via values of type reference.
== will check if both references are the same. You have 2 different objects, no matter they are equivalent, they point to different memory blocks.
The only exception to this rule is String, in special conditions(i.e. invoking .intern() method), but that's really a special case, related to String pool.
If you compare with == equals, the instances of the Object needs to be the same (pointer to the same reference, "same id" in the JVM). The hashcode of the object is'nt checked.
This is why it is a good practice to compare with equals(..) in Java.
Here some code:
Test o1 = new Test();
Test o2 = new Test();
//You can check the ids with System#identityHashCode(Object):
System.out.println(System.identityHashCode(o1));
System.out.println(System.identityHashCode(o2));
o1 == o1 // will be true
o1 == o2 // will be false
o1.equals(o2) //depends on how you have implemented equals() and hashCode() in the Test Object.
The contract between hashCode and Equals is:
objects which are .equals() must have the same .hashCode()
The reverse statement does not need to be true.
In your example, it is exacly the case: you return 999 in .hashCode() and you compare the jvm ids in .equals().
== checks to see if the two objects refer to the same place in memory. In other words, it checks to see if the 2 object names are basically references to the same memory location
EX1:
String obj1 = new String("xyz");
String obj2 = new String("xyz");
obj1==obj2; //False
EX2
String obj1 = new String("xyz");
String obj2 = obj1;
obj1==obj2; //True
public void m1(Integer f) {
...
}
public void m1(Float f) {
...
}
public void main() {
m1(null); // error: the method m1(Integer) is ambiguous for the type Main
m1((Integer) null); // success
}
Given the above example, we can admit in some ways that null is typed. So why do the following lines print true? Sure o1 and o2 both have no value (i.e. null), but they aren't from the same type (Integer vs Float). I firstly thought false would have been printed.
Integer i = null;
Object o1 = (Object) i;
Float f = null;
Object o2 = (Object) f;
System.out.println(o1 == o2); // prints true
// in short:
System.out.println(((Object) ((Integer) null)) == ((Object) ((Float) null))); // prints true
All null values are untyped and are equal. You can pass it to different reference types but it makes no difference for comparison purposes.
It is not the null value which is typed but the reference to the null which can be typed.
A common question is what happens here
class A {
public static void hello() { System.out.println("Hello World"); }
public static void main(String... args) {
A a = null;
a.hello();
System.out.println("a is an A is " + (a instanceof A)); // prints false.
}
}
The compiler sees the type of a as an A so the static method is called. But the value referenced is null and untyped.
The only operations you can perform with null without causing a NullPointerException is to assign or pass it without examining it or comparing it with another reference.
BTW
In short: The compiler will select a method based on the type of the reference, at runtime the execution is based on the class of the object referenced. At runtime null is treated as any type or no type or you get a NullPointerException if you try to dereference it.
"==" in Java checks to see if it is the same instance rather than simply "are they equal?". There is no concept of multiple instances of null in Java. If you compare null to null, you will always receive true regardless of type.
The reason why you cannot then pass null as an argument to a method with the same name as another with different parameter types is because either method could be a candidate to be called without further type context. Rather than guess which one that might be, it correctly indicates an error.
see http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.1
null belongs to the "null type". The "null type" has only one value - the null.
The null type is a subtype of every reference type. Therefore we can do
Integer i = null;
(Integer)null
In another word, null is a valid value in every reference type.
(Think of a type as a set of values; the types of a value is the sets it belongs to; "subtype" means "subset". )
Given the above example, we can admit that null is NOT typed: when you call m1(null), compiler cannot determine the type of the actual parameter and cannot decide which method to invoke. All nulls are equal and not typed, and so (null==null)==true.
Null does not have a type, but a reference (to null or anything else) has a type. We can declare two reference variables with different types, but the null they refer to is the same thing in both cases:
Integer a = null;
Double b = null;
In your example,
m1((Integer) null);
the compiler uses the type of the reference it is passed to work out which overloaded method to call, not the type of the null value itself.
In your example it proves that the compiler cannot identity the type (of null) and decide which method to call. So you have to explicity give the type. Also null == null will be always true; no matter whatever cast you do it doesnt change or give null a type.This post has a long description on null.
I need to call a function with the following signature.
createColumn (N name, V value, Serializer<N> nameSerializer, Serializer<V> valueSerializer)
I want to pass variables of type Object which might have been assigned values of integer or string, I want the type casting to be performed automatically..according to the values that I assigned to Object type variables instead of explicit cast like this:-
Object object1= "MY_AGE";
// string value assigned to to object type variable
Object object2= 31; // integer value assigned to object type variable
createColumn ((String)object1, (int)object2, ....); // Since the datatype of object1 & object2 would not be same everytime while I am calling this function in a for loop, I want that it should automatically cast according to the value I assign to it.* So I am seeking something like this, if possible:-
createColumn (object1, object2, ....);
You can call the following since you don't want to check at compile time that the types match,
createColumn(object1, object2, (Serializer)serializer1, (Serializer)serializer2);
EDIT: This compiles for me (with an "Unchecked" warning)
interface Serializer<T> { }
public static <N,V> void createColumn (N name, V value, Serializer<N> nameSerializer, Serializer<V> valueSerializer) {
}
public static void main(String[] args) throws NoSuchFieldException {
Object object1 = "hi";
Object object2 = 31;
Serializer<String> serializer1 = null;
Serializer<Integer> serializer2 = null;
createColumn(object1, object2, (Serializer) serializer1, (Serializer) serializer2);
}
As I understand your question is not about casting (which deals with compile-time declared types), but conversion (which deals with runtime type of objects).
Consider using String.valueOf() method for your Object arguments. For both Integer and String it will produce their String representation.
I don't think it is possible, you have given the variable a type object and i'm not aware of any way to determine if it is really an int or string unless you use some ugly logic to see what characters the value consists of but that isn't going to be fool proof unless the value will always be either an integer or a string.
Do you need to pass integers or can everything just be passed as a string?