Currently working on a mechanism that allows the deserialization of objects serialized with the Prevayler library. For example:
I have old .jar with classes:
class A {
public B b;
public B getB() {
return b;
}
}
class B {
public int c;
public int getC() {
return c;
}
}
Now I need some kind of migration, because "c" from class "B" need to be cast for example to String.
I'm using custom classloader to load classes and methods:
// 1. make List of URLs to pass to CustomClassLoader class
URL url = new URL(PATH_TO_JAR);
List<URL> urls = new ArrayList<URL>();
urls.add(url);
// 2. Use CustomLoaderClass, to make sure, that loaded classes/methods are not from current project,
// but from the jar specified in URL, since Java class loaders (including URLClassLoader)
// first ask to load classes from their parent class loader.
CustomClassLoader clsLoader = new CustomClassLoader(urls);
java.lang.Class cls = clsLoader.loadClass("A");
// String.class in methods second parametr means, that we should pass String to that method
Method method = cls.getMethod("getB");
// 3. invoke method which returns Object instead "B"
Object obj = method.invoke(null);
I've similary done this with class B.
How I can cast Object obj to "B" so I can invoke method getC from class B?
You wont be able to specify the type on the left hand side of the assignment operator dynamically. At least I know of no way to do that. You will need to check if its a B type first, then explicitly cast it to B. Remember that the obj variable is of type Object, but the object it references is a B, so a getClass() should return B. When you invoke the method, the obj parameter of type Object is the object you want to invoke the method on. It can only be null if the method in question is static. Otherwise, you will need to specify what instance of class A you wish to invoke the method on.
See the invoke doc here: http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Method.html#invoke(java.lang.Object,%20java.lang.Object...)
Related
I am new to Java generics. I have written one function like following:
public class C<T extends MyClass> implements MyInterface<T>{
public void f(T obj){
...
obj.getName()
}
}
Above function f is called for two types of objects MySubClass1 and MySubClass2. MySubClass1 and MySubClass2 are two concreter classes inherited from abstract class MyClass and name is an attribute of MySubClass2.
When f is called with object of MySubClass2 , I would like to access name like above. I cannot figure out how to do that.
...and name is an attribute of MySubClass2
Then your method can't rely on it being there, since obj can be anything deriving from MyClass.
This suggests your design should change such that either you have separate methods or you move name to MyClass.
You could do it with an instanceof check and a cast:
if (obj instanceof MySubClass2) {
String name = ((MySubClass2)obj).getName();
}
...but nine times out of ten, using instanceof should make you step back and reconsider your design.
In a generic method that takes T constrained to MyClass only methods of MyClass are available. Since getName is implemented only in MySubClass2, you cannot access getName without a cast to MySubClass2, which goes contrary to the point of making your f() method generic in the first place.
You can pass a Function object that pulls name from T to f(), like this:
public void f(T obj, Function<T,String> getName){
...
String name = getName.apply(obj);
}
The caller would invoke f() like this:
MySubClass2 s2 = new MySubClass2();
MyInterface<MySubClass2> c = new C<>();
c.f(s2, MySubClass2::getName);
Note that this technique lets you call f on MySubClass1 objects, as long as you provide some way of getting a name:
MySubClass1 s1 = new MySubClass1();
MyInterface<MySubClass1> c = new C<>();
c.f(s1, x -> "<no-name>");
I have a class that is going to be passed into a function and it will be defined as follows:
class ayy{
String blah;
Class a;
Class b;
}
I want to be able to invoke the getSimpleName() method on the classes a and b. Currently I am doing it as follows:
Class c = (Class)argument; // Where argument is the "ayy" class
c.getField("a").getSimpleName();
But this gives me an error saying "getSimpleName()" is not defined for type field.
You cannot call a method directly on an object that results from reflection, such as you're doing with Field, as if it were a reference variable of the desired type.
Instead, you'll need to call getDeclaredField, because getField only gets public fields. Also, you'll need to get() the value of the Field, passing in an instance of the ayy class, which will return the value of the Field. Then you'll need to cast it to a Class, because get() returns an Object. Then you can call getSimpleName().
Class<?> classOfA = (Class<?>) c.getDeclaredField("a").get(anAyy);
String simpleName = classOfA.getSimpleName();
You'll also need to catch the various reflection-related exceptions that may be thrown.
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.
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.
This question already has answers here:
What is the difference between a.getClass() and A.class in Java?
(7 answers)
Closed 7 years ago.
MyClass.class and MyClass.getClass() both seem to return a java.lang.Class. Is there a subtle distinction or can they be used interchangeably? Also, is MyClass.class a public property of the superclass Class class? (I know this exists but can't seem to find any mention of it in the javadocs)
One is an instance method, so it returns the class of the particular object, the other is a Class constant (i.e. known at compile-time).
Class n = Number.class;
Number o = 1;
o.getClass() // returns Integer.class
o = BigDecimal.ZERO;
o.getClass(); // returns BigDecimal.class
Both cases return instances of the Class object, which describes a particular Java class. For the same class, they return the same instance (there is only one Class object for every class).
A third way to get to the Class objects would be
Class n = Class.forName("java.lang.Number");
Keep in mind that interfaces also have Class objects (such as Number above).
Also, is MyClass.class a public property of the superclass Class class?
It is a language keyword.
.getClass() returns the runtime class of the object, so it can be modified when you change the class of the variable
.class on the other hand always return the class constant of the "Type"
NOTE
If the runtime class happens to be the same as the TYPE class, both will be equal.
Example:
Long x = new Long(2);
Class c1 = Long.class;
Class c2 = x.getClass();
//c1==c2
The MyClass doesn't have a static getClass method, in other words, you cannot call MyClass.getClass(), instead you need to call (new MyClass()).getClass() for it to work.
getClass() will return a MyClass.class object. So in other words, MyClass.class is the resulting object while getClass() is a method. The getClass() method is useful in cases where you do not know the actual class of the object, for example:
public void someMethod(Object o) {
if(o.getClass().equals(Set.class)) {
// The object is a set
} else if(o.getClass().equals(List.class)) {
// The object is a List
}
}
Note that the above code example isn't the best possible, I'm just trying to show how it could be used. The same functionality could be achieved with if(o instanceof Set) { ...}
What's the difference between calling MyClass.class and MyClass.getClass()
First of all your question title is a bit misleading! .getClass() is a method defined in java.lang.Object so any object in java can call it where as .class is called on the class itself(like public static variables). So the question should be (sticking to java naming conventions)
What's the difference between calling MyClass.class and myClassObject.getClass()
Now to actual differences
.getClass() is a native java method in java.lang.Object. This method will return java.lang.Class object corresponding to the runtime class of the object on which it is invoked. So
Test t = new TestSubClass();
Class c2 = t.getClass();
System.out.println(c2);
will print class TestSubClass
where as .class will return the statically evaluated (known at compile time) class. It is actually Class object corresponding to the reference type pointing to the actual object.So
Test t = new TestSubClass();
Class c2 = Test.class;
System.out.println(c2);
will print class Test