Problem
The Class Object of a boolean Field does not recognize other booleans as instances.
Code
public class Test {
public boolean b;
public static void main(String[] args) {
System.out.println(Test.class.getFields()[0].getType().isInstance(true));
}
}
Result
false
The method is isInstance(Object) so
x.isInstance(true)
is the same as
x.isInstance(Boolean.TRUE);
and Boolean.class is not a sub-class of boolean.class.
Note: primitives don't have a getClass() method, or any methods for that matter. When you can use it as a Object, it has been boxed.
From documentation of Class#isInstance(Object obj)
... If this Class object represents a primitive type, this method returns false.
Notice that expected argument is always Object, which means it will always be instance of some class (which excludes primitive types).
Even if you pass primitive type here it will be autoboxed to its wrapper class, but such wrapper class is not be same as primitive type represented by Class and in your case returned by getType().
Related
I have added three methods with parameters:
public static void doSomething(Object obj) {
System.out.println("Object called");
}
public static void doSomething(char[] obj) {
System.out.println("Array called");
}
public static void doSomething(Integer obj) {
System.out.println("Integer called");
}
When I am calling doSomething(null) , then compiler throws error as ambiguous methods. So is the issue because Integer and char[] methods or Integer and Object methods?
Java will always try to use the most specific applicable version of a method that's available (see JLS ยง15.12.2).
Object, char[] and Integer can all take null as a valid value. Therefore all 3 version are applicable, so Java will have to find the most specific one.
Since Object is the super-type of char[], the array version is more specific than the Object-version. So if only those two methods exist, the char[] version will be chosen.
When both the char[] and Integer versions are available, then both of them are more specific than Object but none is more specific than the other, so Java can't decide which one to call. In this case you'll have to explicitly mention which one you want to call by casting the argument to the appropriate type.
Note that in practice this problem occurs far more seldom than one might think. The reason for this is that it only happens when you're explicitly calling a method with null or with a variable of a rather un-specific type (such as Object).
On the contrary, the following invocation would be perfectly unambiguous:
char[] x = null;
doSomething(x);
Although you're still passing the value null, Java knows exactly which method to call, since it will take the type of the variable into account.
Each pair of these three methods is ambiguous by itself when called with a null argument. Because each parameter type is a reference type.
The following are the three ways to call one specific method of yours with null.
doSomething( (Object) null);
doSomething( (Integer) null);
doSomething( (char[]) null);
May I suggest to remove this ambiguity if you actually plan to call these methods with null arguments. Such a design invites errors in the future.
null is a valid value for any of the three types; so the compiler cannot decide which function to use. Use something like doSomething((Object)null) or doSomething((Integer)null) instead.
Every class in Java extends Object class.Even Integer class also extends Object. Hence both Object and Integer are considered as Object instance. So when you pass null as a parameter than compiler gets confused that which object method to call i.e. With parameter Object or parameter Integer since they both are object and their reference can be null. But the primitives in java does not extends Object.
I Have tried this and when there is exactly one pair of overloaded method and one of them has a parameter type Object then the compiler will always select the method with more specific type. But when there is more than one specific type, then the compiler throws an ambiguous method error.
Since this is a compile time event, this can only happen when one intentionally passes null to this method. If this is done intentionally then it is better to overload this method again with no parameter or create another method altogether.
class Sample{
public static void main (String[] args) {
Sample s = new Sample();
s.printVal(null);
}
public static void printVal(Object i){
System.out.println("obj called "+i);
}
public static void printVal(Integer i){
System.out.println("Int called "+i);
}
}
The output is Int called null and so ambiguity is with char[] and Integer
there is an ambiguity because of doSomething(char[] obj) and doSomething(Integer obj).
char[] and Integer both are the same superior for null that's why they are ambiguous.
Here is a method in which I am casting an Object to a primitive type.
#SuppressWarnings("unchecked")
public <T> T fetchPrimitive(Object object, Class<T> clazz) {
return (T)object;
}
It works fine as long as my Object is of same class as T (which is a primitive class like int, double etc.).
But, this method also runs without any exception when I provide wrong class to cast. Say if I provide the object as boolean (true/false) and clazz as int.class, then also this method runs and return (true/false) the actual Object.
I understand that Generics can not work on primitives. I just need to understand whats happening here when I am providing a primitive class as an argument and return type is Generic.
For example:
Object object = true;
Class clazz = int.class;
Object result = fetchPrimitive(object,clazz);
//result = true and result.getClass() is Boolean.
//I asked it to convert a boolean to int expecting an exception but seems that it simply ignored the casting?
From running the code, I understand that it's simply ignoring the casting when its a primitive class and returning whatever Object it is. I do not want it to be this way, I want it to throw an exception (ClassCastException) if wrong class is provided.
Since you've provided the clazz you can use Class::cast to get what you want:
public static <T> T fetchPrimitive(Object object, Class<T> clazz) {
return clazz.cast(object);
}
If you only do a cast type erasure will transform your code into something like this:
public static Object fetchPrimitive(Object object, Class<Object> clazz) {
return (Object) object;
}
This is absolutely valid.
This simply won't work for primitives due to the way JVM works. Since your return type is T, it gets erased to Object (as seen in Flown's answer) and even if you return a primitive it will be boxed back to Integer/Boolean/etc.
If you want the method to be able to return a primitive, it has to be specified in the return type, and there is no way for a method to return different primitives depending on the arguments. You'll have to have separate methods for each primitive, unfortunately, or live with boxing.
The default return of an object in Java is to return the toString method, is there a way to change this behavior to for example return a number or some other type or is this just a core unchangeable component of the language?
Test test = new Test();
blankMethod(test);
I am not sure why people are saying my assumption is wrong... if I Override the toString method of object it will output that new toString method...
#Override
public String toString() {
System.out.println("This method is run when the object is used as a parameter");
return "test";
}
The default return of an object in Java is to return the toString method
That's how PrintStream.println works. Any object in java extends java.lang.Object and therefore inherits Object behavior. In particular, any method which takes Object as an argument, also can take any object of another type. However, you can override any public or protected method defined in Object. In your case you should override toString() method in Test class, otherwise if you pass Test object to PrintWriter.println(), it'll use toString from superclass (Object in your case). So, if i understood your question correctly, the answer is no.
Update: your terminology is wrong. There is no default return of an object in java. Returning Object.toString is the default behavior only for PrintStream.println(Object).
Update2: more widely, Java doesn't support implicit type conversion except upcasting. In your case, Test extends Object, but it doesn't extend String (actually, String is final and therefore you can't extend it). So, if you try to pass Test object to method which only takes String, you'll get compilation error because String and Test belong to different branches of class hierarchy.
You are actually calling
PrintStream.println(Object x)
instead of
public void println(String x)
The PrintStream.println(Object x) implementation is below:
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
The method calls String.valueOf(x) whose implementation is below:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
Note that the Object.toString() method is being called.
Notes on implicit conversion
An Object is only implicitly converted to a String using the toString method when the string concatenation operator (+) is invoked. More exactly the conversion works as follows:
A value x of primitive type T is first converted to a reference value...
This reference value is then converted to type String by string conversion.
Now only reference values need to be considered.
If the reference is null, it is converted to the string "null" (four
ASCII characters n, u, l, l). Otherwise, the conversion is performed
as if by an invocation of the toString method of the referenced object
with no arguments; but if the result of invoking the toString method
is null, then the string "null" is used instead.
The toString method is defined by the primordial class Object"
Java Language Specification 15.18.1
One language (of many) that expand on the idea of implicit conversions is Scala which allows one to bring a conversion (e.g., A -> B) into scope which is then invoked whenever some type (A) is passed as an argument when a different type (B) is required.
This answers "why people are saying my assumption is wrong".
Here is a simple program:
public class Test {
public String toString(){
return "I am a Test object.";
}
public int add(int a, int b){
return a+b;
}
public static void main(String[] args) {
Test object = new Test();
System.out.println(object);
System.out.println(object.add(2,2));
System.out.println(adder(object));
}
public static int adder(Test test){
return test.add(3,5);
}
}
Output:
I am a Test object.
4
8
The System.out.println method has to turn its argument into a String, one way or another. If it is passed an object reference, it uses its toString() method. If it is passed a primitive, such as an int expression, it converts it in an appropriate way.
It is nothing to do with what is being returned.
It also has nothing to do with any automatic conversion on passing a reference as an argument. See the third line of output, which depends on using the Test reference I passed to adder as a Test, not a String.
If you want to change what println prints, do what I did above, and pass it something different.
Suppose there is the following code:
#SuppressWarnings("unchecked")
public static <T> T implicitCaster(Class<T> cls, Object o) {
return (T) o;
}
public static <T> T reflectionCaster(Class<T> cls, Object o) {
return cls.cast(o);
}
The code works as expected in both cases with the following exception, found in primitives:
public static void main(String[] args) {
System.out.println(implicitCaster(int.class, 42));
System.out.println(reflectionCaster(int.class, 42));
}
The first call works as expected but the second call throws java.lang.ClassCastException.
Is this a corner case in which autoboxing was disregarded? Or is it impossible to provide autoboxing in this case, of reflection casting?
Or is there something else causing this inconsistency?
Edit: calling this code works as expected:
public static void main(String[] args) {
System.out.println(implicitCaster(Integer.class, 42));
System.out.println(reflectionCaster(Integer.class, 42));
}
This happens because of type erasure.
At runtime, generic type parameters don't exist.
Casting an object to a generic type parameter has no effect. (which is why you get the unchecked cast warning)
Therefore, your first line autoboxes 42 to Object to pass to the method.
The function then returns that Object, which is passed to System.out.println.
Your second call calls the cast method of the int primitive type.
This throws an exception, because objects cannot be casted to primitive types. (auto-boxing is a purely compile-time feature, so it doesn't help)
The error happens when cast() checks isInstance() to verify that the cast is valid.
The docs for isInstance() say:
Specifically, if this Class object represents a declared class, this method returns true if the specified Object argument is an instance of the represented class (or of any of its subclasses); it returns false otherwise. If this Class object represents an array class, this method returns true if the specified Object argument can be converted to an object of the array class by an identity conversion or by a widening reference conversion; it returns false otherwise. If this Class object represents an interface, this method returns true if the class or any superclass of the specified Object argument implements this interface; it returns false otherwise. If this Class object represents a primitive type, this method returns false.
(emphasis added)
Your edit works because you are no longer using a primitive type.
In both cases, the compiler autoboxes 42 so that it can be passed as an object.
The first call, as before, has no effect.
The second call verifies that the boxed integer is in fact an instance of the Integer class, then returns it.
How can i compare 2 classes?
The following if statement never passes although class is type of MyClass:
public void(Class class) {
if (class == MyClass.class){
}
}
if (clazz.equals(MyClass.class)) {
}
BTW, class is a reserved word.
To test whether clazz is a (sub) type of MyClass do
MyClass.class.isAssignableFrom(clazz)
From the javadoc for Class.isAssignableFrom
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter. It returns true if so; otherwise it returns false. If this Class object represents a primitive type, this method returns true if the specified Class parameter is exactly this Class object; otherwise it returns false.
Specifically, this method tests whether the type represented by the specified Class parameter can be converted to the type represented by this Class object via an identity conversion or via a widening reference conversion. See The Java Language Specification, sections 5.1.1 and 5.1.4 , for details.
So
Object.class.isAssignableFrom(String.class)
is true because each String is also an Object but
String.class.isAssignableFrom(Object.class)
is false because not all Objects are Strings.
The name "isAssignableFrom" comes from the fact that,
Class1 x = (Class2) null;
is only legal when
Class1.class.isAssignableFrom(Class2.class)
I.e., we can assign a field or variable with static type Class1 a value that comes from an expression whose static type is Class2.
You can use == or .equals() to compare Class objects.
Example:
class MyClass
{
public static void main (String[] args) throws java.lang.Exception
{
MyClass m = new MyClass();
if (MyClass.class == m.getClass())
{
System.out.println("it worked");
}
}
}
Demo: http://ideone.com/AwbNT
You can use instanceof operator to check if an instance belongs to a specific class or its subclasses.
class MyClass{}
class SubClass extends MyClass{}
public static void main(String args[]) {
SubClass object = new SubClass();
if (object instanceof MyClass) {
System.out.println("It works, too");
}
}