36

I am new to Java; through my studies, I read that reflection is used to invoke classes and methods, and to know which methods are implemented or not.

When should I use reflection, and what is the difference between using reflection and instantiating objects and calling methods the traditional way?

5
  • 6
    Check out stackoverflow.com/questions/37628/…
    – Jalayn
    Dec 8, 2011 at 8:47
  • 10
    Please do your share of research before posting. There is lots of material on StackExchange (as @Jalayn noted) and the web in general about reflection. I suggest you read e.g. the Java Tutorial on Reflection and come back after that if you have any more concrete questions. Dec 8, 2011 at 8:49
  • 1
    There has got to be a million dupes.
    – DeadMG
    Dec 8, 2011 at 8:53
  • 3
    More than a few professional programmers would answer "as rarely as possible, maybe even never." Apr 2, 2013 at 23:30
  • This article provides an example of how to improve your code using Reflection: levelup.gitconnected.com/… It's in C#, but the concepts are exactly the same. Dec 2, 2020 at 11:44

6 Answers 6

44
  • Reflection is much slower than just calling methods by their name, because it has to inspect the metadata in the bytecode instead of just using precompiled addresses and constants.

  • Reflection is also more powerful: you can retrieve the definition of a protected or final member, remove the protection and manipulate it as if it had been declared mutable! Obviously this subverts many of the guarantees the language normally makes for your programs and can be very, very dangerous.

And this pretty much explains when to use it. Ordinarily, don't. If you want to call a method, just call it. If you want to mutate a member, just declare it mutable instead of going behind the compile's back.

One useful real-world use of reflection is when writing a framework that has to interoperate with user-defined classes, where the framework author doesn't know what the members (or even the classes) will be. Reflection allows them to deal with any class without knowing it in advance. For instance, I don't think it would be possible to write a complex aspect-oriented library without reflection.

As another example, JUnit used to use a trivial bit of reflection: it enumerates all methods in your class, assumes that all those called testXXX are test methods, and executes only those. But this can now be done better with annotations instead, and in fact JUnit 4 has largely moved to annotations instead.

10
  • 8
    "More powerful" needs care. You don't need reflection to get Turing completeness, so no computation ever needs reflection. Of course Turing complete says nothing about other kinds of power, like I/O capabilities and, of course, reflection.
    – user8709
    Dec 8, 2011 at 9:11
  • 1
    Reflection is not necessarily "much slower". You can use reflection once to generate a direct calling wrapper bytecode.
    – SK-logic
    Dec 8, 2011 at 10:57
  • 2
    You'll know it when you need it. I often wondered why (outside of language generation) one would need it. Then, suddenly, I did... Had to walk up and down parent/child chains to peek/poke data when I got panels from other devs to pop into one of the systems I maintain. Dec 8, 2011 at 13:41
  • @SK-logic: actually for generating bytecode you don't need reflection at all (indeed reflection contains no API for bytecode manipulation at all!). Oct 22, 2012 at 11:19
  • 1
    @JoachimSauer, of course, but you'll need a reflection API to load this generated bytecode.
    – SK-logic
    Oct 22, 2012 at 15:29
19

I was like you once, I didn't know much about reflection - still don't - but I did use it once.

I had a class with two inner classes, and each class had lots of methods.

I needed to invoke all of the methods in the inner class, and invoking them manually would've been too much work.

Using reflection, I could invoke all these methods in just 2-3 lines of code, instead of the number of the methods themselves.

3
  • 4
    Why the downvote? Dec 15, 2011 at 7:58
  • 1
    Upvoting for the preamble Jul 29, 2015 at 13:46
  • 1
    @MahmoudHossam Perhaps not a best-practice, but your answer illustrates an important tactic one can deploy.
    – ankush981
    Nov 7, 2015 at 15:20
16

I'd group uses of reflection into three groups:

  1. Instantiating arbitrary classes. For example, in a dependency injection framework, you probably declare that interface ThingDoer is implemented by the class NetworkThingDoer. The framework would then find the constructor of NetworkThingDoer and instantiate it.
  2. Marshalling and unmarshalling to some other format. For example, mapping an object with getters and settings that follow the bean convention to JSON and back again. The code doesn't actually know the names of the fields or the methods, it just examines the class.
  3. Wrapping a class in a layer of redirection (perhaps that List isn't actually loaded, but just a pointer to something that knows how to fetch it from the database) or faking a class entirely (jMock will create a synthetic class that implements an interface for testing purposes).
1
  • This is the best explanation of reflection I've found on StackExchange. Most answers repeat what the Java Trail says (which is "you can access all these properties", but not why you would), provide examples of doing things with reflection that are much easier to do without, or give some vague answer about how Spring uses it. This answer actually gives three valid examples that CANNOT easily be worked around by JVM without reflection. Thank you!
    – ndm13
    Jan 11, 2018 at 2:28
4

Fundamentally, reflection means using the code of your program as data.

Therefore, using reflection might be a good idea when your program's code is a useful source of data. (But there are trade-offs, so it might not always be a good idea.)

For example, consider a simple class:

public class Foo {
  public int value;
  public string anotherValue;
}

and you want to generate XML from it. You could write code to generate the XML:

public XmlNode generateXml(Foo foo) {
  XmlElement root = new XmlElement("Foo");
  XmlElement valueElement = new XmlElement("value");
  valueElement.add(new XmlText(Integer.toString(foo.value)));
  root.add(valueElement);
  XmlElement anotherValueElement = new XmlElement("anotherValue");
  anotherValueElement.add(new XmlText(foo.anotherValue));
  root.add(anotherValueElement);
  return root;
}

But this is a lot of boilerplate code, and everytime you change the class, you have to update the code. Really, you could describe what this code does as

  • create an XML element with the name of the class
  • for each property of the class
    • create an XML element with the name of the property
    • put the value of the property into the XML element
    • add the XML element to the root

This is an algorithm, and the algorithm's input is the class: we need its name, and the names, types and values of its properties. This is where reflection comes in: it gives you access to this information. Java allows you to inspect types using the methods of the Class class.

Some more use cases:

  • define URLs in a webserver based on a class's method names, and URL parameters based on the method arguments
  • convert the structure of a class into a GraphQL type definition
  • call every method of a class whose name starts with "test" as a unit test case

However, full reflection means not only looking at existing code (which by itself is known as "introspection"), but also modifying or generating code. There are two prominent use cases in Java for this: proxies and mocks.

Let's say you have an interface:

public interface Froobnicator {
  void froobnicateFruits(List<Fruit> fruits);
  void froobnicateFuel(Fuel fuel);
  // lots of other things to froobnicate
}

and you have an implementation that does something interesting:

public class PowerFroobnicator implements Froobnicator {
  // awesome implementations
}

And in fact you have a second implementation too:

public class EnergySaverFroobnicator implements Froobnicator {
  // efficient implementations
}

Now you also want some log output; you simply want a log message whenever a method is called. You could add log output to every method explicitly, but that would be annoying, and you'd have to do it twice; once for each implementation. (So even more when you add more implementations.)

Instead, you can write a proxy:

public class LoggingFroobnicator implements Froobnicator {
  private Logger logger;
  private Froobnicator inner;

  // constructor that sets those two

  public void froobnicateFruits(List<Fruit> fruits) {
    logger.logDebug("froobnicateFruits called");
    inner.froobnicateFruits(fruits);
  }

  public void froobnicateFuel(Fuel fuel) {
    logger.logDebug("froobnicateFuel( called");
    inner.froobnicateFuel(fuel);
  }
  // lots of other things to froobnicate
}

Again, though, there is a repetitive pattern that can be described by an algorithm:

  • a logger proxy is a class that implements an interface
  • it has a constructor that takes another implementation of the interface and a logger
  • for every method in the interface
    • the implementation logs a message "$methodname called"
    • and then calls the same method on the inner interface, passing along all arguments

and the input of this algorithm is the interface definition.

Reflection allows you to define a new class using this algorithm. Java allows you to do this using the methods of the java.lang.reflect.Proxy class, and there are libraries that give you even more power.

So what are the downsides of reflection?

  • Your code becomes harder to understand. Your are one level of abstraction further removed from the concrete effects of your code.
  • Your code becomes harder to debug. Especially with code-generating libraries, the code that is executed may not be the code that you wrote, but the code you generated, and the debugger may not be able to show you that code (or let you place breakpoints).
  • Your code becomes slower. Dynamically reading type information and accessing fields by their runtime handles instead of hard-coding access is slower. Dynamic code generation can mitigate this effect, at the cost of being even harder to debug.
  • Your code may become more fragile. Dynamic reflection access is not type-checked by the compiler, but throws errors at runtime.
3

Reflection allows a program to work with code that may not be present and do so in a reliable way.

"Normal code" have snippets like URLConnection c = null which by its sheer presence cause the class loader to load the URLConnection class as part of loading this class, throwing a ClassNotFound exception and exiting.

Reflection allow you to load classes based on their names in string form and test them for various properties (useful for multiple versions outside your control) before launching actual classes that depend on them. A typical example is the OS X specific code used to make Java programs look native under OS X, which are not present on other platforms.

1

Reflection can automatically keep parts of your program in sync, where previously, you would have had to manually update your program to use the new interfaces.

1
  • 5
    The price you pay in this case is that you lose type-checking by the compiler and refactor-safety in the IDE. It's a trade-off that I'm not willing to make.
    – Barend
    Jan 6, 2012 at 9:42

Not the answer you're looking for? Browse other questions tagged or ask your own question.