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();
}
Related
This question already has answers here:
Java generics type erasure: when and what happens?
(7 answers)
Closed 7 months ago.
Given a Set<X>, I want to write a method that acts differently depending on the class X is. In actuality, I'd have 2 cases: A or B.
The method looks like:
public<X> boolean myMethod(Set<X> mySet)
{
// if X is actually the class A
...
// if X is B
...
}
I am not sure how to check this. I tried X::getClass, but it wouldn't let me use equals method.
In a general sense, this is not possible
Due to type erasure, a Java Set does not have a generic type at runtime. Generics act as compile-time checks on the objects passed into methods, but consequently the specific values are not available at runtime. A Set<String> is the same class as a Set<Map<Integer, Thread>> and the same class as a bare Set.
Potential workaround with class parameter
If you really need to know this, you could change the signature of your method to be:
public <X> boolean myMethod(Set<X> mySet, Class<X> clazz)
Now you have a Class instance available at runtime, which is guaranteed to be compatible with X. This you can introspect (e.g. String.class.isAssignableFrom(clazz)).
There are two drawbacks to this approach: firstly, you'll have to explicitly pass in the extra parameter each time the method is called. Secondly, if A and B can be subclasses of one another, this is not going to work; you could pass in e.g. B.class even when the generic parameter was A.
However, this feels like a code smell
You shouldn't be trying to do fundamentally different things based on a generic parameter. Instead of switching behaviour in your method here, do something different within the classes A and B:
public<X> boolean myMethod(Set<X> mySet)
{
boolean result = false;
for (X x : mySet) {
result &= x.doSomething();
}
return result;
}
class A implements MyDoSomethingInterface {
public boolean doSomething() {
// Here you put the logic for "if X is A"
}
}
class B implements MyDoSomethingInterface {
public boolean doSomething() {
// Here you put the logic for "if X is B"
}
}
And if your reaction is that this won't work because A and B are built-in classes, you'll need to wrap them in your own domain objects (which is the correct approach anyway because you want to associate this extra behaviour with them).
I suggest you take one object from set and check class of single object
like below, please check
public<X> boolean myMethod(Set<X> mySet)
{
Object tmpObj = null;
for(Object obj : set){
tmpObj = obj;
break;
}
if(tmpObj instanceof A){
// if X is actually the class A
}else if(tmpObj instanceof B){
// // if X is B
}
}
I have an Interface IGeneralEvents and I have implemented three classes based on it Social, Sport and Traditional. All three of them are using singletons to make sure they are only instantiated once.
The three classes have some additional methods in them which are unique for each one.
I have also created a class to manage these events named EventManager. Depending on the date and time one of these three events will occur through the EventManager. The EventManager will instantiate one of them like below:
public class EventManager {
public EventManager() {
if (time_is_right()) {
Social social_event = Social.getInstance();
}
}
}
In another class I need to know which is the current running event. So my approach of a solution was to do the following:
public class EventManager {
public static IGeneralEvents current_event_instance = null;
public EventManager() {
if (time_is_right()) {
Social social_event = new Social.getInstance();
current_event_instance = social_event;
}
}
}
I created a static variable in the EventManager of type IGeneralEvents and tried to pass the instance of the event when it was decided in the constructor. When I do that and I call the current_event_instance with a method that does not exist in IGeneralEvents (e.g current_event_instance.chat()) then I obviously get java: cannot find symbol as the method is not available in the Interface.
What is the proper way to follow in order to be able to call something like current_event_instance.chat() from other classes ?
There's instanceof which checks if any given reference is an instance of the stated class, and there's the cast operator which does many completely unrelated things - one of them is to treat a given object as some more specific type - if it is of that type, then you can treat it as that type. If it is not, you get a ClassCastException. Combining them:
if (currentInstance instanceof A) {
A a = (A) currentInstance;
a.methodThatIsOnlyInA();
}
There's also the .getClass() method that all classes have; but note that if there's also, say, class AChild extends A{}, then:
Iab a = new AChild();
System.out.println(a instanceof A); // Prints true
System.out.println(a.getClass() == A.class); // Prints false
System.out.println(a instanceof AChild); // Prints true
System.out.println(a.getClass() == AChild.class); // Prints true
Why is second SOP showing output as true here, I was hoping it would display false like first SOP ?
public class reflect1 {
public static void main(String[] args) {
Reflect1A obj1 = new Reflect1A();
Reflect1A obj2 = new Reflect1A();
System.out.println(obj1 == obj2);
Class c1 = obj1.getClass();
Class c2 = obj2.getClass();
System.out.println(c1 == c2);
}
}
class Reflect1A {
}
From the Java Language Specification
The method getClass returns the Class object that represents the class of the object.
A Class object exists for each reference type. It can be used, for
example, to discover the fully qualified name of a class, its members,
its immediate superclass, and any interfaces that it implements.
Since both your objects are of type Reflect1A, they both return the same Class object.
You would get the same object by doing
Class<?> clazz = Class.forName("com.example.Reflect1A")
System.out.println(c1 == clazz); // true
(though this is not necessarily required by all classloaders.)
The values of obj1 and obj2 refer to different objects - when you use == in Java and both operands are references, the result is to compare whether those references refer to the exact same object. In this case you've got two different objects, so the references are not the same.
However, they're both of the same class, so that's why c1 == c2 is true.
The first line prints false because it is a different instance of the same class.
The second line prints true because it is the same class type. There is a obscure gotcha here to be aware of, if you're in a multiple classloader environment, e.g. an application server like JBoss, or OSGI etc, it is possible for two class instances to not be equal
An object is equal (==) only to itself. So clearly both getClass() statements are returning the same Class object
Because obj1 and obj2 are different instances (first check is false) of the same type (class - second check is true).
https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#getClass%28%29
why did you expect to return false?
The operator == compares the references in which the objects are created by default
Obj1 and Obj2 are of same type class Reflect1. For these objects are equal only when compared like this obj1.equal(obj2).
While the class type of obj1 and obj2 are the same == operation will be true.
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.
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.