1

Here's something that's got me a bit stumped but intrigued all the same. In my Android game I have various Levels that extend the superclass Level. What I am trying to do is build a levelDirectory (based on the Singleton DP) that essentially is an object that has a HashMap object within it that stores all the Level subclasses. Here is my question:

We're all familiar with the enhanced for loop, but how can I write something that would be the equivalent of

for(Level l : An Array Of Every Level Subclass In My Project that is an Extension of the Level Superclass){

HashMap.put(l.name, l);

}

I am trying to build a system that can dynamically update itself when I add more and more level subclasses. I know having a method in Level that submitted itself to the static Directory and was called in the Level's constructor is an option, But I'm just wondering whether there is a way of doing what I said above in that enhanced for loop?

Many thanks

Darius
  • 5,180
  • 5
  • 47
  • 62
  • Since you said you are intrigued by the subject itself, take a look at jhats oql console - it is of no use for the problem you describe, but creating queries over a whole heap of objects using a oql/javascript mix is a great fun (people who program dynamic languages and consider Java "uncool" are usually very impressed on seeing this) – fdreger Dec 31 '10 at 15:25

6 Answers6

2
  1. The question itself is wrong. You cannot loop over List ("Every Level Subclass In My Project") and get instances of Level. l should be Class.

  2. From the context, I think you meant "every instance of every Level subclass". No, it is not possible - a virtual machine is not and should not be a database. You cannot just query for objects, you have to manage references in your code (but that you already knew that - your constructor solution will work).

fdreger
  • 12,264
  • 1
  • 36
  • 42
  • Many thanks, I think I will stick with the way I was going then – Darius Dec 31 '10 at 12:49
  • I disagree that the runtime shouldn't be able to provide you at least a list of all loaded classes. I think you misunderstood the question. He doesn't need every instance, but rather every class. – tster Dec 31 '10 at 14:44
  • @tster: Read the question again, especially the fragment: "I know having a method in Level that submitted itself to the static Directory and was called in the Level's constructor is an option". It clearly shows that the question was about instances. – fdreger Dec 31 '10 at 15:15
  • @tster: also, even if the question was about classes (although representing levels with static classes might seem strange), listing every *loaded* class would not be a solution, as jvm and dalvik load classes on demand. You could not use such utility to discover classes dynamically. That is why Java SE includes the ServiceLoader API. – fdreger Dec 31 '10 at 15:21
2

Option 1:

Lately I had to solve a similar problem within JavaSE. I'm using the Google Reflections Library for that:

http://code.google.com/p/reflections/

However I'm not sure if it can run with Android. I think it's worth to give it a try, since it's quite easy to use. In your case you would do something like:

Reflections reflections = new Reflections("my.project.prefix");
Set<Class<? extends Level>> subTypes = reflections.getSubTypesOf(Level.class);

That would give you a Set (subTypes) to iterate on and put it in the HashMap.

Option 2:

You could maybe use custom annotations to annotate your Level classes, for example:

@Level public class MyCustomLevel {}

Then use a custom annotation processor which implements AbstractProcessor to process the annotation at compile time. Implement the process method to find all classes annotated with your @Level annotation. Now you can write the full names of the found classes to a property file in your META-INF dir. From your application you can read this property file and instantiate the classes using reflection.

Robe Elckers
  • 967
  • 1
  • 6
  • 19
1

If you're trying to dynamically fetch the list of all classes that extend Level at runtime, that's not really possible, I'm afraid. Have a look at this thread: How do you find all subclasses of a given class in Java?

Community
  • 1
  • 1
Costi Ciudatu
  • 37,042
  • 7
  • 56
  • 92
0

Don't know much about Android but sounds like Reflection might help here, so what do you know about reflection in Java?

EDIT

Didn't know you had to limit yourself to loaded levels. That being the case you would want to do your tracking on every instance as it is created pretty much like you proposed in your question.

My idea involved parsing all the directories of a project looking for subclasses - it could be done once at the start of program execution but it would list levels that may never get instantiated...

BigMac66
  • 1,528
  • 5
  • 19
  • 35
  • There isn't a way, to my knowledge, of enumerating all the currently-loaded classes using reflection. – C. K. Young Dec 31 '10 at 12:42
  • I am reasonably happy with the implementation I've built so far, where like I've said above, in each level subclass it has inherited the superclass constructor that submits itself to a static levelDirectory. I suppose this achieves the same thing, but I wondered whether it was possible to do it this way, but it would appear not then? – Darius Dec 31 '10 at 12:45
  • Android is very much a rehashing of Java, with the exception of the hardware-centric API's and abstract methods that you need to implement! – Darius Dec 31 '10 at 12:46
0

I think you might want to make the level an interface and then check if it's an interface.

In its most common form, an interface is a group of related methods with empty bodies. A bicycle's behavior, if specified as an interface, might appear as follows:

interface Bicycle {

       void changeCadence(int newValue);   // wheel revolutions per minute

       void changeGear(int newValue);

       void speedUp(int increment);

       void applyBrakes(int decrement);
}

To implement this interface, the name of your class would change (to a particular brand of bicycle, for example, such as ACMEBicycle), and you'd use the implements keyword in the class declaration:

class ACMEBicycle implements Bicycle {

   // remainder of this class implemented as before

}

Implementing an interface allows a class to become more formal about the behavior it promises to provide. Interfaces form a contract between the class and the outside world, and this contract is enforced at build time by the compiler. If your class claims to implement an interface, all methods defined by that interface must appear in its source code before the class will successfully compile.

Will
  • 6,179
  • 4
  • 31
  • 49
  • I know about interfaces and implementing them, but that wasn't really what I was asking. Sorry if it was ambiguous! I am going to just use my static solution described above of passing Level subclass objects to the static directory in the constructor of the Level subclass. Thanks for your time though – Darius Dec 31 '10 at 12:55
0

I think standard way in the "spirit" of java is the service provider pattern.

Add a declaration file in the META-INF/services of the "plugin" jar and use java.util.ServiceLoader (http://developer.android.com/reference/java/util/ServiceLoader.html) to enumerate your providers.

mtraut
  • 4,720
  • 3
  • 24
  • 33