Armpc
Armpc

Reputation: 53

Pass Class as Type to Other Class with Method in Java

I want to separate 2 class from each other and DataExchange not info of Row Class, but it makes problem.

How to solve this problem?

Code:

class MyActivity {
    public void onCrate() {
        DataExchange de = new DataExchange(BookRow.Class);
        ....
    }

    public class BookRow {
        public String book_id;
        public String book_title;
    }    
}

File DataExchange:

class DataExchange<T> {
    public DataExchange(Class<T> SendedClass) {
        SendedClass[] items = new SendedClass[5]; // main problem
        for(int i = 0; i < 5; i++) {
           items[i] = new SendedClass(i , "my book title" + i); // problem
        }
        // ...
    }
}

Upvotes: 1

Views: 3213

Answers (5)

Michał Schielmann
Michał Schielmann

Reputation: 1382

Try this code:

public class MyActivity 
{
    public void onCrate()
    {
        DataExchange de = new DataExchange(BookRow.class);
    }
}

public class BookRow
{
    public String book_id;
    public String book_title;
}

public class DataExchange<T>
{
    public DataExchange(Class<T> sendedClass)
    {
        try
        {
            T[] items = (T[]) Array.newInstance(sendedClass, 5);
            //or Class<T>[] items = (Class<T>[]) Array.newInstance(sendedClass, 5);
            for(int i = 0; i<5; i++)
            {
               Constructor<T> constructor = (Constructor<T>) sendedClass.getConstructor(Integer.class, String.class);
               items[i] = constructor.newInstance(i , "my book title" + i);
            }
        }
        catch (final Exception e)
        {
            e.printStackTrace();
        }
    }
}

What you did wrong was:

  1. You used BookRow.Class instead of BookRow.class.
  2. In your method declaration you had: public DataExchange(Class<T> SendedClass) and it should be public DataExchange(T sendedClass); Edit: as @Daniel suggested that is not needed - my bad.
  3. You cannot initialize variables like that: sendedClass[] items even if sendedClass is of type Class. sendedClass is a variable and not a type. Thats why you have to use T or Class<T>.
  4. As the above - you cannot initialize a class object using variable - like sendedClass(params). If you know the class type you can use reflection to do that: http://docs.oracle.com/javase/tutorial/reflect/ http://tutorials.jenkov.com/java-reflection/index.html

Upvotes: 1

Daniel
Daniel

Reputation: 1861

You can make use of the reflection to instantiate your objects, but that is not type safe, nor safe in any way ( the constructor Class(int, String) might not exist and you'll get runtime errors).

public class DataExchange<T> {
    public DataExchange(final Class<T> SendedClass) throws IllegalArgumentException, SecurityException, InstantiationException,
        IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        T[] items = (T[])Array.newInstance(SendedClass, 5);
        for (int i = 0; i < 5; i++) {
            items[i] = SendedClass.getConstructor(MyActivity.class , Integer.class, String.class).newInstance(i, "my book title" + i); //1st param is outer class when you try to call constructors for inner classes
        }

    }
}

Upvotes: 0

stealthjong
stealthjong

Reputation: 11093

BookRow should be a static inner class

Your question has two parts, though. One for creating an array based on a generic type, the second constructing an item of that generic type (and setting its values).

public DataExchange(Class<T> SendedClass) {
     // create an array of generic type
     final T[] items = (T[]) Array.newInstance(SendedClass, 5); 
     for (int i = 0; i < 5; i++) {
         // create item of generic type
         T item = SendedClass.newInstance();
         SendedClass.getField("book_id").set(item, "" + i);
         SendedClass.getField("book_title").set(item, "book title"+i);
         // add item of generic type to array of generic types.
         items[i] = item;
     }
     //items is now an array with multiple items
    ...
}

Upvotes: 1

Thomas
Thomas

Reputation: 88757

First, you should adhere to the Java naming convention, to make things easier to understand. In your case SendedClass is a parameter name and not a class name, i.e. it should be sendedClass which then would make it clear that you can't jsut call the constructor as you did.

So actually you can pass in any class and you'd have to call its constructor using reflection, e.g. like this:

items[i] = sendedClass.getConstructor( Integer.TYPE, String.class ).newInstance( i, "my book title" + i);

Just note that such a constructor might not exist and you'd have to account for that as well as for the multitude of exceptions that can be thrown by reflection.

Creating the array would be done in a similar way using reflection:

 T[] array = (T[]) Array.newInstance( sendedClass, 5 );

As you can see, creating objects that way is not as easy as it would seem and thus patterns like the factory pattern would most probably help here.

Update on inner classes:

It would be easier if BookRow wasn't an inner class, but it it really needs to be, you could still use reflection.

From the JavaDoc on getConstructor(...):

If this Class object represents an inner class declared in a non-static context, the formal parameter types include the explicit enclosing instance as the first parameter.

Hence you'd need to create the instance like this (which you'd have to know or pass as a parameter):

sendedClass.getConstructor( MyActivity.class, Integer.TYPE, String.class ).newInstance( myActivityInstance, i, "my book title" + i);

Upvotes: 1

faylon
faylon

Reputation: 7450

The inner class should be static, or it cannot be initialized in this way.

   public static class BookRow
   {
     public String book_id;
     public String book_title;
   }

Upvotes: 0

Related Questions