SharedSecrets 机制是如何工作的?

Gil*_*ili 2 java

jdk.internal.misc.SharedSecrets 将自己描述为:

“共享秘密”的存储库,这是一种在不使用反射的情况下调用另一个包中的实现私有方法的机制。包私有类实现了一个公共接口,并提供了在该包内调用包私有方法的能力;实现该接口的对象是通过限制访问的第三个包提供的。该框架避免了为此目的使用反射的主要缺点,即编译时检查的丢失。

有人可以提供一个示例来演示这种机制如何使一个包中的类能够访问不同包中的包私有方法吗?

Gil*_*ili 6

引用http://blog.fuseyism.com/index.php/2008/05/26/sharing-secrets/

在查看 VM 项目的 OpenJDK 时,我注意到他们对此有一个相当有趣的解决方案。这封装在 sun.misc.SharedSecrets 中。此类提供对许多公共接口实例的访问,例如 sun.misc.JavaLangAccess。实际的实现在适当的包中作为内部类提供,例如 java.lang,它可以访问其中的私有和包私有变量和方法。

下面是一个具体的例子:

  • 我们有两个类:CharacterStory
  • 我们希望将Character的非公共方法公开给Story但不公开给外部用户(驻留在模块之外的类)。

主.java:

package external.main;

import external.character.Character;
import external.story.Story;

public class Main
{
    public static void main(String[] args)
    {
        Story story = new Story();
        story.introduce(Character.HARRY_POTTER);
        story.introduce(Character.RON_WEASLEY);
        story.introduce(Character.HERMIONE_GRANGER);
    }
}
Run Code Online (Sandbox Code Playgroud)

故事.java

package external.story;

import external.character.Character;
import internal.secrets.SharedSecrets;

public final class Story
{
    /**
     * Introduces a character.
     *
     * @param character the character
     */
    public void introduce(Character character)
    {
        System.out.println(character.name() + " enters the room and says: " + SharedSecrets.INSTANCE.secretCharacter.getPhrase(character));
    }
}
Run Code Online (Sandbox Code Playgroud)

字符.java:

package external.character;

import internal.secrets.SecretCharacter;
import internal.secrets.SharedSecrets;

public enum Character
{
    HARRY_POTTER
    {
        @Override
        String getPhrase()
        {
            return "Your bird, there was nothing I could do. He just caught fire.";
        }
    },
    RON_WEASLEY
    {
        @Override
        String getPhrase()
        {
            return "Who are you and what have you done with Hermione Granger?";
        }
    },
    HERMIONE_GRANGER
    {
        @Override
        String getPhrase()
        {
            return "I'm not an owl!";
        }
    };

    static
    {
        SharedSecrets.INSTANCE.secretCharacter = new SecretCharacter()
        {
            @Override
            public String getPhrase(Character character)
            {
                return character.getPhrase();
            }
        };
    }

    /**
     * @return the character's introductory phrase
     */
    abstract String getPhrase();
}
Run Code Online (Sandbox Code Playgroud)

SharedSecrets.java:

package internal.secrets;

public final class SharedSecrets
{
    public static SharedSecrets INSTANCE = new SharedSecrets();
    public SecretCharacter secretCharacter;

    /**
     * Prevent construction.
     */
    private SharedSecrets()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

SecretCharacter.java:

package internal.secrets;

import external.character.Character;

public interface SecretCharacter
{
    /**
     * @param character a character
     * @return the character's introductory phrase
     */
    String getPhrase(Character character);
}
Run Code Online (Sandbox Code Playgroud)

模块信息.java:

module SharedSecret
{
    exports external.character;
    exports external.main;
    exports external.story;
}
Run Code Online (Sandbox Code Playgroud)

输出

HARRY_POTTER 走进房间说:你的鸟,我无能为力。他刚刚着火了。

RON_WEASLEY 走进房间说:你是谁,你对赫敏格兰杰做了什么?

HERMIONE_GRANGER 走进房间说:我不是猫头鹰!

解释

  • external.character.Character.getPhrase() 是包保护的。
  • external.story.Story 位于不同的包中。
  • 通常Story无法调用Character.getPhrase(); 但是,SharedSecrets允许Character与其信任的类共享访问权限。
  • Story调用SharedSecrets.INSTANCE.secretCharacter它使用匿名嵌套类来访问Character的内部。
  • external.story.Story可以访问,internal.secrets.SharedSecrets因为两者位于同一个模块中,但外部用户无法访问它,因为module-info.java不导出该包。

如果要将 SharedSecrets 导出到受信任的外部模块,请参阅/sf/answers/3755755601/