首页 > 解决方案 > 反射值未正确输出

问题描述

我目前正在做一个项目,我决定创建一个新的测试项目来了解我失败的地方。我以一种简单的方式重新创建了我正在使用的类。我的测试项目如下所示:

在此处输入图像描述

这些是 Java 类。

ChunkGenerator

package chunk;

public interface ChunkGenerator {
    WorldChunkManager getManager();
}

ChunkGeneratorAbstact

package chunk;    

public class ChunkGeneratorAbstract implements ChunkGenerator {
    private WorldChunkManager c;

    public ChunkGeneratorAbstract(WorldChunkManager c){
        this.c = c;
    }

    @Override
    public WorldChunkManager getManager() {
        return c;
    }
}

WorldChunkManager

package chunk;

import java.util.UUID;

public class WorldChunkManager {
    private UUID uuid;

    public WorldChunkManager(UUID uuid){
        this.uuid = uuid;
    }

    public UUID getUuid() {
        return uuid;
    }
}

World

package world;

public class World {
    private WorldProvider provider;

    public World(WorldProvider provider){
        this.provider = provider;
    }

    public WorldProvider getProvider(){
        return provider;
    }
}

Main

import chunk.ChunkGenerator;
import chunk.ChunkGeneratorAbstract;
import chunk.WorldChunkManager;
import world.World;
import world.WorldProvider;

import java.lang.reflect.Field;
import java.util.UUID;

public class Main {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        WorldChunkManager manager = new WorldChunkManager(UUID.randomUUID());
        System.out.println("DEFAULT MANAGER UUID:" + manager.getUuid());

        ChunkGeneratorAbstract chunkGeneratorAbstract = new ChunkGeneratorAbstract(manager);
        System.out.println("ChunkGeneratorAbstract: " + chunkGeneratorAbstract.getManager());

        ChunkGenerator generator = new ChunkGenerator() {
            @Override
            public WorldChunkManager getManager() {
                return manager;
            }
        };

        WorldProvider provider = new WorldProvider(generator);
        System.out.println("DEFAULT PROVIDER: " + provider);

        World world = new World(provider);

        Field field = chunkGeneratorAbstract.getClass().getDeclaredField("c");
        field.setAccessible(true);
        WorldChunkManager manager1 = new WorldChunkManager(UUID.randomUUID());
        field.set(chunkGeneratorAbstract, manager1);
        System.out.println("CUSTOM MANAGER UUID: " + manager1.getUuid());

        System.out.println("FINAL:" + world.getProvider().getGenerator().getManager().getUuid());

    }
}

这是putput:

DEFAULT MANAGER UUID:7c85e3ec-2288-4427-aae3-ce9e0b72c581
ChunkGeneratorAbstract: chunk.WorldChunkManager@2b193f2d
DEFAULT PROVIDER: world.WorldProvider@355da254
CUSTOM MANAGER UUID: 98a89e86-3b81-4fc3-8b5d-f22645b1685a
FINAL:7c85e3ec-2288-4427-aae3-ce9e0b72c581

正如您在使用反射并将 设置WorldChunkManager为自定义后看到的那样,我尝试打印出 的 UUID WorldChunkManager,但由于某种原因,我一直得到原始的而不是自定义的

标签: javareflection

解决方案


ChunkGenerator您在此代码中有 2 个实例:

// 1
ChunkGeneratorAbstract chunkGeneratorAbstract = new ChunkGeneratorAbstract(manager);
// 2
ChunkGenerator generator = new ChunkGenerator() {
    @Override
    public WorldChunkManager getManager() {
        return manager; // hard-coded to return manager
    }
};

您使用反射来更改WorldChunkManagerof chunkGeneratorAbstract,但WorldProvider创建时引用了另一个:

WorldProvider provider = new WorldProvider(generator);
//                                         ^^^^^^^^^
World world = new World(provider);

当你这样做时world.getProvider().getGenerator(),它会返回 other ChunkGenerator,它被硬编码为 return manager

我想您需要创建WorldProvider这种方式来查看您期望的行为:

WorldProvider provider = new WorldProvider(chunkGeneratorAbstract);

还:

  1. 这个问题实际上与反射的使用无关。如果你在ChunkGeneratorAbstract课堂上做了一个 setter 并使用它,你会看到同样的问题。

  2. 像这样使用反射设置私有字段不是一个好习惯。我们将类(和其他成员)的字段设为私有,作为与使用该类的代码的合同的一部分。约定是使用该类的代码必须以某种方式使用它(由其设计者规定),并且不得依赖私有成员。通过使用反射来访问私有成员,您违反了该合同。


推荐阅读