I'm not sure if this is possible with Java, but I'm trying to implement an interface that's unavailable at compile time** and pass it to another class as an object of that interface. Let's say I have an interface like:
public interface MyInterface {
void onReceive(int i);
}
and another class like:
public void MyClass {
ArrayList<MyInterface> listenerList = new ArrayList<MyInterface>();
public void add(MyInterface m) {
listenerList.add(m);
}
}
If they were available at compile time, I would be using them like:
blah = new MyInterface() {
public void onReceive(int i) {
System.out.println("BLAH");
}
}
MyClass mc = new MyClass();
myClass.add(blah);
I'm wondering if there is a way to write code that does the same as above if the first two classes are only available at runtime.
Thanks in advance!
**I'm trying to use a framework library from Android's ROM, but it is in dalvik bytecode so I can't use it for compilation.
UPDATE: Here's some sample code I used to test the solution:
File a/IIMSListener.java
// Excerpt from decompiled class
public interface IIMSListener
{
void onReceive(int p0, int p1/*, IMSParameter p2*/);
}
File a/IMSRemoteListenerStub.java
// Excerpt from decompiled class
import java.util.concurrent.*;
import java.util.*;
public class IMSRemoteListenerStub
{
public List<IIMSListener> mListenerList = new CopyOnWriteArrayList<IIMSListener>();
public boolean addListener(final IIMSListener iimsListener) {
if (iimsListener != null && !this.mListenerList.contains(iimsListener)) {
this.mListenerList.add(iimsListener);
return true;
}
return false;
}
public boolean removeListener(final IIMSListener iimsListener) {
if (iimsListener != null && this.mListenerList.contains(iimsListener)) {
this.mListenerList.remove(iimsListener);
return true;
}
return false;
}
}
File b/test.java
import java.lang.reflect.; import java.util.;
public class test {
public static void main(String[] args) throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException,
NoSuchMethodException,
SecurityException,
ClassNotFoundException {
// Implement interface
Class<?> IIMSListener = Class.forName("IIMSListener");
Object listenerInstance = Proxy.newProxyInstance(IIMSListener.getClassLoader(), new Class<?>[]{IIMSListener}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("onReceive")){
System.out.println("ARGS: " + (Integer)args[0] + ", " + (Integer)args[1]);
return 1;
}
else return -1;
}
});
// Test
Method onReceive = listenerInstance.getClass().getDeclaredMethod("onReceive", new Class[] { int.class, int.class });
onReceive.invoke(listenerInstance, new Object[] { 1, 2 });
try {
// Pass to another class
Class IMSRemoteListenerStub = Class.forName("IMSRemoteListenerStub");
Constructor ctor = IMSRemoteListenerStub.getConstructor();
Object stubInstance = ctor.newInstance(new Object[] {});
Method addListener = stubInstance.getClass().getDeclaredMethod("addListener", new Class[] { IIMSListener });
addListener.invoke(stubInstance, new Object[] { listenerInstance });
// Test
Field mListenerList = IMSRemoteListenerStub.getField("mListenerList");
List<?> list = (List<?>)mListenerList.get(stubInstance);
onReceive.invoke(list.get(0), new Object[] { 3, 4 });
}
catch (InstantiationException e) {}
catch (NoSuchFieldException e) {}
}
}
Execution:
$ cd b
$ CLASSPATH=".:../a" java test
ARGS: 1, 2
ARGS: 3, 4
The implements keyword is used to implement an interface . The interface keyword is used to declare a special type of class that only contains abstract methods. To access the interface methods, the interface must be "implemented" (kinda like inherited) by another class with the implements keyword (instead of extends ).
Using Arrays. One final use of reflection is in creating and manipulating arrays. Arrays in the Java language are a specialized type of class, and an array reference can be assigned to an Object reference. This example creates a 10-long array of Strings, and then sets location 5 in the array to a string value.
An interface can extend any number of interfaces but one interface cannot implement another interface, because if any interface is implemented then its methods must be defined and interface never has the definition of any method.
We can use newInstance() method on the constructor object to instantiate a new instance of the class. Since we use reflection when we don't have the classes information at compile time, we can assign it to Object and then further use reflection to access it's fields and invoke it's methods.
If it is going to be same interface then use Dynamic Proxies
//Loading the class at runtime
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException {
Class<?> someInterface = Class.forName("SomeInterface");
Object instance = Proxy.newProxyInstance(someInterface.getClassLoader(), new Class<?>[]{someInterface}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//Handle the invocations
if(method.getName().equals("someMethod")){
return 1;
}
else return -1;
}
});
System.out.println(instance.getClass().getDeclaredMethod("someMethod", (Class<?>[])null).invoke(instance, new Object[]{}));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With