代码之家  ›  专栏  ›  技术社区  ›  GuruKulki

与类级和实例级混淆

  •  3
  • GuruKulki  · 技术社区  · 15 年前

    我有以下课程:

    public class B {
    
        public void print() {
        }
    
        public static void main(String[] args) {
            B B = new B();
            B.print();
        }
    
    }
    

    我想知道为什么编译器没有给出错误,说它不是静态方法。当对象与类相同时,它将如何区分类级别和实例级别?

    5 回复  |  直到 15 年前
        1
  •  5
  •   Bozho    15 年前

    因为您正在访问类实例上的方法。顺便说一句,实例的名称与类名相同,但是由于没有具有此名称的静态方法,编译器假定是正确的,即实例方法。

    如果你把方法定义为 static ,然后它将再次假设唯一可能的事情-调用 静止的 方法在 B 类,因为实例没有此类方法。

    最终,你不能同时拥有 静止的 而非 静止的 方法的名称相同。

        2
  •  3
  •   ewernli    15 年前

    这个 JLS 讨论并定义此类情况范围规则的优先级:

    6.3.2模糊声明

    简单名称可能出现在 可能被解释为 变量、类型或 包裹。在这种情况下, _6.5条规定 变量 将优先选择 类型 ,并且将选择一个类型 而不是包裹。因此,它 有时是不可能的 引用可见的类型或包 通过其简单名称声明。我们 说这样的声明是 模糊的。

    还有其他边界案例,其中变量可以是 阴影的 隐藏 . 例子:

    class Test {
            static int x = 1;
            public static void main(String[] args) {
                    int x = 0;
                    System.out.print("x=" + x);
                    System.out.println(", Test.x=" + Test.x);
            }
    }
    

    同样,编译器遵循jls并根据规范解析名称。编译器不是智能的,不会“发现”任何东西,它只是遵循规范。

        3
  •  2
  •   Herms    15 年前

    你的问题是关于print()方法吗?它之所以起作用是因为变量名“隐藏”了类型名,所以当您执行b.print()操作时,它会查看变量b,这是类b的一个实例。

    您真的不应该将变量调用为与类相同的名称,至少不应该使用相同的大小写。如果将变量重命名,即使只是将其重命名为“b”,情况也会更清楚。所以:

    public class B{
    
      public void print(){
    
      }
    
      public static void main(String[] args){
    
        B b = new B();
    
        b.print(); // This works
        B.print(); // this fails
    
      }
    
    }
    
        4
  •  0
  •   Poindexter    15 年前

    因为在那个例子中, print() 是实例方法。它是从类B的一个实例调用的。如果您的主类如下所示:

    public static void main(String[] args){
           print():
           }
    

    然后 打印() 必须是静态方法。

    实例的名称与类的名称相同也无关紧要。自从 打印() 是一个实例方法,它期望从对象调用它。恰巧有一个名为b的对象,它是类b的一个实例,所以没有问题。

        5
  •  0
  •   Danilo Piazzalunga    15 年前

    我想类名和实例变量不共享同一个名称空间;对于编译器来说,很明显 B.print() 正在对实例而不是类调用。

    无需说这令人困惑,应该在真正的代码中避免;)