4

我试图了解 Java Service Loader 的工作原理?我遇到了这个博客

您能否帮助我理解作者为何声称:

实现必须有一个公共的无参数构造函数。

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

考虑java 文档

它说:

此外,必须编译非私有内部成员类的构造函数,使其第一个参数是表示直接封闭实例的附加隐式参数(第 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?

谢谢

4

3 回答 3

3

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

我想这是相关的代码,第 362 行

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

因此它调用“无参数”构造函数,因为Class.newInstance()只能调用零参数构造函数

编辑:

实际上,除非您定义另一个构造函数,否则不需要创建零参数构造函数。public class

文档

您不必为您的类提供任何构造函数,但这样做时必须小心。编译器会自动为任何没有构造函数的类提供无参数的默认构造函数。

所以,下面的代码是完全正确的:

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

默认构造函数MyServiceImpl 将与以下内容相同:

public MyServiceImpl() { }

由于MyServiceImpl 是公共课程

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

因此构造函数 inMyServiceImpl是多余的。

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


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

于 2013-07-03T14:00:47.853 回答
2

您可以在官方 java doc上阅读原因

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

如果您声明了带有参数的构造函数,则无法正确使用它。通过示例阅读本文

于 2013-07-03T14:23:24.183 回答
1

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

一个值得注意的例外是序列化机制,它不需要无参数构造函数,但这仅仅是因为它从 VM 中添加了一些“魔法帮助”。

于 2013-07-03T14:01:21.777 回答