静态内部类访问外部非静态成员

静态内部类访问外部非静态成员

在java中,静态内部类(static nested class)只能访问外部类的静态成员,不能访问外部类的非静态成员。

静态内部类如何访问外部被”@Resource“修饰的非静态成员,该成员变量如下:

@Resource
private TerminalMstMapper terminalMstMapper;

解决思路:@Resource通常用于注入非静态的成员。如果你需要在静态内部类中使用这个成员,那么你应该考虑将外部类的实例传入静态内部类。

方案1:通过外部类实例传递依赖(推荐)

在创建静态内部类对象时,将外部类的依赖(terminalMstMapper)通过构造函数或方法传入。

@Service
public class OutClass {
    @Resource
    private TerminalMstMapper terminalMstMapper;

    public static class StaticInnerClass{

        private final TerminalMstMapper terminalMstMapper;
        //通过构造函数传入依赖
        public StaticInnerClass(TerminalMstMapper mapper){
            this.terminalMstMapper = mapper;
        }

        public void doSomething(){
            //可以使用传入的mapper
            terminalMstMapper.selectByPrimaryKey(1);
        }
    }

    public void doSomething(){
        //创建静态内部类实例
        StaticInnerClass innerClass = new StaticInnerClass(this.terminalMstMapper);
        innerClass.doSomething();
    }
}

方案2:将依赖声明为静态(需谨慎)

如果你的静态内部类只需要访问外部类的静态成员,你可以将外部类的依赖(terminalMstMapper)声明为静态变量,并通过静态方法初始化(需确保线程安全)。

@Service
public class OuterClass {
    
    private static TerminalMstMapper terminalMstMapper; // 静态成员

    @Resource
    public void setTerminalMstMapper(TerminalMstMapper mapper) {
        OuterClass.terminalMstMapper = mapper; // 手动注入到静态变量
    }

    public static class StaticInnerClass {
        public void doSomething() {
            // 直接访问静态变量
            if (terminalMstMapper != null) {
                terminalMstMapper.someMethod();
            }
        }
    }
}

外部类中提供一个静态的方法或字段来访问该Mapper

在外部类中提供一个静态的方法或字段来访问该Mapper,但是同样,这个静态的访问点需要依赖于外部类的实例。

使用@PostConstruct注解来确保在Spring初始化后执行初始化方法,将外部类的实例赋值给静态变量。

@PostConstruct用于标记一个方法,该方法应在依赖注入完成后(如 @Autowired/@Resource 注入结束),构造函数执行之后,对象投入使用前被自动调用。在 Spring 框架中,它也被支持并具有相同的作用。执行顺序如下:

graph LR A[构造函数] --> B[依赖注入] --> C[@PostConstruct方法] --> D[Bean投入使用]

@PostConstruct 是 Spring Bean 生命周期管理的关键注解,它解决了 依赖注入与初始化逻辑的时序问题,确保初始化代码能安全使用所有注入的依赖项。相较于构造函数初始化,它更符合依赖注入的原则,是 Spring 应用中最推荐的初始化方式之一。

@PostConstruct注意事项:

  • 方法必须是 void 返回类型;
  • 不能是 static 方法,因为 static 方法在类加载时就会执行,而 @PostConstruct 是在 Bean 初始化后执行的;
  • 不能有参数;
  • 访问权限建议 public(Spring 要求非 private);
@Service
public class ExternalClass {

    @Resource
    private TerminalMstMapper terminalMstMapper;

    private static ExternalClass instance;
    
    @PostConstruct
    public void init(){
        instance = this;
    }

    public static TerminalMstMapper getTerminalMstMapper(){
        return instance.terminalMstMapper;
    }
    
    private static class StaticInnerClass{
        public void doSomething(){
            TerminalMstMapper mapper = instance.getTerminalMstMapper();
        }
    }
}

这种方法需要注意:

它使用了静态字段(instance),在Spring中,如果存在多个实例(比如原型作用域),那么instance会被覆盖为最后一个初始化的实例。

通常,我们不推荐使用静态字段来持有Spring Bean,因为这可能导致内存泄漏或状态不一致。

总结

  • 方案1更安全:避免了静态变量的线程安全问题,符合依赖注入原则。
  • 方案2和方案3的风险:静态变量在并发环境下可能被覆盖,且生命周期与整个应用一致,可能导致内存泄漏。
posted @ 2025-06-17 23:13  joudys  阅读(28)  评论(0)    收藏  举报