Dynamically create and cast objects at runtime - java

Let's say we have 2 classes A and B
public class A{
private int member1;
A() {
member1 = 10;
}
public getMember(){
return member1;
}
}
Class B is also on the same lines except that its member variable is named member2 and gets intitialized to say 20 inside the constructor.
My Requirement :
At runtime , I get a string which contains a className ( could be A or B). I want to dynamically create an object of this class along with invoking the constructor. How can I achieve this . I don't want to use interfaces for common functionality of above classes Morever, later on I set the properties of this raw object using Propery Builder Bean Util class based on a list of columns .
Class clazz = Class.forName("className");
Obj obj = clazz.newInstance();
How I can dynamically convert that obj to className object.

How can I achieve this . I don't want to use interfaces for common functionality of above classes
Then the answer is very simple and you won’t like it: you can’t. You want to modify the static type of the variables which is, by definition, determined at compile time. Changing it at runtime is not possible.

What do you mean with "dynamically convert"? It IS an object of type "className", stored in a variable of type Object. If you want to use it as an object of type A, you have to cast it, and for example store it in a variable of type A.

Class Class has a cast method which at first sight seems to be doing just what you want. So you could try
... = clazz.cast(obj);
but what would be the return type??? It should be either A or B, but you can't declare a variable dynamically...
So I see no other way than the ugly, but tried and true
if (obj instanceof A) {
A a = (A) obj;
...
} else if (obj instanceof B) {
B b = (B) obj;
...
}
Note that if with bean introspection, you can always see the actual dynamic type and internals of the object, so I see not much point trying to get a static reference of the right type to it.

Related

difference between 'Class<?>' and 'Object' as argument of method

Assume i want to have a method that get an object of any type in my application to validate all fields it has (each object has different fields with different types) and wrap it to a message. so the method input argument would be instance of any object
Now my question is :
what's the difference between having this input argument as an Object or Class<?> ?
as i know ? means 'any type or class' and 'Object' is a super type in java .
i appreciate if Someone could explain me in which cases better to use this :
public validateAndConvertAnyObject(Object obj) {
// compute and return a message
}
and when it's better to use this ?
public validateAndConvertAnyObject(Class<?> obj) {
// compute and return a message
}
First you don't specify a return type in your method.
It is not valid.
Second, these two parameters are totally different.
public validateAndConvertAnyObject(Object obj)
can accept any object.
While public validateAndConvertAnyObject(Class<?> obj)
can accept any class.
The equivalent of
public validateAndConvertAnyObject(Object obj)
with generic would be :
public <T> void validateAndConvertAnyObject(T obj){
After compilation and type erasure, these provide the same compiled class.
So in this example, using Object makes more sense as more explicit.
To convert an instance to another class with reflection, generally, you pass the target class :
public <T> T validateAndConvertAnyObject(Object obj, Class<T> targetClass){
...//processing on obj
}
And you could use it :
MyObject myObject = ...;
MyOtherClass myOtherClass = validateAndConvertAnyObject(myObject, MyOtherClass.class);
The first method can be called with any object as an argument, eg "foo", 42 or Integer.class. The second one will only accept class objects, eg "foo".getClass() or String.class
What is the difference between Class<?> and Object
Object
This takes the instance as a parameter
Class<?>
This takes a class as a parameter
Example
Object could be equal to String, and for a similar result you could have Class<?> equal to java.lang.String.
Confusion
Technically, you could pass an instance of Class<?> as an Object, which adds confusion, which is a good reason to use Class<?> instead, as it prevents mixing up the instance and it's class.
Object actually represents an instance of a created object like:
String text = "Hello World!";
Object textAsObj = (Object) text;
Whereas Class only represents the class of objects, it has no connection to an actual instance of this class:
Class<?> textClass = Class.forName("java.util.String");
So you should probably use the Object variant if you want to access specific values of an instance. You can, at anytime, retrieve the class from an Object using the getClass method:
String text = "Hello World!";
Class<String> textClass = text.getClass();
And here is an example how you could use that to access a field of a given Object:
Person person = new Person("John Doe");
Class<Person> personClass = person.getClass();
Field nameField = personClass.getDeclaredField("name");
String name = (String) nameField.get(person);

Questions about the Class method "forName()"

How do I let the user insert a String and check for classes with the same "name"?
Imagine I have a method marked as public A[] getB(String bString) and two classes, A and B, where B extends A.
In this method I want to search through an existing A[] for objects that are upcast from being from the class B and return an A[] with said objects.
I searched through the internet and found out that the class Class has the method forName(), but I don't really understand how to use it. For example, I do this:
Class<?> cl = Class.forName(bString);
Where bString is a String that contains B, B being another class.
My questions are:
What exactly is the object "cl" now?
How could I now check if objects are of the same class as it?
What exactly is the object "cl" now?
cl is an instance of Class class.
How could I now check if objects are of the same class as it?
you have 2 object o1 and o2 you can use getClass()
o1 != null && o2 != null && o1.getClass().equals(o2.getClass())
The method Class.forName(String) returns a Class object for the corresponding class, if known. To quote from its documentation:
Returns the Class object associated with the class or interface with the given string name.
An example would be:
Class threadClass = Class.forName("java.lang.Thread");
Note that the name of the class needs to be fully qualified, not just Thread but java.lang.Thread.
The object you are getting is, as said, a representation of the corresponding class. You can use it to dynamically create instances, check methods, and so on. Here is its documentation and here is an example:
Class<?> threadClass = Class.forName("java.lang.Thread");
// Dynamically create a thread, unchecked cast
Thread thread = (Thread) threadClass.newInstance();
You can check whether two objects are of the same class by using the getClass (documentation) method which every object has:
if (first.getClass().equals(second.getClass()) {
// Same
} else {
// Different
}
However note that this comparison is strict. It would throw false if you compare Integer and Number although Integer extends Number. If you want a less strict variant you may use the instanceof operator:
if (first instanceof second) {
// Is type of
} else {
// Not type of
}
are you sure you wouldn't rather use isInstance?
You could change your method to take a Class instead of a String, since that's what you're really using, a Class.
public A[] getB(Class type){
// I'm assuming you have an array of all As somewhere, called Aarray here
List<A> BList = new ArrayList<>();
for(int i = 0; i < Aarray.length; i++){
if(type.isInstance(Aarray[i])){
BList.add(Aarray[i]);
}
}
return BList.toArray();
}

call getter of property after getting value from variable

I am trying to call getter method on object but which getter to call depends on the value in a variable.
public void met1(String var) {
MyClass m = new MyClass();
if(var.equals("A"))
m.getA();
if(var.equals("B"))
m.getB();
if(var.equals("C"))
m.getC();
}
This is one way. Another could be using switch but I don't want to hardcode values as they may change. Is there any better way of doing this?
String is a class not a primitive type, you can't compare instances of String class like var using == this will not work!!!
You need to use method equals like: if(var.equals("A")) then ... .
Apart form that this way is fine.
Another way would be using reflection without if-statement:
Class<?> c = Class.forName("MyClass");
Object my_object = c.newInstance();
Method setNameMethod = my_object.getClass().getMethod("get"+var,String.class);
setNameMethod.invoke(my_object, var);

Access variables outside a class that extends another class

How can I access variable outside a class that extends an other class that is used in an array list? I get an error that says that the variable does not exist in the extended class. Take a look, I want to access the variable members without having to declare it in my Object class:
public abstract class Object {
public int x, y;
}
public class House extends Object {
public int members = 10;
}
// Somewhere else
ArrayList<Object> list = new ArrayList<Object>();
list.add( new House() );
for (Object o : list ) {
o.members;
}
The problem is that in the RTS I'm writing, my Object class has over 40 variables, just because it doesn't work to declare them only in the sub class and access them from outside.
Hope you understand. How can I do this?
You can use instanceof and a cast:
for (Object o : list ) {
if (o instanceof House) {
h = (House) o;
h.members;
}
}
However, this is often considered bad design; you should consider defining an appropriate method in Object (which should really have another name, as others have pointed out) and override it in House. Then, you may call that method on an Object without knowing what kind of object it refers to, and if it is a House, the correct method will be called. (Learning how to do this properly, and when to do it, takes a bit of practice - google polymorphy and overriding.)
First do not name your class Object (see the comments). You cannot access member of an Object in your code, because Object has no field member, House has. But an Object does not have to be a House, so it is not guaranteed that it has member.
If you're sure that in this case youre Object is always a House, cast it:
((House) anObject).member;
This way the compiler assumes that you know more than he does about the actual class of the Object and handles it as if it was a House. You can use instanceof to check if the cast is valid.
Hope you understand that you are using the name for your class as 'Object', which is the parent class for all the classes in Java. Now in your environment there will be two Object classes one which java provides from java.lang.Object and another one you have created. So when you are trying to access your class object and trying to get the attributes of that, it is actually not your class object rather it is an instance of java.lang.Object and hence you are running into an issue.
You have to cast o to a House. E.g. ((House) o).members
just cast the member of arraylist like this
((House)o).members;

See if an object is an instance of a class passed through a string

I imagine that there has to be some way to use reflection to do what I want to do.
I need to be able to take a string at runtime that is of a certain class, for example:
string s = "mypackage.MySuperClass"
Then I may have an object of some type. It could be one of the following:
mypackage.MySuperClass obj = new mypackage.MySuperClass();
or
mypackage.MySubClass obj2 = new mypackage.MySubClass();
or
someotherpackage.SomeOtherClass obj3 = new someotherpackage.SomeOtherClass();
What I need to do is see if an object (which its type is determined at runtime), is equal to the string s (which is also determined at runtime via completely different means).
In the cases above I would want obj and obj2 to be the same type as s (since MySubClass is a subclass of MySuperClass), and obj3 would not.
Is there an easy way to do this in java? Possibly something using instanceOf?
Sounds like you want something like this:
boolean isInstance(Object o, String className) {
try {
Class clazz = Class.forName(className);
return clazz.isInstance(o);
} catch (ClassNotFoundException ex) {
return false;
}
}
Or you could do it the other way round - take o's class (o.getClass()), find all ancestor classes and compare their names to className.
You can use Class.forName(String className) to get the Class based on the string value passed in.
If all you're concerned with is whether it is an instance of a particular class, you can then call isInstance(Object o) on the Class to test whether a the parameter is an instance of the class.
If you actually need an object of the class, you can call newInstance() on the Class. You can then test the resulting object with instanceOf against another object.

Categories