What I\'d like to be able to do is to load set of classes, probably all in the same folder. All of which implement the same interface and are the same class, then in my code
The only framework I know which does support what you are after is OSGI:
Its network model, described in this article "Exposing the boot classpath in OSGi", does allow that
One of the side effects (or aims) of the networking model is type isolation or class versioning: multiple version of the same class can coexist nicely inside the same VM since each one is loaded into its own network, its own space.
See this tutorial for beginning and choose on eof the OSGI Framework (like Equinox, Knoplerfish or Apache Felix)
If you can use OSGI, its as simple as snapping a finger! In oSGI you can have multiple verssions of the same class. All you do is have same bundles with different versions.
Otherwise you can still write your custom class loader that reads both the classes. One way of doing it would be like this. You write two ClassLoaders, one of them loads one version of the class and the other loads the other version of the class. Now based on the need you choose the classloader1 or classloader2 to load the class. So now you can also have multiple versions of the same class loaded simultaneously in the memory.
Note: Make sure this is actually you want to do, there may be other ways of coming around your problem.
Jim's response is good - you name the classes you want to use, and they all conform to a common API. However the solution given assumes the classes are all available on the classpath of the application already. You may be wanting to be able to add more implementations later, e.g. after the application is installed.
If thats the case, then you'll probably need to use a custom classloader. For example, you could allow people to put jar files inside a particular folder somewhere, and to add the class names of the implementations to a properties file. You would then need a custom classloader than can load classes from the jars inside that folder, and you would use that classloader to load the classes (e.g. using Class.forName(className, classLoader)).
In fact if you have a classloader per jar file, you will be able to have multiple classes with the same names across the jar files, as the classloader defines the class name boundaries. This is pretty much what OSGI is doing.
Here's some code relating to loading classes from jars:
http://sourceforge.net/projects/jcloader/ http://www.javaworld.com/javatips/jw-javatip70.html
It can be done using dynamic class loading. It is not loading class of different version but different sub-classes of a super class or interface.
The important steps are:
(1) Use Class.forName(...) to load a class by name. The class must be in the class path.
(2) Use aClass.newInstance() to instantiate the object. This is easy if there is no parameter needed for the constructor.
The following code should provide some idea for you. It does not handle exception which you have to do it.
class Context {
void moveUp();
void moveDown();
...
}
interface AI {
void action(Context con);
}
public class Game {
public Game() {
Context aContext = new Context();
String[] aAIClsNames = this.getAIClassNames("ai.list");
AI[] aAIs = this.loadAI(aAIClsNames);
this.run(aAIs);
}
String[] getAIClassNames(String pAIClassListFile) {
// .. Load the file containning the AI-class file names
}
AI[] loadAI(String[] pAIClsNames) {
AI[] AIs = new AI[pAIClsNames.length];
for(int i = 0; i < pAIClsNames.length; i++) {
String aAIClsName = pAIClsNames[i];
// (1) Get the class by name
Class<? extends AI> aAICls = Class.forName(aAIClsName);
// (2) Notice the cast as all of class in the list must implements AI
AIs[i] = (AI)aAICls.newInstance();
}
return AIs;
}
void run(AI[] pAIs) {
// ...
}
}
Hope this helps.
It is possible to do what you want with OSGI but you could as well use a custom classloader. The idea is that you have to instanciate a classloader for every version of the class you want to load. Here you can find a good explanation.
But I think what you really need to solve your problem is something based on interfaces like described by Jim Garrison or Dave L Delaney...
Have you tried something like:
class Move; // some data type that is able to represent the AI's move.
interface AI {
Move getMove( GameState state);
};
AIOne implements AI;
AITwo implements AI;
Each class would implement its own algorithm for generating a move, but would be called but called by common method