Java reflecting nested anonymous classes - java

Why does this code return "class java.lang.Object" ?
Object a = new Object() {
public Object b = new Object(){
public int c;
};
};
System.out.println(a.getClass().getField("b").getType());
Why does the inner-inner type get lost? How can I reflect the c field ?
Edit:
This one works (as pointed out in some answers):
a.getClass().getField("b").get(a) ...
But then I have to invoke a getter, is there any way to reflect c with only reflection meta data?

Because b is declared as Object:
public Object b = ...;
There is a distinction between type of variable (static type) and type of the object referenced by that variable (runtime type).
Field.getType() returns static type of the field.
If you want to get runtime type of the object referenced by the field, you need to access that object and call getClass() on it (since a is declared as Object and therefore b is not visible as its member you have to use reflection to access it):
System.out.println(
a.getClass().getField("b").get(a).getClass());
UPDATE: You can't reflect c without accessing the instance of object containing it. That's why these types are called anonymous - a type containing c has no name, so that you can't declare field b as a field of that type.

Let's look at this line carefully:
System.out.println(a.getClass().getField("b").getType());
First, your take the a variable. It is of some anonymous subclass of the Object. Let's call that class MyClass$1. Okay, so far so good.
Next, you call the getClass() method. It returns the class of a, that is, a description of the MyClass$1 class. This description is not tied to any particular instance of that class, though. The class is the same for all instances, be it a or whatever else (unless different class loaders are used). In this particular case, however, there can be only one instance, because the class is anonymous, but the mechanism is still the same.
Now, from the class, you get the field b. As the class isn't directly tied to any of this instances, the field has nothing to do with a either. It's just a description of what exactly the field a of the class MyClass$1 is.
Now you get its type. But since it isn't tied to any instance, it can't know the runtime type. In fact, if the class wasn't anonymous, you could have numerous instances of MyClass$1, each having different value in a. Or you could have no instances at all. So the only thing getType() can possibly tell you is the declared type of b, which exactly what it does. The b field could in fact be null at that point, and you'd still get Object as the result.
The Field class provides the get() method to actually access that particular field of some object, like this:
System.out.println(a.getClass().getField("b").get(a).getClass());
Now you get something like MyClass$1$1, which is the name of the anonymous class of the object that field b references to, in the a instance.

Why does the inner-inner type get lost?
Because you are getting the type type of the field "b" (Object), not the type of the anonymous inner class of which you assigned the instance to "b".
How can I reflect the c field ?
You could use this
System.out.println(a.getClass().getField("b").get(a).getClass().getField("c"));
instead. This gets the value of the field "b" and it's class, but this only works if "b" is guaranteed be not null.
Doing this seems to indicate a bad design, there might be other ways to archive what you want to do with this. But without knowing the purpose, this is everything I can answer.

Related

handle different instance variables in method

So if I have a method where a variable can be an instance of a bunch of different classes where only some of them have a specific instance variable, how do I use this instance variable in the method without getting the cannot be resolved or is not a field error?
consider this code:
void method1(){
SuperType randomInstance = getRandomInstance();
if(randomInstance.stop == true) //do something
}
where SuperType is a super class to all possible instances that randomInstance can hold.
However, an instance doesn't necessarily have the variable stop so I get an error saying stop cannot be resolved or is not a field
So my question is, is there a way to get around this or would I have to create different methods for different instances depending on if they have the variable stop or not?
If having a stop property can be viewed as a behavior shared by some of the sub-classes of SuperType, you can consider defining an interface - let's call it Stoppable - having methods getStop (or perhaps isStopped if it's a boolean) and setStop.
Then your code can look like :
void method1(){
SuperType randomInstance = getRandomInstance();
if (randomInstance instanceof Stoppable) {
Stoppable sInstance = (Stoppable) randomInstance;
if(sInstance.getStop() == ...) //do something
}
}
Give the classes in question a common supertype or interface (they seem, from your code, to have one — SuperType), and define the instance field (it's not a "variable") on the supertype or define a getter function on the interface. (Actually, even if the supertype is a class, it's commonly best practice to define the field using a getter anyway, even if you could make it a public or protected instance field.)
If you cannot change your class hiearchy with the introdution of an Interface (Stoppable for example) can resort to reflection to detect if the class has a provate field named stop.
You can find an example of field "listing" from a class here and Field is documented here

Java.lang.Class.cast doesn't return a casted object

I am trying to cast an object to its superclass using Java.lang.Class.cast but I get the same object. What can be the reason?
This is the code I'm running:
public static void parse(Object obj)
{
// parse all super classes
Class<?> clazz = obj.getClass().getSuperclass();
if (!clazz.equals(prevClass))
{
prevClass = clazz;
Object castedObj = clazz.cast(obj);
parse(castedObj);
}
fillObject(obj);
}
but when passing to parse an object of dynamic type B, where B extends A, castedObj is equal to obj.
But I want castedObj to be a new object of dynamic type A because the parse method relies on that fact (iterates on the fields of the dynamic type class).
I am trying to cast an object to its superclass using Java.lang.Class.cast but I get the same object.
That is exactly what is supposed to happen.
For reference types, a cast is simply a type check. For example:
A a = (A) b;
This says to check that b is-a A and the assign the reference so that we can refer to it as an A using a.
There is no object conversion going on. No creation of new instances. The value assigned to a is identical in every respect to the value in b.
The same also applies when you use reflection to do the typecasting.
Or to put it another way, the value returned by getClass() for a given object is always going to be the same ... no matter how you cast is.
It is not clear what you are trying to do in your code, but it we assume that fillObject is filling in fields that relate to a particular class, then you most likely need to pass the Class as an explicit parameter. The true class of obj is always going to be the object's actual class ... irrespective of any casting.

Check if Field is from specific class

To display keys & values of a dataobject, I'm using a Collection of AccessibleObjects to generate a table. The AccessibleObject'S are collected on a specific time, but the values are read, when the render have to render the table.
The Problem: I'm not only want to hold AccessibleObject's of one specific Class. Is it possible to check a AccessibleObject Class-Origin? e.g. accessibleObject.fromClass(classType);
Do you mean
Member member = field or method;
Class clazz = member.getDeclaringClass()
to get the class the field appears in.
Note: this is the actual class, not the class you might have used to look it up. e.g. say A has a field x and a subclass B. If you get field x of class B, it will say the declaring class is A. This is because A and B can have a field called x.
Class c = field.getDeclaringClass();
From JavaDoc:
Returns the Class object representing the class or interface
that declares the field represented by this Field object.

In a non-static method is the method duplicated every time an object is created?

for example, lets say you have:
class X
{
public void foo()
{
}
}
and then in your main you have
X anX = new X();
anX.foo();
X bX = new X();
bX.foo();
is the "foo" method being duplicated for every instance of X? Or is it that each instance just re-uses the foo method code.
It will reuse the method code for each object. What changes is the implicit argument, which is the object you invoke the method on.
Instance methods are despatched (more or less) using a Class pointer and an internal virtual-method table. Similar, but slightly more indirect & slower, for methods accessed via an interface.
Class VMTs and method code are loaded once per ClassLoader & then shared between all objects using the method. Thus class type information & method code are not duplicated in memory.
Objects always keeps their Class pointer and the (internal) virtual-method table. This applies whether casting to a subtype or assigning to a supertype. Object Class and the internal pointer are assigned at construction and invariant for the lifetime of the object.
Static methods OTOH are not virtualized, do not use a VMT & despatch according to the static type of the reference. This is resolved at compile time.

Casting reference variable in Java

I have something unclear concerning casting reference variable in Java.
I have two classes A and B. A is the super class of B.
If I have the two objects, and then the print statement:
A a = new A(); //superclass
B b = new B(); //subclass
System.out.println ((A)b);
then what exactly is happening when the println method is executed?
I know that because B is a subclass of A, I am allowed to make the following cast:
A a2 = (A)b;
I also know that when println takes a reference variable as argument, then the toString() method of the class, which has created the object-argument, is invoked (implicitly). This is so, because the method println() is looking for an argument of type String, and the toString() method represent the object as a string. And even if we don't write toString(), the method is invoked - implicitly. So, the following two statements are equivalent:
System.out.println (b);
System.out.println (b.toString());
So, my question is: what is the implicit action taken when we have
System.out.println ((A)b);
?
I suppose that the type of the reference variable b is automatically changed from B to A. The variable should still be pointing to the same object - the one created with
B b = new B();
but just the type of b would be now changed. Is this correct?
Another question: even though I have changed the type of b to the type of the superclass, are the overriden methods in the subclass going to be called, and not those of the superclass?
Thanks a lot.
Regards
The cast has no impact in this case.
The System.out.println(XXX) takes parameters of different types (multiple overloaded versions) but in this case you would get the version that takes Object. Since every object in Java supports toString(), toString is invoked on the actual argument, no matter what it is.
Now, since all methods in Java are dispatched dynamically, the version that runs is the version that corresponds to the dynamic type. Casting an object of B to A only changes the static (declared) type of the expression. The dynamic type (what's really in there) is still a B. Therefore, the version in B gets invoked.
There are many declarations of println(...) in the PrintStream class (which is the type of System.out).
Two of them are:
void println(String x)
void println(Object x)
When you call println((A)b) the compiler chooses to call println(Object) because A is not String (or any of the other types that println supports). When you call println(b.toString()), the compiler chooses println(String) because you are passing a String.
In your case, casting b to A has no effect since println() doesn't have a declaration for either A or B types. But the cast will still occur (because you asked for it), or maybe it won't because the compiler optimises it away as it knows it is redundant and it can't fail and has no effect.
It is not idiomatic to write:
A a2 = (A)b;
as this is redundant since B is a subclass of A. It may be that the compiler will optimise away the cast (which is a run-time operation to check whether an object is of a particular type, never to change it's type).
Once an object of type B is constructed, it's type never changes. It is always a B:
class B extends/implements A {...}
B b = new B(); // construct a B
A a = b; // assign a B to an A variable, it's superclass
A a = (A) b // as above including check to see that b is an A (redundant, may be optimised away).
B b = a; // Syntax error, won't compile
B b = (B) a // Will check whether a is of type B then assign to variable b
In the last case, since B is a subclass of A, it may be that a holds an instance of B and the cast will succeed. Or it may be that a holds an instance of some other class that extends/implements/is A and isn't a B and you'll get a ClassCastException.
So since an object of type B always retains it's identity (it's "B"-ness) then any (instance-) methods called on that object will always call B's implementation regardless of whether the variable through which you access the object was declared as A or B.
Remember, you can only call methods that are declared in the class that the variable is defined as.
So for example, if B declares a method b_only() then the compiler won't allow you to write a.b_only(); you could write ((B)a).b_only() though.
Since Java methods all have dynamic dispatch, which function gets called doesn't depend on the static type of the reference. Therefore, the results will be the same with or without the cast. [The results could be different if you were downcasting - the casting version could throw an exception]
Is this correct?
Sort of. The result of the casting expression would be of the A type. The type of the 'b' variable will always remain of type B.
Another question: even though I have changed the type of b to the type of the superclass, are the overriden methods in the subclass going to be called, and not those of the superclass?
The instance methods of the underlying object will be called. Example:
class Foo {
public static void main(String[] args) {
B b = new B();
assert "B".equals(((A) b).m());
}
}
class A {
String m() { return "A"; }
}
class B extends A {
String m() { return "B"; }
}
Always think of your object as the type it's instantiated as (B in your case). If it's upcast to A think of it as--hmm--think of it as B putting on A clothes. It may look like an A, and you may not be able to do any of the nice B things you want to do, but inside the clothes it's still a B--the clothes don't change the underlying object at all.
So the summary would be--you can only call the methods in A, but when you call it, it goes straight through and executes it as it would if it was a B.
I think when we use reference variable in java and by using this variable we can assign a object of any class type. most of the cases we create a reference variable of Interface and abstract class because we can't create the object of interface and abstract class so assign the object of class in reference variable of Interface or abstract class.
Ex-
Interface X {
public abstract void xx();
public abstract void yy();
}
Class XXX implements X {
...........
}
Class XY extends XXX {
X xy = new XXX();
}
here xy is a reference of Interface X and assign the object of Class XXX in the reference of Interface.
so according to my point of view by using reference variable we can also use interface to participate in Object creation.
The casting, as has been mentioned, is irrelevant in this case due to overridden methods being dynamically bound. Since the toString is present in all objects it meets this condition and thus the object type and method to call are determined at runtime.
Please note though, this is NOT the case with all methods since only overridden methods are dynamically bound. Overloaded methods are statically bound. Many of the answers here mention that java methods are always dynamically bound, which is incorrect.
See this question for a more detailed explanation.
question: even though I have changed the type of b to the type of the superclass, are the overriden methods in the subclass going to be called, and not those of the superclass?
in this case the method of subclass b is called ; to convincingly understand why; you may relate to the following real world scenario
consider a parent class Father exhibiting a behaviour(method): height
defined as
the father is tall ;height = 6'2"
Son is a child class inheriting the height behavior from Father ;as a result he is also tall; height being 6' clearly overriding the behaviour
whenever your subclass Son calls the behavior height on his name he displays the overridden behavior i.e his own height 6' .

Categories

Resources