首页 > 解决方案 > 调整作为单例且具有最终访问修饰符的方法的返回值

问题描述

我想从实例类调整方法的返回值,我不太确定是否可以使用或不使用反射。我想不通,所以我想在这里问。假设我有例如以下类 Foo:

public final class Foo {

    private static final INSTANCE = new Foo()

    protected Foo() {}
    
    public final String getName() {
        return "Foo";
    }

    public static Foo getInstance() {
        return INSTANCE;
    }
    
}

一些上下文:

因此,对于这个基本示例,我想从方法 getName() 而不是Foo返回Bar。要非常明确:

Foo foo = Foo.getInstance();
String name = foo.getName();
System.out.println(name) // --> prints "Bar"

为什么我需要这个?

好吧,我需要将 Foo 的这个实例传递给另一个只接受 Foo 类型的对象的方法。此方法将调用方法 getName() 并进行一些额外的计算。

实际用例:

我将尝试提供更多上下文,希望它会更清楚一点。构建器类中有一个方法,它接受一个KeyManagerFactory名为 的方法的实例setKeyManagerFactory(KeyManagerFactory keyManagerFactory)。此构建器类将在内部调用getKeyManagersKeyManagerFactory 并将返回KeyManagers[]

KeyManagerFactory 是最终类,它根本没有公共构造函数。getKeyManager 方法也是最终的。我已经有一个KeyManager[],所以我想破解这个 KeyManagerFactory 来返回我自己的数组自己的 KeyManagers 并将其提供给构建器。

通常 KeyManagerFactory 使用以下代码片段进行实例化:

KeyStore keyStore = ... //initialized keyStore
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
kmf.init(keyStore, keyPassword);

KeyManager[] keyManagers = kmf.getKeyManagers();

使用上面的代码片段,KeyManagerFactory 将根据提供的 KeyStore 对象返回一个 KeyManager 数组。我想要实现的是以某种方式返回我的自定义 KeyManager 数组。

我还添加了 KeyManagerFactory 的反编译源代码:

package javax.net.ssl;

import java.security.AccessController;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivilegedAction;
import java.security.Provider;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import sun.security.jca.GetInstance;
import sun.security.jca.GetInstance.Instance;

public class KeyManagerFactory {
    private Provider provider;
    private KeyManagerFactorySpi factorySpi;
    private String algorithm;

    public static final String getDefaultAlgorithm() {
        String var0 = (String)AccessController.doPrivileged(new PrivilegedAction<String>() {
            public String run() {
                return Security.getProperty("ssl.KeyManagerFactory.algorithm");
            }
        });
        if (var0 == null) {
            var0 = "SunX509";
        }

        return var0;
    }

    protected KeyManagerFactory(KeyManagerFactorySpi var1, Provider var2, String var3) {
        this.factorySpi = var1;
        this.provider = var2;
        this.algorithm = var3;
    }

    public final String getAlgorithm() {
        return this.algorithm;
    }

    public static final KeyManagerFactory getInstance(String var0) throws NoSuchAlgorithmException {
        Instance var1 = GetInstance.getInstance("KeyManagerFactory", KeyManagerFactorySpi.class, var0);
        return new KeyManagerFactory((KeyManagerFactorySpi)var1.impl, var1.provider, var0);
    }

    public static final KeyManagerFactory getInstance(String var0, String var1) throws NoSuchAlgorithmException, NoSuchProviderException {
        Instance var2 = GetInstance.getInstance("KeyManagerFactory", KeyManagerFactorySpi.class, var0, var1);
        return new KeyManagerFactory((KeyManagerFactorySpi)var2.impl, var2.provider, var0);
    }

    public static final KeyManagerFactory getInstance(String var0, Provider var1) throws NoSuchAlgorithmException {
        Instance var2 = GetInstance.getInstance("KeyManagerFactory", KeyManagerFactorySpi.class, var0, var1);
        return new KeyManagerFactory((KeyManagerFactorySpi)var2.impl, var2.provider, var0);
    }

    public final Provider getProvider() {
        return this.provider;
    }

    public final void init(KeyStore var1, char[] var2) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
        this.factorySpi.engineInit(var1, var2);
    }

    public final void init(ManagerFactoryParameters var1) throws InvalidAlgorithmParameterException {
        this.factorySpi.engineInit(var1);
    }

    public final KeyManager[] getKeyManagers() {
        return this.factorySpi.engineGetKeyManagers();
    }
}

标签: javasslreflectionsingleton

解决方案


你可以这样做。(您可以将 setAccessible(true) 用于私有字段)

public final class  Single {
    public String s;

    public Single() {
    }

    public String getS() {
        return s;
    }
}

public class Main {
    public static void main(String[] args) throws IllegalAccessException {
        Single single = new Single();
        single.getClass().getFields()[0].set(single, "Hmm");
        System.out.println(single.getS());
    }
}

推荐阅读