public static void main( String... args )
    {
        Interface1 reflectProxy = Interface1.class.cast( Proxy.newProxyInstance(
                IndyProxyTest.class.getClassLoader(), new Class[]{Interface1.class},
                new InvocationHandler()
                {
                    @Override
                    public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable
                    {
                        if ( Object.class == method.getDeclaringClass() )
                        {
                            switch ( method.getName() )
                            {
                            case "hashCode":
                                return "foo".hashCode();
                            case "equals":
                                return proxy.getClass().isInstance( args[0] );
                            case "toString":
                                return "foo";
                            }
                        }
                        else
                        {
                            return SayHelloBootstrap.sayHello( "foo" );
                        }
                        throw new UnsupportedOperationException();
                    }
                } ) );
        Interface1 indyProxy = createProxyFactory( IndyProxyTest.class.getClassLoader(), new SayHelloBootstrap(),
                                                   Interface1.class ).create( "foo" );
        Interface1 noProxy = new Interface1()
        {
            @Override
            public String sayHello()
            {
                return SayHelloBootstrap.sayHello( "foo" );
            }
        };
        boolean skipReflect = Boolean.getBoolean( "skipReflect" );
        boolean skipIndy = Boolean.getBoolean( "skipIndy" );
        boolean skipDirect = Boolean.getBoolean( "skipDirect" );
        benchmark( reflectProxy, 10 );
        benchmark( indyProxy, 10 );
        for ( int iterations = 1_000_000; ; )
        {
            assertTrue( reflectProxy.equals( reflectProxy ) );
            assertTrue( indyProxy.equals( indyProxy ) );
            assertEquals( reflectProxy.hashCode(), indyProxy.hashCode() );
            assertEquals( reflectProxy.toString(), indyProxy.toString() );
            long reflectTime = 0, indyTime = 0, noTime = 0;
            if ( !skipReflect )
            {
                reflectTime = benchmark( reflectProxy, iterations );
            }
            if ( !skipIndy )
            {
                indyTime = benchmark( indyProxy, iterations );
            }
            if ( !skipDirect )
            {
                noTime = benchmark( noProxy, iterations );
            }
            System.out.printf( "reflectProxy:%.3fns/inv   indyProxy:%.3fns/inv   noProxy:%.3fns/inv%n",
                               reflectTime / (double) iterations, indyTime / (double) iterations,
                               noTime / (double) iterations );
        }
    }