-2

First of all, allow me to explain a "behaviour" that I observed, then I will ask in "Example" section.

Inner-class-reference behaviour

In Java we can have (non-static) inner-classes, which seem to behave like having a strong-reference to their container-class and/or owner-class, but without causing memory-leak.

I mean, I observed that even if both owner-class and inner-class keep strong-reference to each other, the classes are garbage-collected anyway (once no external class references them, although having reference-recursion).

In other words, or in other programming-languages, where "reference-counters" are often used (unlike Java?);

We could achieve such behaviour if owner-class and all inner-classes share the same reference-counter. Where just like above, even if we only keep a single reference to inner-class, owner-class is kept as well.

Example (background and question)

My previous logic, which used above said behaviour, was something like:

public class WebApi {
    public UserApi user = new UserApi();
    public PostApi post = new PostApi();

    protected String post(String url, String json) {
        // ...
    }

    public class UserApi {
        public void login() {
            WebApi.this.post(...);
        }

        public void logout() {
            WebApi.this.post(...);
        }

        // ...
    }

    public class PostApi {
        // ...
    }
}

Then day by day the project did grow, till each of UserApi and PostApi classes deserved their own separate files (instead of being inner-classes of one huge file).

How can we implement above described "Inner-class-reference" behaviour for external classes?

Top-Master
  • 7,611
  • 5
  • 39
  • 71
  • With "memory-leak" we immply **"unintended" use of memory**, but in situations like above beside being "intended", it also **has far less memory usages** (as all share same "service"). – Top-Master May 09 '22 at 15:33

1 Answers1

2

In Java we can have (non-static) inner-classes, which seem to "behave" like having a strong-reference to their container-class and/or owner-class, but without causing memory-leak.

I mean, I observed that even if both owner-class and inner-class keep strong-reference to each other, the classes are garbage-collected anyway (once no external class references them, although having reference-recursion).

Yes, that's how references work in Java: if an object is reachable, then it's retained, and if not, then it's (eventually) garbage-collected.

But how can we implement above described "Inner-class-reference" behaviour for external classes?

You don't need to do anything special: just give UserApi a field of type WebApi, and initialize it in the constructor.

Java's reference-tracing and garbage collection will ensure that, as long as any reachable UserApi instance holds a reference to a given WebApi instance, the WebApi instance is also considered reachable, and hence retained.

Top-Master
  • 7,611
  • 5
  • 39
  • 71
ruakh
  • 175,680
  • 26
  • 273
  • 307
  • But `WebApi` holds an instance to `UserApi` as well, I want both classes to reference each other, but without memory-leak (caused by recursion). – Top-Master May 09 '22 at 07:13
  • @Top-Master: Yup, that's fine, you can do that. Java doesn't rely on reference counting for garbage collection, so it doesn't matter if two objects hold references to each other. – ruakh May 09 '22 at 07:16
  • If that's true, that would be a huge advantage of Java's GC vs other languages. – Top-Master May 09 '22 at 07:32
  • But as said in OP, other languages can implement "shared reference-counter" instead (which is complicated). – Top-Master May 09 '22 at 07:36
  • It would be nice if you provided link to any official doc(s), but I think to mark the answer as accepted. – Top-Master May 09 '22 at 07:38
  • 1
    @Top-Master: See https://docs.oracle.com/javase/9/gctuning/garbage-collector-implementation.htm. Re: "that would be a huge advantage of Java's GC vs other languages": Plenty of languages use a garbage collection approach that's similar to Java's; in fact, Lisp already used the basic idea in 1960 (see http://jmc.stanford.edu/articles/recursive/recursive.pdf, page 27), though modern-day implementations are *much* more sophisticated. Any languages that use reference-counting do so by choice, e.g. because they want to invoke user-supplied destructor functions at a deterministic time. – ruakh May 10 '22 at 04:33