Service Loader实现需要默认的公共构造函数

时间:2013-07-03 13:54:04

标签: java static constructor externalizable

我试图了解Java Service Loader的工作原理?我偶然发现了blog

请您帮助我理解作者声称的原因:

  

实现必须具有公共无参数构造函数。

好的,我得到了第一部分。现在是一个跟进问题。我可以将其作为后续问题发布,但想到了 将它作为同一问题的一部分会更好。

考虑java doc

它说:

  

此外,必须编译非私有内部成员类的构造函数,使其具有作为其第一个参数的附加隐式参数,该参数表示直接封闭的实例(第8.1.3节)。

这是否意味着我不能外化内部类。请考虑以下代码:

import java.io.*;

class Y {
  class ABC {
    ABC() {
      System.out.println("ABC Constructor");
    }
    public void writeExternal(ObjectOutput out)
      throws IOException {
      System.out.println("ABC.writeExternal");
    }
    public void readExternal(ObjectInput in)
      throws IOException, ClassNotFoundException {
      System.out.println("ABC.readExternal");
    }
  }

  public void foo() throws IOException, ClassNotFoundException {
    System.out.println("Constructing objects:");
    ABC abc = new ABC();
    ObjectOutputStream o = new ObjectOutputStream(
    new FileOutputStream("InnerClass.out"));
    System.out.println("Saving objects:");
    o.writeObject(abc);
    o.close();
    // Now get them back:
    ObjectInputStream in = new ObjectInputStream(
      new FileInputStream("InnerClass.out"));
    System.out.println("Recovering abc:");
    // OOPS! Throws an exception:
    abc = (ABC)in.readObject();
  }
}

public class InnerClass {
  public static void main(String[] args) throws IOException, ClassNotFoundException {
    System.out.println("Hello World\n");
    Y y = new Y();
    System.out.println(y);
    y.foo();
  }  
}

它在运行时失败:

Hello World

Y@6bc7c054
Constructing objects:
ABC Constructor
Saving objects:
Exception in thread "main" java.io.NotSerializableException: Y$ABC
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
    at Y.foo(InnerClass.java:24)
    at InnerClass.main(InnerClass.java:40)

如何使用Externalize类ABC?

由于

3 个答案:

答案 0 :(得分:2)

那是因为需要通过反射创建一个新实例。

I guess here's relevant code, line 362

S p = service.cast(Class.forName(cn, true, loader).newInstance());

因此它从Class.newInstance() can only invoke the zero-argument constructor开始调用“无参数”构造函数。

修改

实际上,除非你定义另一个构造函数,否则为public class创建零参数构造函数不是必需

javadoc

  
    

您不必为您的班级提供任何构造函数,但在执行此操作时必须小心。编译器会自动为没有构造函数的任何类提供无参数的默认构造函数。

  

因此,以下代码完全正确:

public final class MyServiceImpl implements MyService { 
    @Override
    public long getTime() {
        return System.currentTimeMillis();
    } 
}

MyServiceImpl的默认构造函数与:

相同
public MyServiceImpl() { }

MyServiceImpl is a public class

以来
  
    

如果类被声明为public,则默认构造函数被隐式赋予访问修饰符public

  

因此MyServiceImpl中的构造函数是多余的。

我的猜测是博客文章的作者只是想确保ServiceLoader能够实例化服务提供商,即使它包含一些带参数的显式构造函数。


结论: 服务提供商 应该只有在包含带参数的显式构造函数时才有明确的无参数构造函数。否则默认构造函数就足够了。

答案 1 :(得分:1)

许多技术都需要无参数构造函数,因此可以创建实例。如果只有构造函数需要参数,则该机制不知道要传递什么。

一个值得注意的例外是序列化机制,它不需要no-param构造函数,但这只是因为它有一些来自VM的“魔术帮助”。

答案 2 :(得分:1)

您可以在官方java doc

上阅读原因
  

此工具强制执行的唯一要求是提供者类必须具有零参数构造函数,以便在加载期间实例化它们。

如果您使用参数声明了构造函数,则无法正确使用它。 阅读此article示例