I have 2 Classes, A and B. Class A has some fields, one of them being an ArrayList<B>. Now, B has some fields of its own(their type&content is not relevant to the problem)
I know how to get the fields of A, and display their value, but I have been unable to find a solution that would enable me to also get the fields of B, from the ArrayList<B> declared in A.
Basically, I'm trying to print the content of each A, including the content of the ArrayList<B>. By content I mean pairs of attributes/fields .
It is assumed I know nothing of A and B ---> I have to write something very generic. Managed to make it work using reflection until I got to the issue described earlier.
Any ideas?
What's wrong with:
final A a = new A();
for (final Field f : a.getClass().getDeclaredFields()) {
f.setAccessible(true);
System.out.println(f.get(a));
}
This loops over all fields in A and prints the content. List has a nice toString method so you just need to have a toString method in B and it should work just fine.
If for some reason you cannot do that then recursion would work. This is dangerous however as, unless you know B does not have a reference at A somewhere, you will end up in an infinite loop.
void printMethods(final Object input) {
for (final Field f : input.getClass().getDeclaredFields()) {
f.setAccessible(true);
if (Collection.class.isAssignableFrom(f.getType())) {
final Collection<?> c = (Collection<?>) f.get(input);
for (final Object obj : c) {
printMethods(obj);
}
} else {
System.out.println(f.get(input));
}
}
}
It's a simple as this:
"Bs: " + a.bList();
B should override toString() too
Related
I have class B which extends A. I declare object of A and initialise it as B. I want to call method which is not in super class.
Is there an easy way to do it?
or I need to cast every time?
Class A //don't have access to it.
Class B extends A {
methodNotInClassA();
}
I know this works:
Class C {
A obj;
method{
obj = new B();
((B)obj).methodNotInClassA();
}
}
But does something more simpler and nicer exists?
Sadly, you are required to cast every single time, or you have to make a variable that is actually type B. You can check if a variable that is type A is type B, then make a temporary variable something like so:
if(obj instanceof B) {
B tmp = (B) obj;
// Code using tmp instead of obj
}
But that is just about the prettiest you are going to get.
Is there a work around that will allow me to cast an object of the base class to an object of the derived class?
something like the following
B extends A
A a = new A();
B b = (B)a
Is there a trick that will achieve this?
No, absolutely not. What would you expect the values of any fields declared in B but not in A to be? For example, what would you expect this to do:
Object x = new Object();
String text = (String) x;
System.out.println(text);
An Object has no text data... so what would it mean to cast it as a string?
You can only cast a reference to a type which is appropriate for the actual type of the object.
The desire to do this usually indicates a design problem somewhere... or it might mean that you want something like:
public class A {
public A() {
// Whatever
}
public A(A a) {
// Use the existing values in "a" to initialize this object
}
}
public class B extends A {
/** Creates a new B from the values in an A, with suitable defaults. */
public B(A a) {
super(a);
// Now initialize any fields in B with appropriate values
}
}
Then:
A a = new A();
B b = new B(a);
That will create two objects, unlike a cast... but it would at least be valid.
How is that even possible? Think about it. It is like saying if you have a class FourWheeler, you can simply cast it into a Ferrari and make it a Ferrari!
No, this isn't possible. When B extends A it inherits the behavior of A, but on the same time, there is nothing stopping you from defining new behavior for B (where those new behaviors won't be part of A)
For example say A has a single method called 'methodA'. Now when B extends A it inherits 'methodA' but it also declares another method called 'methodB'. So under such circumstance you will get a runtime 'ClassCastException' when you try to call the 'methodB' over an instance of Object A.
Trying to understand upcasting in Java. Recently observed strange behavior.
Example:
public class A extends B {
public int i = 2;
public void printI() {
System.out.println("print i = " + this.i);
}
public static void main(String[] args) {
B a = new A(); // <- upcasting here
System.out.println("i = " + a.i);
a.printI();
}
}
class B {
public int i = 1;
public void printI() {}
}
//Output:
//i = 1
//print i = 2
Seems, that upcasted object has two separate "i" properties. One "i" accessible directly (a.i) and the other through methods of child class (a.printI()).
Looks like upcasted object gets properties from superclass and methods from child class.
How object can have two separate "i"s?!
Seems, that upcasted object has two separate "i" properties.
Firstly, it's worth being clear about terminology. There's no such thing as an "upcasted object" - and "i" is a field in each of A and B.
But yes, there are two separate fields here. It's not like one field "overrides" another or anything like that.
It's not clear what you were trying to achieve, but the declaration of i in A shadows the declaration of i in B. See section 6.4 of the Java Language Specification for more information.
Note that in almost all cases, fields should be private - at which point the hiding really doesn't matter, as you wouldn't try to refer to a variable which wasn't declared in the class you're coding in anyway.
That's how Java works. You have both fields "available", they just happen to have the same name. When you reference from the subclass, it is hiding the superclass' version, but it is still there.
I have two classes A and B while B is a subtype of A:
public class A {
private String stringVar;
public A() {
stringVar = "";
}
public String getStringVar() {
return stringVar;
}
public void setStringVar(String str) {
this.stringVar = str;
}
#Override
public String toString() {
return getStringVar();
}
}
Class B:
public class B extends A {
private int intVar;
public B() {
intVar = 0;
}
public int getIntVar() {
return intVar;
}
public void setIntVar(int intVar) {
this.intVar = intVar;
}
#Override
public String toString() {
return super.toString() + " " + getIntVar();
}
}
As you can see in the following main method I assign the b to a. Now "a" can't invoke b's methods which is clear, because I'm using an instance of type A now. But it behaves like a B when toString is invoked. Curious, I would have expected toString of a. Why is this so?
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
b.setIntVar(200);
b.setStringVar("foo");
a = b;
System.out.println(a);
}
}
Because a points to the implementation of B.
And is declared as A.
So behavior of B. And methods visible of A.
To use B methods do like this
((B) a).getIntVar();
Think of it like this
Object o = new FancyObject();
When compiling this only Objects methods will be accepted even though it's a FancyObjcet with lots of methods.
To use the methods of FancyObject on o do like this.
Object o = new FancyObject();
(FancyObject o).fancyMethod();
Quote "because I'm using an instance of type A now" you are still using an instance of type B. You can see it like you have upcasted b but it's the same instance.
Picture cross linked from another site with credits in the picture, if this is against the rules then somebody is free to edit this part of my answer.
This is nature of inheritance / polymorphism and overriding methods.
Overrided methods will be determined in runtime based on objects real type and not based on reference type.
Therefore a.toString() is actually b.toString() because it is determined in runtime.
http://download.oracle.com/javase/tutorial/java/IandI/override.html
The concept you need to understand is the difference between References and Objects.
a is a reference (a local variable in this case) that points first to an Object of type A and then to an Object of type B.
The compiler knows that it must be of type A (or a subtype thereof), so it can safely call all methods A defines, but they will be called on the actual Object, not on the original Type of a.
This is polymorphism: The object that a holds has static type A, but it is still an Object of dynamic type B. Dynamic dispatch therefore chooses the overridden toString() defined in B.
That's exactly how Java's runtime polymorphism works. All that matters is the actual type at runtime. What you have done is take a reference to an A and point it at an instance of B. You have changed the type of the thing that a points to.
Try
a = (A)b;
No, B Overrides the toString method of A, so if an object is an instance of B, when you call its toString method, you get whatever method that instance has. In general, if you have an object and call its methods, the method called is the one that is in the instance, not in the variable type. The only exception is static methods.
In C++, this is not the case. The method called is the one of the variable type, if one exists, unless you explicitly select the above described behavior by making a method virtual.
That is called runtime polymorphism in OOP.
public static <A, B> B convert(A instance,
Class<B> targetClass) throws Exception {
B target = (B)targetClass.newInstance();
for (Field targetField : targetClass.getDeclaredFields()) {
targetField.setAccessible(true);
Field field =
instance.getClass().getDeclaredField(targetField.getName());
field.setAccessible(true);
targetField.set(target, field.get(instance));
}
return target;
}
Above is the code I get from forum, When I try to reflect an single type object it works, but when I try on the complex type which mean inside ClassA I got ClassB object, I got the java.lang.NoSuchFieldException. Can anyone help me?
You have two different classes, with, most likely, different set of fields.
So if your Class A doesn't have the same fields as your class B, then the exception is thrown.
I'd suggest using BeanUtils.copyProperties(source, target) from apache commons-beanutils. You just create the second object yourself, and pass it to the method. It will not throw an exception if fields differ.
What is your ultimate goal with this piece of code?
Two suggestion:
(1) You can drop the downcast at the first line of the method:
B target = targetClass.newInstance();
(2) Add a try catch so that you can see the name of the missing field. This will help you sort out the issue you're having:
Field field = null;
try {
field = instance.getClass().getDeclaredField(targetField.getName());
}
catch(NoSuchFieldException e) {
throw new RuntimeException("Didn't find field named '" + targetField.getName() + "'");
}
...
Another answer.
If I understand your comment correctly it seems that you have inner classes: Class B (Target) is a class that is defined inside class A. Something like this:
class A {
int n;
class B {
int n;
}
}
Although these two classes seem to have the same fields, and therefore - should not inude a field not found error - they are not.
Inner classes (unless they are defined as static) has a hidden field inserted by the compiler. This field is of the type of the outer class and points to the object that created the inner class object. When using reflection this field is exposed. As A does not have such field, an exception is raised.