Search code examples
javareflectionprivateencapsulation

Dosen't Reflection API break the very purpose of Data encapsulation?


Very recently I came across the Reflection API and to my surprise we can access and even alter the private variables.I tried the following code

import java.lang.reflect.Field;

public class SomeClass{
    private String name = "John";
}

public class Test{
    public static void main(String args[]) throws Exception {
        SomeClass myClass = new SomeClass();

        Field fs = myClass.getClass().getDeclaredField("name");
        fs.setAccessible(true);

        System.out.println("Variable is " + fs.getName() + " and value is "
                + fs.get(myClass));

        fs.set(myClass, "Sam");
        System.out.println("Variable is " + fs.getName() + " and value is "
                + fs.get(myClass));
    }
}

and I got the following output.

Variable is name and value is John
Variable is name and value is Sam

We say Java is an Object oriented language and it's main features are Data Encapsulation, Inheritance, Polymorphism.. etc. Isn't the reflection API changing the very purpose of Data Encapsulation? Why do we have to use Reflection API? I read in some sites that it can be used for testing purpose but according to me modules are tested and that can be done easily using JUnit test cases. So can anyone explain why do we have such a hack?


Solution

  • Isn't the reflection API changing the very purpose of Data Encapsulation?

    Yes and no.

    • Yes, some uses of the reflection API can break data encapsulation.
    • No, not all uses of the reflection API do break data encapsulation. Indeed, a wise programmer only breaks encapsulation via the reflection API when there is a good reason to do so.
    • No, reflection API does not change the purpose of data encapsulation. The purpose of data encapsulation remains the same ... even if it someone wilfully breaks it.

    Why do we have to use Reflection API?

    There are many uses of reflection that DO NOT break encapsulation; e.g. using reflection to find out what super types a class has, what annotations it has, what members it has, to invoke accessible methods and constructors, read and update accessible fields and so on.

    And there are situations where is is acceptable (to varying degrees) to use the encapsulation breaking varieties of reflection:

    • You might need to look inside an encapsulated type (e.g. access / modify private fields) as the simplest way (or only way) to implement certain unit tests.

    • Some forms of Dependency Injection (aka IoC), Serialization and Persistence entail accessing and/or updating private fields.

    • Very occasionally, you need to break encapsulation to work around a bug in some class that you cannot fix.

    I read in some sites that it can be used for testing purpose but according to me modules are tested and that can be done easily using JUnit test cases. So can anyone explain why do we have such a hack?

    That depends on the design of your class. A class that is designed to be testable will either be testable without the need to access "private" state, or will expose that state (e.g. protected getters) to allow testing. If the class doesn't do this, then a JUnit test may need to use reflection to look inside the abstraction.

    This is not desirable (IMO), but if you are writing unit tests for a class that someone wrote, and you can't "tweak" the APIs to improve testability, then you may have to choose between using reflection or not testing at all.


    The bottom line is that data encapsulation is an ideal that we strive to achieve (in Java), but there are situations where the pragmatically correct thing to do is to break it or ignore it.

    Note that not all OO languages support strong data encapsulation like Java does. For example, Python and Javascript are both unarguably OO languages, yet both make it easy for one class to access and modify the state of objects of another class ... or even change the other classes behaviour. Strong data abstraction is not central to everyone's view of what Object-Oriented means.