import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

import static java.lang.invoke.MethodHandles.identity;
import static java.lang.invoke.MethodHandles.loop;

/**
 * @author Anastasiya Solodkaya.
 */
public class InitNullImpl {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException {
        Increment1 increment = new Increment1();
        docImplementation(null, increment.predHandle(), increment.bodyHandle());
    }

    private static MethodHandle docImplementation(MethodHandle init, MethodHandle pred, MethodHandle body) {
        MethodHandle[]
                checkExit = {null, null, pred, identity(init.type().returnType())},
                varBody = {init, body};
        return loop(checkExit, varBody);
    }


    private static class Increment1 {
        private int i = 0;

        void init(int k) {
        }

        void body(int k) {
            i++;
        }

        boolean pred(int k) {
            return i < k;
        }

        /**
         * Handle for static method {@link Increment1#init(int)} bound to current instance
         */
        MethodHandle initHandle() throws NoSuchMethodException, IllegalAccessException {
            return MethodHandles.lookup().findVirtual(getClass(), "init", MethodType.methodType(void.class, int.class)).bindTo(this);
        }

        /**
         * Handle for static method {@link Increment1#pred(int)} bound to current instance
         */
        MethodHandle predHandle() throws NoSuchMethodException, IllegalAccessException {
            return MethodHandles.lookup().findVirtual(getClass(), "pred", MethodType.methodType(boolean.class, int.class)).bindTo(this);
        }

        /**
         * Handle for static method {@link Increment1#body(int)} bound to current instance
         */
        MethodHandle bodyHandle() throws NoSuchMethodException, IllegalAccessException {
            return MethodHandles.lookup().findVirtual(getClass(), "body", MethodType.methodType(void.class, int.class)).bindTo(this);
        }
    }
}
