SaintLike
SaintLike

Reputation: 9589

Using reflection in Java

I need some help with reflection, since I can't make my code work the way I want to.

I have the following:

nrThreads = Utilities.getNumberOfThreads(filePath, propertiesFile);
testName = Utilities.getTestName(filePath, propertiesFile);  
System.out.println(Utilities.nowDate());
System.out.println("Inserting...");

switch (testName)
{
case "InsertAndCommit":
      final InsertAndCommit[] threads = new InsertAndCommit[nrThreads];
      for (int i = 0; i < nrThreads; i++) {
        threads[i] = new InsertAndCommit();
        threads[i].start();
      }                         
      break;            
case "CommitAfterAllInserts":
      final CommitAfterAllInserts[] threads1 = new CommitAfterAllInserts[nrThreads];
      for (int i = 0; i < nrThreads; i++) {
        threads1[i] = new CommitAfterAllInserts();
        threads1[i].start();
      }
      break;
      default: break;
}

As you can see, I'm repeating code inside this switch/case. I know I can do that piece of code using reflection but I can't seem to get it right.

I've done the following:

 Class<?> clazz = Class.forName(testName);
 Constructor<?> ctor = clazz.getConstructor(String.class);
 final Object[] obj = (Object[]) ctor.newInstance(); //this line isn't right, I need to declare the "threads" array (equivalent to: final InsertAndCommit[] threads = new InsertAndCommit[nrThreads];)

            for (int i = 0; i < nrThreads; i++) {
                //In this line I need to declare a new "generic constructor" with reflection (equivalent to threads[i] = new InsertAndCommit();) 
                threads[i].start();
            }

I've been reading a lot about reflection and I can't seem to get this right, can you please help me?

Upvotes: 4

Views: 360

Answers (2)

RealSkeptic
RealSkeptic

Reputation: 34648

I think you should be relying on the fact that both of your classes are actually subclasses of Thread (I'm assuming this as you're using start() in both cases).

  • You can create an array of type Thread [] and assign any object of a subclass of Thread to it.
  • You don't need to look up the constructor because your the parameterless construcor can be invoked directly from the class object.
  • A constructor always gives you a single object, not an array of objects. So you should use it only inside the loop, to create each individual thread, not to create the array.

So the missing piece is:

Class<? extends Thread> clazz = (Class<? extends Thread>) Class.forName(testName);
Thread[] threads = new Thread[nrThreads];
for ( int i = 0; i < nrThreads; i++ ) {
    threads[i] = clazz.newInstance();
    threads[i].start();
}

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727047

In this line I need to declare a new "generic constructor" with reflection (equivalent to threads[i] = new InsertAndCommit();)

If you use generics, you do not have to do that through a reflection proper, in the sense that you do not need to work with the constructor object explicitly (although Class.newInstance() and Array.newInstance() methods are part of the Java reflection API).

Since you have Class<T>, and because both classes have parameterless constructors, you can call clazz.newInstance() to create a new object, like this:

public <T extends Thread> T[] makeArray(Class<T> clazz, int n) throws Exception {
    T[] res = (T[]) Array.newInstance(clazz, n);
    for (int i = 0 ; i < n ; i++) {
        res[i] = clazz.newInstance();
        res[i].start();
    }
    return res;
}

Demo.

Upvotes: 5

Related Questions