Is it possible to serialize anonymous class without outer class?

前端 未结 6 1040
广开言路
广开言路 2021-02-06 03:45

I made a small research on web and reviewed related topics on this site, but the answers were contradictory: some people said it is not possible, others said it is possible, but

6条回答
  •  旧时难觅i
    2021-02-06 04:08

    You can't do exactly what you want, which is to serialize an anonymous inner class, without also making its enclosing instance serializable and serializing it too. The same applies to local classes. These unavoidably have hidden fields referencing their enclosing instances, so serializing an instance will also attempt to serialize their enclosing instances.

    There are a couple different approaches you can try.

    If you're using Java 8, you can use a lambda expression instead of an anonymous inner class. A serializable lambda expression does not (necessarily) have a reference to its enclosing instance. You just need to make sure that your lambda expression doesn't reference this explicitly or implicitly, such as by using fields or instance methods of the enclosing class. The code for this would look like this:

    public class Caller {
        void call() {
            getRpcService().call(() -> {
                System.out.println("It worked!");
                return null;
            });
    }
    

    (The return null is there because RPCService.Runnable.run() is declared to return Object.)

    Also note that any values captured by this lambda (e.g., local variables, or static fields of the enclosing class) must also be serializable.

    If you're not using Java 8, your next best alternative is to use a static, nested class.

    public class Caller {
        static class StaticNested implements RPCService.Runnable {
            @Override
            public Object run() {
                System.out.println("StaticNested worked!");
                return null;
            }
        }
    
        void call() {
            getRpcService().call(new StaticNested());
        }
    }
    

    The main difference here is that this lacks the ability to capture instance fields of Caller or local variables from the call() method. If necessary, these could be passed as constructor arguments. Of course, everything passed this way must be serializable.

    A variation on this, if you really want to use an anonymous class, is to instantiate it in a static context. (See JLS 15.9.2.) In this case the anonymous class won't have an enclosing instance. The code would look like this:

    public class Caller {
        static RPCService.Runnable staticAnonymous = new RPCService.Runnable() {
            @Override
            public Object run() {
                System.out.println("staticAnonymous worked!");
                return null;
            }
        };
    
        void call() {
            getRpcService().call(staticAnonymous);
        }
    }
    

    This hardly buys you anything vs. a static nested class, though. You still have to name the field it's stored in, and you still can't capture anything, and you can't even pass values to the constructor. But it does satisfy your the letter of your initial question, which is how to serialize an instance of an anonymous class without serializing an enclosing instance.

提交回复
热议问题