[关闭]
@coldxiangyu 2017-06-16T06:47:19.000000Z 字数 2466 阅读 1235

接口可以直接new?

java黑科技


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

  1. new Thread(new Runnable(){
  2. @Override
  3. public void run(){
  4. ......
  5. }
  6. }).start();

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

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

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

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

RpcFramework$1.class

  1. package com.lxy.rpc.framework;
  2. import java.io.ObjectInputStream;
  3. import java.io.ObjectOutputStream;
  4. import java.lang.reflect.Method;
  5. import java.net.Socket;
  6. final class RpcFramework$1
  7. implements Runnable
  8. {
  9. public void run()
  10. {
  11. try
  12. {
  13. try
  14. {
  15. ObjectInputStream input = new ObjectInputStream(this.val$socket.getInputStream());
  16. try {
  17. String methodName = input.readUTF();
  18. Class[] parameterTypes = (Class[])(Class[])input.readObject();
  19. Object[] arguments = (Object[])(Object[])input.readObject();
  20. ObjectOutputStream output = new ObjectOutputStream(this.val$socket.getOutputStream());
  21. try {
  22. Method method = this.val$service.getClass().getMethod(methodName, parameterTypes);
  23. Object result = method.invoke(this.val$service, arguments);
  24. output.writeObject(result);
  25. output.writeUTF("123123");
  26. } catch (Throwable t) {
  27. output.writeObject(t);
  28. } finally {
  29. output.close();
  30. }
  31. } finally {
  32. input.close();
  33. }
  34. } finally {
  35. this.val$socket.close();
  36. }
  37. } catch (Exception e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. }

RpcFramework$2.class

  1. package com.lxy.rpc.framework;
  2. import java.io.ObjectInputStream;
  3. import java.io.ObjectOutputStream;
  4. import java.io.PrintStream;
  5. import java.lang.reflect.InvocationHandler;
  6. import java.lang.reflect.Method;
  7. import java.net.Socket;
  8. final class RpcFramework$2
  9. implements InvocationHandler
  10. {
  11. public Object invoke(Object proxy, Method method, Object[] arguments)
  12. throws Throwable
  13. {
  14. Socket socket = new Socket(this.val$host, this.val$port);
  15. try {
  16. ObjectOutputStream output;
  17. try {
  18. output.writeUTF(method.getName());
  19. output.writeObject(method.getParameterTypes());
  20. output.writeObject(arguments);
  21. ObjectInputStream input;
  22. try {
  23. Object result = input.readObject();
  24. System.out.println(input.readUTF());
  25. if (result instanceof Throwable) {
  26. throw ((Throwable)result);
  27. }
  28. Object localObject1 = result;
  29. input.close();
  30. output.close();
  31. return localObject1;
  32. }
  33. finally
  34. {
  35. input.close();
  36. }
  37. } finally {
  38. output.close();
  39. }
  40. } finally {
  41. socket.close();
  42. }
  43. }
  44. }

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

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注