0

In normal Java class, when VM load a class, it will invoke clinit method, so I wonder know when VM load a interface, can it invoke some code?

for example, class B implements A, new B(), VM invoke clinit of B, what will VM do with A, in A can I insert some code like System.out.println("hello")

kkwang
  • 249
  • 1
  • 11
  • 2
    Could you clarify your question a bit? What do you mean by "when VM load a class, it will invoke method"? What method? What class? – Ben May 18 '18 at 08:51
  • Class loading is a very specific thing regarding Java technology, so I don't see any confusion into the question ... – LoganMzz May 18 '18 at 08:57
  • 3
    @LoganMzz then you'll surely provide an answer as everything's crystal clear to you. – Kayaman May 18 '18 at 09:02
  • @Ben I changed the post – kkwang May 18 '18 at 09:03
  • 3
    Loading an interface also results in `clinit`, it's not specific to classes only even if the name might suggest so. If you're asking whether you can do something when an interface class is loaded, i.e. similar to `static {}` in a class, that's not possible with a static block. However it sounds like an XY problem, so what are you really trying to achieve? – Kayaman May 18 '18 at 09:04
  • 1
    @Kayaman why would an interface have a constructor? – Gyro Gearless May 18 '18 at 09:05
  • 1
    @GyroGearless I don't know? Why are you talking about constructors? I sure as hell wasn't. – Kayaman May 18 '18 at 09:07
  • @Kayaman yes, what I want is static {} in a interface. – kkwang May 18 '18 at 09:08
  • 1
    Then refer to https://stackoverflow.com/questions/19722847/static-initialization-in-interface and realize that you can't have that. Now why would you want a static block in an interface? What would you do in it? – Kayaman May 18 '18 at 09:10
  • @Kayaman I use ASM to insert code in every class. Then I can know which class is executed. – kkwang May 18 '18 at 09:12
  • You mean loaded. There are a lot easier ways to find out which classes are loaded though. Easiest way is to enable [classloader logging](https://stackoverflow.com/questions/1432180/is-there-a-way-to-get-which-classes-a-classloader-has-loaded). – Kayaman May 18 '18 at 09:14
  • @Kayaman Used in Android app – kkwang May 18 '18 at 09:16
  • Well, if you're using ASM can't you put stuff in the interface's `clinit`? The compiler won't allow a static block, but the bytecode allows it. – Kayaman May 18 '18 at 09:21
  • @Kayaman Yes, I put the stuff in the interface's clinit but failed. The VM seems not execute clinit of interface. – kkwang May 18 '18 at 09:23
  • That would be very naughty of the VM, as the [JLS](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html) dictates that it will. Of course if the interface never gets loaded or it has already been loaded, it wouldn't execute your code. – Kayaman May 18 '18 at 09:28

3 Answers3

0

Having static {} block in interfaces isn't possible. But if you are really certain that you need to invoke some code when loading interface you can use custom classloader which will hook your interface loading and perform some action on that

Here is an example:

static class MyClassLoader extends ClassLoader {
        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            if (name.equals("test.Test1")) {
                ... do whatewer you need on loading class/interface...
            }
            return getParent().loadClass(name);
        }
    }
}

How to replace classes in a running application in java ?

Also there is very usefull tutorial: https://zeroturnaround.com/rebellabs/reloading-objects-classes-classloaders/

Ruslan Akhundov
  • 2,018
  • 3
  • 18
  • 30
0

As mentioned in another answers, you cannot have static section in interfaces. However you can have static methods and static final fields. You can combine both for debugging purposes.

interface TestInterface {
    int dummy = init();
    static int init() {
        System.out.println("Loaded TestInterface");
        return 1;
    }
}
schaffe
  • 389
  • 2
  • 16
  • I tried before. But when Vm load TestInterface, it will not execute init() method – kkwang May 18 '18 at 09:19
  • @kkwang Ok, got what is wrong. Java compiler optimized (erases) unused method fields and method calls. You need to refer to this fields from another class. – schaffe May 18 '18 at 09:48
0

Directly not, Java interfaces are not supposed to contain any code, even if you can now have default method. Following code will not compile:

interface Foo {
    init {
        System.out.println("Loading Foo...");
    }
}

However, interfaces can contain static fields:

interface Foo {
    static class FooLoader {
        private static Object init() {
            System.out.printf("Initializing %s%n", Foo.class);
        }
    }

    Object NULL = FooLoader.init();
}

Again, it may work BUT:

  1. through Reflection, it's still possible to invoke init() method, so it can be called twice
  2. code isn't really called at load time but at init time. To understand, what I mean check this simple main:

    System.out.println("START"); System.out.println(Foo.class); System.out.println("END");

As long as you don't access static members, Java interfaces are not initialized (See §5.5 of JVM Specification)

So, to truely catch load time, you can use a custom class loader, or instrumentation API.

LoganMzz
  • 1,523
  • 2
  • 17
  • 31