zoukankan      html  css  js  c++  java
  • Java基础(006):在一个静态方法内调用一个非静态成员为什么是非法的?

      静态方法是属于类层面的,它随着类的加载而加载。JVM在加载类时,就会为静态方法分配内存,可以通过'类名.方法名'来进行调用。静态方法在任意对象实例化之前就已经存在。

      非静态成员(方法或者变量)是属于实例对象的,而实例对象则是在类加载完成之后再创建的。当实例化一个对象时,JVM会为其在堆上分配内存,然后通过this指针指向该实例对象。非静态成员只有在对象实例化之后才会分配内存,然后通过实例对象引用来进行访问。对象都没有存在,非静态成员当然也不存在,只依赖于类而不依赖于实例对象的静态方法自然不能调用一个不存在的方法,当然也根本不知道会调用哪个实例对象的方法。

      类似的错误提示:non-static method cannot be referenced from a static context

    参考:

    扩展1:非静态内部类不能定义静态成员

      参考 stackoverflow 上的一个问题 Why can't we have static method in a (non-static) inner class? https://stackoverflow.com/questions/975134/why-cant-we-have-static-method-in-a-non-static-inner-class

    注:非静态内部类的实例需要依赖外部类实例

    扩展2:项目中遇到的问题和解决方案

      最近有个同事还真碰到了这个问题,代码简化如下(Spring 项目,借助 apollo 获取配置):

    public class SubClient extends SuperClient{
        @Value{${client.url}}
        private static String URL;
        
        private static final String CLASS_NAME = SubClient.class.getName();
        
        public SubClient() {
            super(getFullURL()); // SuperClient 会根据这个URL去进行实际的连接
        }
        
        public static getFullURL() {
            return URL + CLASS_NAME;
        }
    }

       因为 url 可能会修改,就在 apollo 上进行了配置。而又因为父类需要使用这个 URL 进行初始化,于是把 URL 字符串直接设置成了 static 。然后问题来了,总是报连接不上的错误,看了下日志打印出来的 url 串,前面是 null 。很明显 URL 这个没有注入进来。将字符串 URL 直接写死则没有问题。

      一开始没去细看,只知道肯定是 @Value{${client.url}} 没有注入进来才导致的 null ,于是就去检查 apollo 上的配置确认已经OK。

      之后把这个 @Value 获取配置的操作,用另一个类来测试,发现能获取到字符串,但是这个 SubClient 却还是一直获取不了。

      纳闷着为何还会这样,秃然注意到了这是需要放到父类构造器中的参数,子类的实例属性并不能访问,然后就看到了这个 static 关键词,哦,原来静态属性是注入不进来的,URL就是 null ,于是就把 static 去掉了,杯具又来了,就是出现了文章所说的那个问题:静态成员引用了非静态成员。

      这下真不行了,实例属性肯定不能这么搞,思来想去,肯定是得先存在才能引用,于是就把 URL 提取出来当作是配置 bean ,作为构造器参数注入到 SubClient 中就OK了。

    public class URLConfig{
        @Value{${client.url}}
        private String URL;
        
        public String getURL() {
            return this.URL;
        }
        // ...
    }
    
    
    public class SubClient extends SuperClient{
        
        private static final String CLASS_NAME = SubClient.class.getName();
        
        @Autowired
        public SubClient(URLConfig urlConfig) {
            super(urlConfig.getURL() + CLASS_NAME); // SuperClient 会根据这个URL去进行实际的连接
        }
        
    }
  • 相关阅读:
    [RxSwift]4.4、Operator
    [RxSwift]4.3.6、ControlProperty
    [RxSwift]4.3.5、Variable (已弃用)
    [RxSwift]4.3.0、Observable & Observer 既是可监听序列也是观察者
    [RxSwift]4.2.2、Binder
    [RxSwift]4.2.1、AnyObserver
    Java重温学习笔记,Java8新特性:接口的默认方法
    Tomcat下,MySQL连接池的配置和使用(Tomcat9,MySQL5.5)
    MyEclipse2020配置JDK1.8及Tomcat9
    Java重温学习笔记,Java7新特性
  • 原文地址:https://www.cnblogs.com/wpbxin/p/14364563.html
Copyright © 2011-2022 走看看