Is something like that possible.
List<?> myList = getMyList();
class cls = class.forname("com.lab.myClass");
cls = myList.get(0);
cls.getValue();
Create an Instance with the fully-qualified name of a class and use their declared Methods?
No, if you call Class.forName, at compile time you know nothing about the returned Class instance. You don't even know that it represents a class; it might be an interface for example. In particular, if it is a class and you create an instance of it, you cannot call any methods of it except those which are already defined in Object because, at compile time, the compiler cannot check whether these methods exist.
The are two solutions:
First, you can use reflection to find out about the methods the class has, and to call these methods. This is very cumbersome.
Second, if you use Class.forName to dynamically load classes at runtime, often you know something about the classes you load. For example, you might know that the class implements a certain interface. Then you can cast the result of newInstance to this interface and then call the methods defined in this interface directly.
For example:
// in file Plugin.java
interface Plugin {
void doSomething();
}
// in file Main.java
public class Main {
...
void runPlugin() {
try {
Class<?> pluginClass = Class.forName("pkg.name.MyPlugin");
Plugin plugin = (Plugin) pluginClass.newInstance();
plugin.doSomething();
}
catch (...) {
// catch the necessary exceptions
}
}
}
Related
public interface A {}
public interface B {}
public class Test implements A{}
public class Test2 {}
I made a method which checks if a class implements an interface. I want my method to only accept generic interfaces and not all class objects.
method
public static boolean containsInterface(Class clazz, Class intf)
{
try
{
Validate.isTrue(intf.isInterface());
if(clazz.isInterface())
return JavaUtil.isClassExtending(intf, clazz);
for(Class c : ClassUtils.getAllInterfaces(clazz))
{
if(JavaUtil.isClassExtending(intf, c))
return true;
}
}
catch(Throwable t)
{
t.printStackTrace();
}
return false;
}
Since Test.class & Test2.class are not interfaces on the 2d parameter I want it to have a compile error since the 2d parameter must be an interface class
containsInterface(Test.class, Test.class);
containsInterface(Test.class, Test2.class);
acceptable use of my method
containsInterface(Test2.class, A.class);
containsInterface(Test.class, B.class);
what I tried
public static boolean containsInterface(Class clazz, Class<? extends Interface> intf)
I currently check if the class in the parameter is an interface then throw an exception. I would rather force people to not be able to call the method to begin with if it's not an interface
I am aware of Annotations and Enum objects are available to use as a class signature to make sure people are using the parameters right but, I can't seem to find the one for the interface itself.
I was told generics do not support interfaces or abstract classes type is this true even in jre 9-13+
You cannot force argument to be ANY interface implementation using type control system. The same would apply if you would like to eg force only Class<?> with abstract modifier. I am not sure if that is really needed as doing simple type isInterface assert is
Straigthforward
Clean
Robust
Easy to understand
Error prone
Testable
JDK Engineers does not care about that either. As an perfect example of such mechanism would be used (but there is none) is JDK Dynamic Proxy creation. You can create only create proxy of an interface (or set of) but not of class.
I don't think that it is just worth of the effort to write own preporocessors. Moreover it would be not universal - as you assume that runtime type must be know at compile time - what about dynamically loaded classes etc?
Intefaces in java has no super class that you can use in generic mode.
If you try get the super class of an interface with reflection returns null.
public static void main (String [] args) {
System.out.println(A.class.getSuperclass());
}
interface A {}
Output:
null
I know I can get the method and classname from StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); but that is not what I want.
I want the class object, so I can access his interface, annotations, etc...
It is possible?
Class<?> classObject = getCallerClass();
I see this question, but that is just for the classname.
How to get the caller class in Java
Edit: Now I'm passing the class this way:
someService.dummyMethod(foo1, foo2, new Object(){}.getClass());
someService(String foo1, int foo2, Class<?> c) {
// stuff here to get the methodname,
// the interface of the class and an annotation from the interface.
}
I call someService from a lot of different classes, If is not possible I will continue this way, but If there is a way to get the caller class at runtime I prefer that way.
If you're using Java 9+ you can use java.lang.StackWalker.
public void foo() {
Class<?> caller = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.getCallerClass();
}
However, since StackWalker is thread safe it might be beneficial to create an instance and store it somewhere (rather than create a new instance every time the method is called).
Javadoc of getCallerClass():
Gets the Class object of the caller who invoked the method that
invoked getCallerClass.
This method filters reflection frames, MethodHandle, and hidden frames
regardless of the SHOW_REFLECT_FRAMES and SHOW_HIDDEN_FRAMES options
this StackWalker has been configured with.
This method should be called when a caller frame is present. If it is
called from the bottom most frame on the stack, IllegalCallerException
will be thrown.
This method throws UnsupportedOperationException if this StackWalker
is not configured with the RETAIN_CLASS_REFERENCE option.
Get the classname using the code of your linked question: How to get the caller class in Java
Then use the classname to retrieve the class, using code from here: Getting class by its name
Complete code:
String callerName = Thread.currentThread().getStackTrace()[2].getClassName();
try {
Class<?> caller = Class.forName(callerName);
// Do something with it ...
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
(community answer, since only mix of existing answers).
Suppose I have a class Foo in package my.package which contains some static fields.
I want to use reflection to get the values of those static fields.
I know I can write my.package.Foo.class.getDeclaredField(... but this is unsatisfactory as I'm hardcoding the class and package names.
I'd like to use this.class.getDeclaredField(... but this is invalid in Java even if called from within a non-static member function.
Is there a way?
Every class inherits the instance method Object#getClass(). Invoke that to get your instance's corresponding Class object.
I don't know why you would do this inside Foo as Foo already knows its static fields and you'd have access to them at compile time directly.
Non-statically, you can use this.getClass() to get the current class, as #sotirios-delimanolis mentioned.
Statically, you can do this, though it is a bit ugly:
public static Class<?> getCurrentClassStatic() {
try {
return Class.forName(new Throwable().getStackTrace()[0].getClassName());
} catch (ClassNotFoundException e) {
return null; //Shouldn't happen...
}
}
I have a class named Agent:
abstract public class Agent {
// this class doesn't has the method "method_A"
}
And a class AgentHistoric:
public class AgentHistoric extends Agent{
public void method_A(){
code
}
}
I have also classes RandomAgent, AgentAlways0, etc, all extending the abstract class Agent, but only AgentHistoric has the method "method_A".
Suppose I created AgentHistoric's objetcs, RandomAgent's objetcs, etc, and I have added them to an ArrayList named agents.
In another class, I have the following code:
for (Agent ag: this.agents ){
ag.update(); // all Agent's subclasses have this method
if (ag.returntype() == AgentHistoric){ // I know there's a more elegant way, but OK
method_A() } // error!
}
How can I execute a exclusive method of AgentHistoric in this loop?
Use the instanceof operator to determine if ag is an AgentHistoric. If so, cast ag to an AgentHistoric, then call method_A.
Maybe try to use instanceof operator?
if (ag instanceof AgentHistoric){
...
}
Instead of using instanceof, a more "OO way" of doing it is just NOT override method_A in the classes that you want to run Agent.method_A() or if you want to do additional work, call super.method_A() while in the classes that you want to change the implementation - override the method.
The compiler only knows that the variable ag is of type Agent which, as you said yourself, has no method_A defined. In order to call method_A, you need to cast ag to an instance of AgentHistoric.
As others have said, you can use the instanceof operator to check that the current assignment of ag is in fact an AgentHistoric instance.
I'm having trouble to find how to typecast the dynamically created class while using reflection.
String s;
...
Class unknownClass = Class.forName(s);
Constructor defaultConstructor = unknownClass.getConstructor(null);
Object retobj = defaultConstructor.newInstance(null);
retobj.Writeout(); // This won't work since;
The object class does not have a method called Writeout, but that is the name of the method which is shared by nine other possible classes that is dynamically created here (needless to say every Writeout method does a seperate thing). Any suggestions ? Thx in advance for your time.
Use reflection Luke...
Method writeOutMethod = unknownClass.getMethod("Writeout", new Class[]{});
writeOutMethod.invoke(retobj, new Object[]{});
Or, ensure that your objects implement a well known interface (the clean approach).
The 9 classes should all implement a single interface (let's call it Output) which declares the writeOut() method. The code would thus be:
Output retobj = (Output) defaultConstructor.newInstance(null);
retobj.writeOut();
Note that you could just use unknownClass.newInstance() to invoke the no-arg constructor.
Side note: please respect tha Java naming conventions: methods start with a lower-case letter.
Cast it:
((YourObjectWithThatMethod) retobj).Writeout();
EDIT (see the comment from Kevin Welker):
If all of your 9 classes implement the same interface, you can cast every class to that interface:
((YourInterface) retobj).Writeout();
If all nine classes share a super-class or an interface which declares/implements writeOut then you can cast retobj to that interface and then call it.
public interface Writable {
public void writeOut();
}
Then each class needs to have in the class declaration.
class MyClass implements Writable {
}
Then you can say
((Writable) retobj).writeOut();