Large Inner classes and private variables

One thing I've run into a few times is a service class (like a JBoss service) that has gotten overly large due to helper inner classes. I've yet to find a good way to break the class out. These helpers are usually threads. Here's an example:

/** Asset service keeps track of the metadata about assets that live on other
 * systems. Complications include the fact the assets have a lifecycle and their
 * physical representation lives on other systems that have to be polled to find
 * out if the Asset is still there. */
public class AssetService
  //...various private variables
  //...various methods

  public AssetService()
    Job pollerJob = jobService.schedule( new AssetPoller() );
    Job lifeCycleJob = jobService.schedule( AssetLifecycleMonitor() );

  class AssetPoller
    public void run()
      // contact remote systems and update this service's private variables that
      // track the assets.

  class AssetLifecycleMonitor
    public void run()
      // look for assets that have meet criteria for a lifecycle shift
      // and update this service's private variables as relevant.

So, what can happen if I have a couple helpers and they're at all complex, is the overall class file can get really large. I like the inner classes in that it makes clear the classes are wholly owned by the service and exist only to help that service. I've tried breaking the classes out and passing the parent service as a reference, which works mostly, but things I don't like are:

  • I end up exposing package level accessors so the broken out classes can get to the variables, whereas before I didn't expose the setters at all since the inner classes had direct access.
  • Plus, things get a bit more wordy as I'm constantly calling accessors rather than the underlying variables. A minor nit, granted.
  • Convenience methods (e.g. checkAssetIsValid() or some such) need package level exposure now so the helper classes can call them, where as before as inner classes they could be private.
  • Even worse, I need to pass the service implementation class to the helper classes constructors since I don't want to expose these helpers methods in the interface the service implements because that forces them to be public. This can create some unit test/mocking issues.
  • Worse yet, any synchronization I wanted to do gets leaked out through some external convenience method (e.g. lockDownAssets() during a poller update). Before, the internal classes had access to private Locks.
  • So, in short, breaking the classes out loses some of the encapsulation I like. But leaving them in can lead to some large java files. I've yet to find a good way to deal with this. C++ had the concept of "friends" which I've rarely missed, but would actually help in this case.


    Asked by: Tess686 | Posted: 28-01-2022

    Answer 1

    On bytecode level inner classes are just plain Java classes. Since the Java bytecode verifier does not allow access to private members, it generates synthetic accessor methods for each private field which you use. Also, in order to link the inner class with its enclosing instance, the compiler adds synthetic pointer to the outer 'this'.

    Considering this, the inner classes are just a layer of syntax sugar. They are convenient and you have listed some good points, so I'd list some negative aspects which you might want to consider:

    • Your inner class has a hidden dependency to the whole parent class, which obfuscates its inbound interface. If you extract it as package-private class you have a chance to improve your design and make it more maintainable. Initially it's more verbose, but often you'd find that:
      • Instead of exposing 10 accessors you actually want to share a single value object. Often you would find that you don't really need a reference to the whole outer class. This also works well with IoC.
      • Instead of providing methods for explicit locking, it's more maintainable to encapsulate the operation with its context in a separate class (or move it to one of the two classes - outer or formerly-inner).
      • Convenience methods belong in package private utility classes. You can use the Java5 static import to make them appear as local.
    • Your outer class can bypass any protection levels and access private members of your inner class directly. This is not bad thing per se, but it takes away one of the language means of expressing your design.
    • Since your inner class is embedded in exactly one outer class, the only way to reuse it is to subclass the outer class. An alternative would be to pass explicit reference to a package-private interface that the outer class implements. This would allow you to mock the outer and better test the inner class.
    • Though recent debuggers are quite good, I have experienced problems with debugging inner classes before (conditional breakpoint scope confusion, not stopping at breakpoints, etc.)
    • Private classes bloat your bytecode. See my first paragraph - often there is an API that you could use and reduce the number of synthetic cruft.

    P.S. I'm talking about non-trivial inner classes (especially ones that do not implement any interfaces). Three line listener implementations are good.

    Answered by: Adelaide320 | Posted: 01-03-2022

    Answer 2

    Don't forget to consider why you're trying to break up your large class. Is it for software engineering purposes? E.g. it's a programming hotspot and you have such a large file it causes complicated merges on your developer team?

    Is it just a general desire to avoid large classes? In which case it may be that your time would be better spent improving the code you do have.

    Is the code becoming difficult to manage, e.g. debugging and ensuring avoidance of unintended side effects is becoming more difficult.

    Rick's comment about using unit tests to ensure continued consistent behavior is very valuable and a good idea. It may be that the current design simply precludes refactoring and you're better off re-implementing the same behavior starting from the interface of the original. Be ready for plenty of regresssion testing!

    Answered by: Elise753 | Posted: 01-03-2022

    Answer 3

    The line between encapsulation and separation can be difficult to walk. However, I think the main issue here is that you need some kind of solid interaction model to use as a basis of separating your classes.

    I think it's reasonable to have external helper utility classes which are used in many places, as long as they don't side effect I don't see an issue. It's also reasonable to have static helper classes, as long as they are well organized, which contain often used methods such as checkAssetIsValid(). This is assuming that checkAssetIsValid does not need to access any external state other than the object you are passing it.

    The most important thing for separation is not to have objects which share permanent references in many of these classes. I like to look to functional programming for guidance. Each class should not be reaching into the guts of other classes and changing state. Instead each class which does work should produce and consume container objects.

    Visualization can be very helpful too. I noticed a thread on the topic of Java Visualization tools here. Ideally, your class interaction diagram should look more like a tree than a graph.

    Also, I just want to note that refactoring a large class into smaller classes can be extremely difficult. It's best to build a suite of unit tests for the public interface at the very least so that it will become immediately obvious if you break something. I know tests have saved me countless hours in the past.

    Hopefully some of this will be helpful. I'm kind of just rambling on here.

    Answered by: Victoria214 | Posted: 01-03-2022

    Answer 4

    I'm not a fan of excessive use of inner classes. I think that they don't really offer any advantage (when used in the extreme) that putting the code in a normal class wouldn't, and they just serve to make the class file unnecessarily large and hard to follow.

    What's the harm if you have to increase the visibility of a few methods? Is it going to completely break your abstraction or interface? I think too often programmers tend to make everything private by default, where there isn't really much of a harm in letting some other classes call your methods - if your design is truly OO-based, that is.

    If all of your "inner helper classes" need access to some of the same methods, consider putting them in a base class so they can be shared via inheritance.

    Answered by: Jack416 | Posted: 01-03-2022

    Answer 5

    Yeap. Probably you need to re-refactor those helpers and not move them all as they are. Some things belong to the service some other to the helper. Probable new classes should be used to encapsulate the data.

    One posibility you can use is to AOP to provide fine-grained access, and include in the point cut that the method should be only invoked from the "friend" class. Still your method would be exposed :(

    I guess there is no easy solution for this.

    Answered by: Robert878 | Posted: 01-03-2022

    Similar questions

    java - Using object variables inside other classes

    I have an object whose functions I would like to call from with in another class for example class smo { int spoon = 10; smo() { } int get_spoon() { return spoon; } } class boat { boat() { } print_smo(Object test) { test.get_spoon(); } } it tells me that the function get.spoon() does not exists. The error makes sense since the obj...

    java - Local inner classes safe access to local variables of containing method

    When defining a local inner class, is it safe to access local variables of the containing method that only said class has references to. Like so: public Bar containingMethod() { Foo foo = new Foo(); Bar bar = new Bar() { public void baz() { System.out.println("Accessing foo: " + foo.getValue()); } }; return bar; }; In my example above...

    global variables - How to share which Locale to use among all the classes in Java?

    I decided my software needs to go international, so I made one of the classes prompt the user which locale to use. To the 7 other classes I added a parameter to take this info in. Now, somehow this doesn't feel right. It seems to complicate things. It seems more natural to make the chosen Locale a 'global' variable, instead of adding a parameter to all 7 other classes to take this info in. (do you agree?) S...

    java - How do I share variables between classes?

    Say I am making something like a quiz, and I have a counter to show the number of questions that have been answered correctly. When one question is correctly answered, and a new screen(Activity) is shown, how do I carry over the number to the next screen?

    android - Is there a way to make classes as stack variables in Java, or am I too much in the C++ mindset?

    I am somewhat familiar to Java, but am using it more now for Android. Anyway, I'm kind of wondering if the only way to instantiate a class variable in Java is to allocate it onto the heap. For instance: [C++ Land] Foo foo; foo.doSomeAwesomeStuff(9001); [Java Land] Foo foo = new Foo(); foo.doSomeAwesomeStuff(9001); This kind of irks me because there are some things in Java...

    Getting classes from variables in Java

    I'm making a small (for fun) game where virtual robots fight each other. I have an array of names of the classes of these robots, but I don't know how to load them. It's probably clearer in codes: String[] classes={"Bot1","Bot2","Bot123"}; Object[] bots=new Object[classes.length]; for(int i=0;i<classes.length;i++){ bots[i]=UnknownFunction(classes[i]); } Additional details: ...

    Why Java Inner Classes require variables of outer class be final?

    This question already has answers here:

    How to Access and Modify Variables from Different Classes in Java

    java - use and save variables between classes

    I am trying to create a simple grade tracker for android. The way I have it set up is that the user has a list of classes that are in their major. When they click on the title of the class, a new activity starts that has the name of the class, the catalog description, a space to place your grade, and a button to return to the list of classes. What I would like to do is save the grade number that they input on t...

    java - Two of the same variables in different classes

    I could only find a c# link for this and couldn't understand it so here goes.. I have a Player and a Target class in my program, and I want to be able to make like this: public Player(int difficulty) { if(difficulty == 1) health = hArray[0]; else health = hArray[1]; } where hArray is my array of possible health values. This works, but I also deal with player...

    Java - Abstract class to contain variables?

    Is it good practice to let abstract classes define instance variables? public abstract class ExternalScript extends Script { String source; public abstract void setSource(String file); public abstract String getSource(); } The sub class, ExternalJavaScript.class, would then automatically get the source variable but I feel it's easier to read the code if all the sub classes t...

    Library that subverts java access control and lets me access private member variables?

    Can anoyne recommend a good library that will let me easily read/write private member fields of a class? I was looking through apache commons, but couldnt see it. I must be getting blind ? Edit: Asking questions on the border of legalities always give these questions of "why"? I am writing several javarebel plugins for hotswapping classes. Accessing private variables is only step 1, I might even have to replace imp...

    Java session variables

    I'm hearing that some people believe storing info on the server in a session is a bad idea, that its not secure. As a result, in a multi-page business process function, the application is writing data to a db, then retrieving the info when its needed. Is there something necessarily unsafe about storing private info in a session?

    Simple Variables in Java & C++

    I saw this sentence in some matrials: "In Java, simple data types such as int and char operate just as in C." I am wondering that actually they are different in Java & C++? In C++, simple variables like the primitives in Java are assigned a memory address as well, so these primitive types in C++ can have a pointer as well. However primitives in Java are not assigned a memory address like Objects...

    variables - What is the purpose of long, double, byte, char in Java?

    So I'm learning java, and I have a question. It seems that the types int, boolean and string will be good for just about everything I'll ever need in terms of variables, except perhaps float could be used when decimal numbers are needed in a number. My question is, are the other types such as long, double, byte, char

    java - Can you define your own template variables in Eclipse

    In Eclipse there are templates that help you by automatically inserting some code or comments. You can edit these templates yourself via Preferences > Java > Editor > Templates. There are so-called "template variables" that you can use to make these templates a little smarter. For instance, there is the ${see_to_overridden} variable that inserts "@see, my.other.package....

    Does it help GC to null local variables in Java

    I was 'forced' to add myLocalVar = null; statement into finally clause just before leaving method. Reason is to help GC. I was told I will get SMS's during night when server crashes next time, so I better did it :-). I think this is pointless, as myLocalVar is scoped to method, and will be 'lost' as soon as method exits. Extra nulling just pollutes the code, but is harmless otherwise. My questi...

    java - Static variables and methods

    I ran across a class that was set up like this: public class MyClass { private static boolean started = false; private MyClass(){ } public static void doSomething(){ if(started){ return; } started = true; //code below that is only supposed to run //run if not started } } My understanding with static methods is that you should not use class variables i...

    java - Should all methods be static if their class has no member variables

    I've just had an argument with someone I work with and it's really bugging me. If you have a class which just has methods like calculateRisk or/and calculatePrice, the class is immutable and has no member variables, should the methods be static so as not to have to create an instance of the class each time. I use the following example: public class CalcService { public int calcPr...

    Can using too many static variables cause a memory leak in Java?

    If my application has too many static variables or methods, then as per definition they will be stored in heap. Please correct me if I am wrong 1) Will these variables be on heap until application is closed? 2) Will they be available for GC at any time? If not can I say it is a memory leak?

    Still can't find your answer? Check out these amazing Java communities for help...

    Java Reddit Community | Java Help Reddit Community | Java Community | Java Discord | Java Programmers (Facebook) | Java developers (Facebook)