0

In my project I want quickly read from and make modifications to a private-ish variable. I was initially going to do reflection, but my thinking was that it would be too inefficient.

//Reference for what I need to get data from.
public class SomeControllerInALibraryThatICantEdit {

    //I can easily get an instance of the controller
    public static final SomeControllerInLargeLibrary instance;

    //I need to read from and make changes to the data object quickly.
    //It is final, so I don't need to worry about this object changing or being reset.
    private final Subclass dataClass = new Subclass();

    private class Subclass {

        //I can get a pointer to this once then treat it like any other array.
        public float[] arr;


        //This is the problematic part. I need to be able to quickly check changes and 
        //set this every update. Keeping in mind there are multiple dataPoints.
        public short dataPoint;

    }

}

What is a quick and efficient way to get and set dataPoint? I can use reflection, but I am hoping there is a better way to approach this problem. Can I in some way make a Pojo that represents Subclass and link their pointers together?

If I just fork the library and make it work better with what I am doing, then that defeats the purpose of my project.

Locke
  • 7,626
  • 2
  • 21
  • 41
  • 1
    your question does not make sense – Scary Wombat Aug 20 '18 at 06:37
  • What parts? I want to be able to read and set dataPoint, but I want to try to find a way to do it which is faster than just using reflection every time I need to get it (About 200 times every second). – Locke Aug 20 '18 at 06:41
  • 1
    you don't explain why you are needing to use reflection in the first place – Scary Wombat Aug 20 '18 at 06:48
  • 2
    Why can you not simply use a getter/setter? Could you please elaborate why Reflection is what you think is neccessary here? – Ben Aug 20 '18 at 06:48
  • This is in a library which I can not edit and I am trying to use it in a way that was not originally intended. So while getters and setters would be ideal, they are not an option. I am using reflection in order to get the private variables since I need to access them from a different class. – Locke Aug 20 '18 at 06:50
  • 1
    What are you asking about when you say "quickly"? If you can't get or set it yet, how do you know that whatever way you choose isn't quick enough? – Andy Turner Aug 20 '18 at 06:51
  • I don't know that reflection isn't quick enough, but I do know that using reflection is very slow. I want to find out if there is a better way to do this so that I write it correctly the first time. Also, any added time takes away from different processes which are much more time sensitive. https://stackoverflow.com/questions/435553/java-reflection-performance – Locke Aug 20 '18 at 06:55
  • Also as this field is final and inside singleton... you can just get it once and re-use – GotoFinal Aug 22 '18 at 09:57

1 Answers1

1

but I do know that using reflection is very slow.

It is not.

Create private static final MethodHandle to that variable, it will be optimized to near same performance as using normal code - it will be for sure much less than few ns to call it, so you can call it not 200 but 2 000 000 times per second too.
Only creating reflected accessor is very slow, but you need to do it only once.

private static final MethodHandle dataGetter;

static {
    Field dataField;
    try {
        dataField = SomeControllerInALibraryThatICantEdit.class.getDeclaredField("dataClass");
        dataField.setAccessible(true); // or trySetAccessible for new java
        dataGetter = MethodHandles.lookup().unreflectGetter(dataField);
    } catch (NoSuchFieldException | IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

and use like:

DataClass data = (DataClass) dataGetter.invokeExact(SomeControllerInALibraryThatICantEdit.instance);

Note that even if invokeExact method is expecting objects in signature you must provide variables of valid type, as it uses @PolymorphicSignature.

you can also use:

dataGetter = MethodHandles.lookup().unreflectGetter(dataField).bindTo(SomeControllerInALibraryThatICantEdit.instance); 

Then you can skip instance and it might be also a bit faster.

The only slow part here is creation of that MethodHandle.
But performance can also depend on JVM like I think they are often slower on android VM.

But on hotspot it should be very fast, here are my old benchmark results:

Benchmark                                                      Mode  Cnt  Score   Error  Units
normalDirectAccess                                             avgt   10  2,867 ± 0,142  ns/op
somethingPrivateFieldAccessor_static_final_handle_access       avgt   10  2,827 ± 0,058  ns/op
somethingPrivateFieldAccessor_static_final_handle_bound_access avgt   10  2,859 ± 0,084  ns/op

Full benchmarks can be found here: https://blog.gotofinal.com/java/benchmark/performance/2017/09/17/performance-of-java-3.html like for other kind of reflections etc, but this small part should be enough for this answer.

Also as this field is final and inside singleton... you can probably just get it once and re-use

GotoFinal
  • 3,585
  • 2
  • 18
  • 33