I'm trying to build a generic class loader. I need to check classes that I load against a method argument to determine if they are of the same class.
The code mostly explains what I'm trying to do.
private static LinkedList<Object> loadObjectsInDirectory(Class class0, File dir) throws ClassNotFoundException {
LinkedList<Feature> objects = new LinkedList<Object>();
ClassLoader cl = new GenericClassLoader();
for(String s : dir.list()) {
Class class1 = cl.loadClass(s);
try {
Object x = class1.newInstance();
if (x instanceof (!!! class0 !!!) ) {
objects.add(x);
}
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
}
}
return objects;
}
How is this achieved?
Looks like you need the isAssignableFrom method
if (kelass.isAssignableFrom(klass)) {
objects.add(x);
}
JavaDoc
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter. It returns true if so; otherwise it returns false. If this Class object represents a primitive type, this method returns true if the specified Class parameter is exactly this Class object; otherwise it returns false.
Specifically, this method tests whether the type represented by the specified Class parameter can be converted to the type represented by this Class object via an identity conversion or via a widening reference conversion. See The Java Language Specification, sections 5.1.1 and 5.1.4 , for details.
Related
Having problems with a factory class, I pass in a human readable name that maps to a class that has a single constructor with a single argument, I get the following error:
java.lang.NoSuchMethodException: com.satgraf.evolution2.observers.VSIDSTemporalLocalityEvolutionObserver.<init>(com.satlib.evolution.ConcreteEvolutionGraph)
at java.lang.Class.getConstructor0(Class.java:2892)
at java.lang.Class.getConstructor(Class.java:1723)
at com.satlib.evolution.observers.EvolutionObserverFactory.getByName(EvolutionObserverFactory.java:84)
at com.satgraf.evolution2.UI.Evolution2GraphFrame.main(Evolution2GraphFrame.java:229)
These are the classes in question, I have about a dozen of these things in different projects, they all work without problem - including one that is almost identical, can't see why this one is failing:
public EvolutionObserver getByName(String name, EvolutionGraph graph){
if(classes.get(name) == null){
return null;
}
else{
try {
Constructor<? extends EvolutionObserver> con = classes.get(name).getConstructor(graph.getClass());
EvolutionObserver i = con.newInstance(graph);
observers.add(i);
return i;
}
catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException | IllegalArgumentException | SecurityException ex) {
Logger.getLogger(EvolutionObserverFactory.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
}
The class being instantiated is:
public class VSIDSTemporalLocalityEvolutionObserver extends JPanel implements EvolutionObserver{
public VSIDSTemporalLocalityEvolutionObserver(EvolutionGraph graph){
...
}
...
}
The argument graph is of type:
public class ConcreteEvolutionGraph extends ConcreteCommunityGraph implements EvolutionGraph{
...
}
getConstructor requires an exact match on the parameter types; it does not attempt to find a 'compatible' constructor. The getConstructor Javadoc simply says "The constructor to reflect is the public constructor of the class represented by this Class object whose formal parameter types match those specified by parameterTypes." (In current OpenJDK, getConstructor delegates to getConstructor0 which loops through all the constructors and compares the given parameter array against constructor.getParameterTypes().)
At runtime, your code looks for a constructor taking a parameter of type ConcreteEvolutionGraph (graph.getClass() returns graph's runtime type), and VSIDSTemporalLocalityEvolutionObserver doesn't have one.
If you're really looking for a constructor taking EvolutionGraph, pass EvolutionGraph.class to getConstructor instead. If instead you want any constructor that could be called with the graph's runtime type, you'll need to manually loop over the result of getConstructors() looking for a single-argument constructor for which graph.getClass().isAssignableTo(ctor.getParameterTypes()[0]). Note there may be more than one, and when interfaces are involved, there may not be a most-specific one. You'll have to decide how to break ties.
Is it possible to get the type of a variable that is declared (but not instantiated) in Java?
for example:
public class Foo {
FooTwo foo2;
FooTwo foo3;
FooThree foo4;
public static void main(String[] args) {
if (foo2.getClass() == foo3.getClass()) {
System.out.println("foo2 is the same type as foo3");
}
if (foo3.getClass() == foo4.getClass()) {
System.out.println("foo3 is the same class as foo4");
}
}
}
With output:
foo2 is the same type as foo3
obviously the method getClass() does not work on an uninstantiated variable, so this code does not function. I am assuming that the information I am looking for is stored somewhere in the variable (pointer?) for type safety, and that it may be accessible. Is it possible to Achieve this comparison?
the reason:
I have a class with several declared variables. These variables are supposed to point to objects stored in an ArrayList in another class. I am trying to create a method that will take an initialized (but uninstantiated) variable as a parameter, scan the arraylist for an object matching the type of the initialized variable, and set the variable to the object (Make the variable point to the object).
ALSO: The point of the system is to remove coupling in the constructor of the class. The objects cannot be instantiated immediately or in the constructor.
To start with, you need to be aware of the difference between the type of an expression and the runtime-type of a value. Consider, for example, the following code:
List<String> list = new ArrayList<String>();
System.out.println(list.getClass());
The above code prints class java.util.ArrayList, not java.util.List<java.lang.String>, because getClass() returns the runtime-type of the object that list refers to, not the type of list itself.
So it doesn't make sense to call getClass() on an uninitialized variable, because there's no value for it to return the runtime-type of.
I am trying to create a method that will that will take an initialized (but uninstantiated) variable as a parameter, […] and set the variable to the object (Make the variable point to the object).
Since Java is a pass-by-value language, it doesn't expose a way to modify a variable that is passed in as a parameter. For example, consider this method:
public void doNothing(Object obj) {
obj = "obj";
}
The above method does absolutely nothing. It has a local variable obj, which originally contains whatever reference is passed in, and then is changed to refer to the string "obj" instead; but this change has no effect, because nothing actually uses the local variable obj after that point. In particular, this method does not have any effect on whatever reference was passed in.
The closest you can get is to use reflection; if your method takes an instance of type Field, it can both examine the declared type of the field, and set the field to a value of its choosing.
You can do something similar using reflection. Here is an example code snippet. But may be there is a better way to solve your problem if you explain your use case in a bit more in detail.
import java.lang.reflect.Field;
public class Foo {
static FooTwo foo2;
static FooTwo foo3;
static FooThree foo4;
public static void main(String[] args) {
try {
Field foo2Field = Foo.class.getDeclaredField("foo2");
Field foo3Field = Foo.class.getDeclaredField("foo3");
Field foo4Field = Foo.class.getDeclaredField("foo4");
if (foo2Field.getType().equals(foo2Field.getType())) {
System.out.println("foo2 is the same type as foo3");
}
if (foo3Field.getType().equals(foo4Field.getType())) {
System.out.println("foo3 is the same class as foo4");
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
// TODO handle this if this can happen
} catch (SecurityException e) {
e.printStackTrace();
// TODO handle this appropriately
}
}
}
class FooTwo {
}
class FooThree {
}
For the primitive types: int, double, short, etc...
Given:
String typeName = "double";
How do I get double.class?
For a regular class we can do the following:
String typeName = "java.lang.Integer"
Class<?> clazz = Class.forName(typeName);
// Class.forName(typeName) returns Double.class
You can't do that. Check out the reflection documentation. Go to the "Class.forName()" section and there, you can find a note:
This cannot be used for primitive types.
One option might be to create a method that will recognize the primitive types and return the matching class (i.e. Integer.class, Double.class, etc...)
Rather than trying something clever, since there are only 8 primitives would it be so bad to write a switch/case statement, or hard code them in some other way such as a Map (suggested by Scorpion in comment below) ?
The Spring Framework takes this approach for its version of Class.forName.
Here's the code to find the class of a primitive type when all you know is it's name.
public class CheckPrimitve {
public static void main(String[] args) {
Sample s = new Sample();
try {
System.out.println(s.getClass().getField("sampleDouble").getType() == double.class); // returns true
System.out.println(s.getClass().getField("sampleDouble").getType().isPrimitive()); // returns true
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
class Sample {
public double sampleDouble;
public Sample() {
sampleDouble = 10d;
}
}
If you click on #mprivat's link and read the section on "The .class Syntax," what you get at the very beginning is:
If the type is available but there is no instance then it is possible
to obtain a Class by appending ".class" to the name of the type. This
is also the easiest way to obtain the Class for a primitive type.
So double.class works just fine.
How can i compare 2 classes?
The following if statement never passes although class is type of MyClass:
public void(Class class) {
if (class == MyClass.class){
}
}
if (clazz.equals(MyClass.class)) {
}
BTW, class is a reserved word.
To test whether clazz is a (sub) type of MyClass do
MyClass.class.isAssignableFrom(clazz)
From the javadoc for Class.isAssignableFrom
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter. It returns true if so; otherwise it returns false. If this Class object represents a primitive type, this method returns true if the specified Class parameter is exactly this Class object; otherwise it returns false.
Specifically, this method tests whether the type represented by the specified Class parameter can be converted to the type represented by this Class object via an identity conversion or via a widening reference conversion. See The Java Language Specification, sections 5.1.1 and 5.1.4 , for details.
So
Object.class.isAssignableFrom(String.class)
is true because each String is also an Object but
String.class.isAssignableFrom(Object.class)
is false because not all Objects are Strings.
The name "isAssignableFrom" comes from the fact that,
Class1 x = (Class2) null;
is only legal when
Class1.class.isAssignableFrom(Class2.class)
I.e., we can assign a field or variable with static type Class1 a value that comes from an expression whose static type is Class2.
You can use == or .equals() to compare Class objects.
Example:
class MyClass
{
public static void main (String[] args) throws java.lang.Exception
{
MyClass m = new MyClass();
if (MyClass.class == m.getClass())
{
System.out.println("it worked");
}
}
}
Demo: http://ideone.com/AwbNT
You can use instanceof operator to check if an instance belongs to a specific class or its subclasses.
class MyClass{}
class SubClass extends MyClass{}
public static void main(String args[]) {
SubClass object = new SubClass();
if (object instanceof MyClass) {
System.out.println("It works, too");
}
}
I use a class that makes my Hibernate Query through a FilterCriterionList (sort of finder) and it's always worked perfectly until now and triggers a NullPointerException and I have absolutely no idea as to why it's triggered.
This is the method (in ReflectionUtil) that triggers the nullpointer with the following values (mind you that the other values thrown at it work perfectly and it's just these that seem to give an error):
type = interface java.util.List
fieldName = parameter
First it throws the NoSuchFieldException and on it's second run (as it's called again at field = getField(type.getSuperclass(), fieldName);) makes it throw a NullPointerException and just stop dead (all of this happens in my UnitTest, not a live environment yet).
public static Field getField(Class type, String fieldName) {
Field field = null;
try {
field = type.getDeclaredField(fieldName);
} catch (Exception e) {
if (!type.equals(Object.class)) {
field = getField(type.getSuperclass(), fieldName);
}
}
return field;
}
Any ideas as to why this happens (or what I can do to fix it?). I can't really show off more code as it's quite complicated and it's company code.
java.util.List is an interface, therefore calling getSuperclass() on it results in null.
The correct way to apply getField() recursively is the following:
} catch (Exception e) {
Class superclass = type.getSuperclass();
if (superclass != null) {
field = getField(superclass, fieldName);
}
}
You called like this:
getField(List.class, "parameter");
It would have never worked as List is an interface and it doesen't have any field called parameter. For the second call, its' null because interface List doesnet have a superclass.
From the Class.getSuperclass documentation
Returns the Class representing the
superclass of the entity (class,
interface, primitive type or void)
represented by this Class. If this
Class represents either the Object
class, an interface, a primitive type,
or void, then null is returned. If
this object represents an array class
then the Class object representing the
Object class is returned.