冷湘宇 Coldxiangyu's blog

接口可以直接new?

2015-04-21

看到标题,不免让人心生怀疑。接口难道可以new?
我们知道接口本身是用来定义标准的,具体实现由实现类来填充,使用的时候我们再实例化对应的接口的实现类。
严格来说,接口不能new。
但是我们可以通过匿名内部类的方式,无需创建独立的实现类,完成接口的实现。

比如我们常用的实现Runnable接口启动线程的方式:

new Thread(new Runnable(){
    @Override
    public void run(){
        ......
    }
}).start();

这样的写法,大大的简化了我们的代码,否则,我们需要单独定义Runnable的实现类。
还有我们常用的动态代理,其实也可以使用匿名内部类的方式,正常情况下我们定义InvocationHandler的实现类,进行代理方法invoke方法的重写。实际上我们完全可以通过下面的代码实现:

Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] {interfaceClass}, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
            //..........
            }
}

这样,我们就省去了InvocationHandler接口实现类的开销。

实际上在我们的类编译class的时候,匿名内部类也是单独编译成class文件的,见下图: image_1binq5fj7u38jaor7g1137b1q9.png-15.5kB
我们对匿名内部类进行反编译:

RpcFramework$1.class

package com.lxy.rpc.framework;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;

final class RpcFramework$1
  implements Runnable
{
  public void run()
  {
    try
    {
      try
      {
        ObjectInputStream input = new ObjectInputStream(this.val$socket.getInputStream());
        try {
          String methodName = input.readUTF();
          Class[] parameterTypes = (Class[])(Class[])input.readObject();
          Object[] arguments = (Object[])(Object[])input.readObject();
          ObjectOutputStream output = new ObjectOutputStream(this.val$socket.getOutputStream());
          try {
            Method method = this.val$service.getClass().getMethod(methodName, parameterTypes);
            Object result = method.invoke(this.val$service, arguments);
            output.writeObject(result);
            output.writeUTF("123123");
          } catch (Throwable t) {
            output.writeObject(t);
          } finally {
            output.close();
          }
        } finally {
          input.close();
        }
      } finally {
        this.val$socket.close();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

RpcFramework$2.class

package com.lxy.rpc.framework;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.Socket;

final class RpcFramework$2
  implements InvocationHandler
{
  public Object invoke(Object proxy, Method method, Object[] arguments)
    throws Throwable
  {
    Socket socket = new Socket(this.val$host, this.val$port);
    try {
      ObjectOutputStream output;
      try {
        output.writeUTF(method.getName());
        output.writeObject(method.getParameterTypes());
        output.writeObject(arguments);
        ObjectInputStream input;
        try {
          Object result = input.readObject();
          System.out.println(input.readUTF());
          if (result instanceof Throwable) {
            throw ((Throwable)result);
          }
          Object localObject1 = result;

          input.close();

          output.close();

          return localObject1;
        }
        finally
        {
          input.close();
        }
      } finally {
        output.close();
      }
    } finally {
      socket.close();
    }
  }
}

可以看到,其实匿名内部类其实都实现了各自的接口,只是在写法上更简单而已。


Similar Posts

上一篇 MyEclipse整合Git

Comments