1

I am storing a List of .class... things (whatever you call them). For example MyClass1.class, MyClass2.class, etc.

In this case the objects are various/different Fragments but they all accept a single long argument via newInstance().

I want to be able to instantiate the object from the ith position of such a list. How would I do this?

user6419910
  • 155
  • 2
  • 12

2 Answers2

2

To make an instance of a Class, you can use reflection. Getting the class is as simple as using the get method that comes with all List implementations making sure ofcourse that the index you are accessing actually exists. After you obtain the Class object you can use reflection to instanciate it:

Example #1, No parameter constructor:

Class<?> myClass = String.class;
        try {
            Object objectOfClass = myClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e1) {
            e1.printStackTrace();
        }

Example #2 Constructor with parameters:

    Class<?> myClass = String.class;//Get the class from the list. For this example i used String.class
    try {
        Constructor<?> classConstructor = myClass.getConstructor(byte[].class); //Here we get the constructor we aim for. String has a constructor which accepts a byte array as parameter, so all i do is getConstructor with patameter byte[].class. 
//if your class accepts two parameters such as long and int, you will have to do .getConstructor(long.class, int.class); in the correct order ofcourse. 
        Object objectOfClass = classConstructor.newInstance(new byte[]{33,25,111,34});//here we call the constructor and we provide the parameter values it takes to it. So thats why i provide a byte array. In the case of the long and int constructor mentioned above, you will have to invoke it like this: .newInstance(214324324234,34242); 
    } catch (ReflectiveOperationException e) { //Reflective operation exception wraps up all reflection related exceptions, so we catch it instead of having to manually catch each of them. 
        e.printStackTrace();
    }

EDIT #1 after talking with the OP in the coments, a more specific piece of code has to be provided:

        // NOTE: THIS PIECE OF CODE ASUMES THAT Fragment IS THE SUPERCLASS OF ALL IMPLEMENTATIONS IN THE LIST!
    List<Class<? extends Fragment>> l = new ArrayList<>();//This is your list of fragments
    Fragment fragmentObject = (Fragment) l.get(3).newInstance();//use default constructor with no arguments. I am randomly getting index 3
    Bundle arguments = new Bundle();
    arguments.putInt("someValue",123);
    fragmentObject.setArguments(arguments);
fill͡pant͡
  • 1,147
  • 2
  • 12
  • 24
  • My classes in this case are Android Fragments, which I instantiate using newInstance() and they all accept a single long parameter. How would I do this? – user6419910 Jun 04 '16 at 16:40
  • @user6419910 See Example #2 i provided above? I will make some edits providing further explanation on what line does what ;) – fill͡pant͡ Jun 04 '16 at 16:42
  • I am not sure this is doing what I need exactly. I'm trying to maintain a list of various (different) Fragments and then be able to instantiate them by index, but they all accept the same newInstance arg – user6419910 Jun 04 '16 at 16:45
  • @user6419910 That is exactly what you look for then! Unfortunately i cannot provide you with the exact code to do this, so that is why i gave you this piece of code that does the same thing but with a different class. Take a look at it again and check my edits. The basic structure is: 1. get the Fragment.class from the list, 2. get the apropriate cosntructor (see example #2) 3. invoke '.newInstance(X,X,X)' replacing X with the parameter(s) the constructor needs, and that gives you the fragment object! :) – fill͡pant͡ Jun 04 '16 at 16:49
  • That code assumes they're all the same class though; in my case I have various different Fragments (SomeFragment, AnotherFragment, etc) – user6419910 Jun 04 '16 at 16:54
  • Fragments are not supposed to have argument-accepting constructors; only newInstance (otherwise arguments are lost on configuration change) – user6419910 Jun 04 '16 at 16:58
  • @user6419910 Nope, `Class>` is the general type. This is the object of every class. `String.class, Fragment.class, AnotherFragment.class.` and so on. It can take any value. The list will be: `List> l = new ArrayList<>();` for example. And then `get(int index)` returns a `Class>` Then you use the code in example 1 above, because as you said you are accessing the default constructor that takes no parameter. – fill͡pant͡ Jun 04 '16 at 17:07
  • I don't instantiate my Fragments by using new; I use newInstance to pass in arguments (which then get set to a Bundle internally). No parameter-accepting constructor is defined. – user6419910 Jun 04 '16 at 17:10
  • See: http://stackoverflow.com/a/9245510/6419910 – user6419910 Jun 04 '16 at 17:12
  • @user6419910 That wasn't part of the question so i didnt know. My apologies. I made an edit to the main post including the new piece of code that is more on-the-spot. Feel free to contact me if it is wrong or needs improvment. – fill͡pant͡ Jun 04 '16 at 17:20
  • @user6419910 with "doesn't allow" you mean... ? It doesnt compile? it doesnt show it as an actual method? It errors in casting? – fill͡pant͡ Jun 04 '16 at 17:33
  • Nevermind, was an error on my end. It works. Is there a way to get it to call newinstance with the arguments directly (so I use the implementation already inside the Fragment) or do you have to do it externally? – user6419910 Jun 04 '16 at 17:35
  • @user6419910 I'm glad it is fixed. I am sorry but i didnt really get the question :( – fill͡pant͡ Jun 04 '16 at 18:13
  • As in being able to call newInstance(longArgument) (where the bundle coupling is done inside the Fragment class) instead of newInstance() and then setting the bundle arguments to the fragment. – user6419910 Jun 04 '16 at 18:14
  • @user6419910 Again, i am not sure i understand... Sorry. But if you mean how you can invoke the constructor with a long as parameter and then provide the Bundle, it is done as shown in Example 2. Is that it? Or do you want to call the setArguments method via Reflection? – fill͡pant͡ Jun 04 '16 at 18:19
  • Inside my Fragment classes, I have implemented static newInstance(long arg) which, inside this implmentation, creates the Bundle, sets the argument, and returns the Fragment. So from the outside, when I am instantiating the Fragments, is there a way to use newInstance(long)? – user6419910 Jun 04 '16 at 18:24
  • Oh, so `newInstance(long l)` is a static method in the Fragment class! Briliant, that changes things a bit. You need to do the following: `Class extends Fragment c = ...` `Fragment f = (Fragment) c.getMethod("newInstance",long.class).invoke(null,LONG_VALUE_GOES_HERE);` and that is it. Now depending on your case, if getMethod errors, you will need to replace it with getDeclaredMethod and try again. I dont know the inheritance structure to pinpoint the exact method. :/ – fill͡pant͡ Jun 04 '16 at 18:29
  • !!!!! That works perfectly!!! Holy crap, how does that work?! – user6419910 Jun 04 '16 at 18:33
  • @user6419910 It is actually.l very simple if you think of it, you tell Java to go in the Class and find the method named "newInstance" that takes as parameter a long (long.class is provided to show Java the type) then after it is found Java returns a Method object which contains functions such as invoke. The invoke method accepts as first parameter the object in which the method belongs to, but because we are talking static this is null. And then it is the parameter which is a long. We know that when this method runs it returns a fragment object so we cast it to Fragment. I'm happy I helped :) – fill͡pant͡ Jun 05 '16 at 09:05
0

A normal object can be instantiated with the new keyword. Also by using reflection it is possible to instantiate objects. I do not understand what you mean with the class files.

wake-0
  • 3,918
  • 5
  • 28
  • 45