Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 与.Net不同,为什么Java中的实例可以访问静态成员_C#_Java - Fatal编程技术网

C# 与.Net不同,为什么Java中的实例可以访问静态成员

C# 与.Net不同,为什么Java中的实例可以访问静态成员,c#,java,C#,Java,总之,与C#不同,我发现Java中的实例可以访问静态成员。好的,我对此没有任何意见。但事实上这会引起一个问题。让我举个例子来解释一下 假设我们已经有两个班了 public class A { public void m1() { ... } } publc class B { public void m2() { A a= new A(); a.m1(); } } 已经

总之,与C#不同,我发现Java中的实例可以访问静态成员。好的,我对此没有任何意见。但事实上这会引起一个问题。让我举个例子来解释一下

假设我们已经有两个班了

public class A
{
     public void m1()
     {   
         ...
     } 
} 

publc class B
{
     public void m2()
     {
         A a= new A();
         a.m1();
     }
}
已经编译并部署了这些类。它总是很好用。但出于某种原因。有人更改了类
A
,如下所示

    public class A
    {
         public static void m1()
         {   
             ...
         } 
    }
所以他只是编译了
A
并部署了它。类
B
不需要更改。因为代码是一样的。 如果未编译类
B
,则会发生异常

Exception in thread "main" java.lang.IncompatibleClassChangeError: 
Expecting non-static method A.main() at B.main(b.java:34)

虽然从实例变量调用静态成员时没有意义。但是Java允许我们这样做。我只是不明白为什么Java允许它?谢谢。

您必须区分源代码和字节代码

不幸的是,在源代码中,Java允许通过实例引用访问静态成员。因此,您可以轻松编写
a.m1()
,其中
a
是一个变量(如您的示例所示)。然而,这是非常糟糕的风格,因此不推荐

静态绑定在编译时解析。因此,编译器直接将对静态成员的访问以及对类的引用写入字节码。因此,在分析结果字节码时,您将再也找不到实例引用(关于静态成员)


这种区别是你的例外的原因。类B的字节码仍然包含对动态链接方法的调用,而动态链接方法在类a的字节码中根本不存在。结果:异常。

您必须区分源代码和字节码

不幸的是,在源代码中,Java允许通过实例引用访问静态成员。因此,您可以轻松编写
a.m1()
,其中
a
是一个变量(如您的示例所示)。然而,这是非常糟糕的风格,因此不推荐

静态绑定在编译时解析。因此,编译器直接将对静态成员的访问以及对类的引用写入字节码。因此,在分析结果字节码时,您将再也找不到实例引用(关于静态成员)

这种区别是你的例外的原因。类B的字节码仍然包含对动态链接方法的调用,而动态链接方法在类a的字节码中根本不存在。结果:异常。

在C中不能这样做的原因是,语言设计者认为这是一种不好的做法,可能会让人困惑

以下面的Java示例为例:

class A {
    public static void Foo() {
        System.out.println("A::foo");
    }
    public void Bar() {
        System.out.println("A::bar");
    }
}

class B extends A {
    public static void Foo() {
        System.out.println("B::foo");
    }
    public void Bar() {
        System.out.println("B::bar");
    }
}

public static void main(String[] args) {
    A a = new B();
    a.foo();  // A::foo
    a.bar();  // B::bar
    a = null; // Oh-oh
    a.foo();  // A::foo
}
如您所见,即使将
a
设置为
null
,您仍然可以使用实例变量调用静态方法。对于新手程序员和周一早上来说,这看起来非常混乱。从我收集的资料来看,大多数Java开发人员也反对这种做法

我不太熟悉Java的当前状态,也不太熟悉它们的发展方向。很可能这只是几年前允许的,但很难去掉,因为它可能会破坏许多现有的应用程序。

在C中不能使用的原因是,语言设计者认为这是一种不好的做法,可能会让人困惑

以下面的Java示例为例:

class A {
    public static void Foo() {
        System.out.println("A::foo");
    }
    public void Bar() {
        System.out.println("A::bar");
    }
}

class B extends A {
    public static void Foo() {
        System.out.println("B::foo");
    }
    public void Bar() {
        System.out.println("B::bar");
    }
}

public static void main(String[] args) {
    A a = new B();
    a.foo();  // A::foo
    a.bar();  // B::bar
    a = null; // Oh-oh
    a.foo();  // A::foo
}
如您所见,即使将
a
设置为
null
,您仍然可以使用实例变量调用静态方法。对于新手程序员和周一早上来说,这看起来非常混乱。从我收集的资料来看,大多数Java开发人员也反对这种做法


我不太熟悉Java的当前状态,也不太熟悉它们的发展方向。很可能这只是几年前允许的,但很难取出,因为它可能会破坏许多现有的应用程序。

据我所知,您的问题是“为什么”允许它?对吗?基本上,对于代码进化来说,应该允许这种更改

实际上,您所做的更改被称为二进制不兼容更改。Java语言规范清楚地列出了可能破坏代码的不兼容更改。是的,这是一个二进制不兼容的更改,但编译器无法知道是否有任何客户端应用程序正确使用它?因此,它至少会给您一个警告,作为一名java开发人员,您应该知道这种二进制不兼容的更改及其影响。作为代码的作者,您知道您的代码可能会被其他库使用,这会阻止您对代码库进行此类不兼容的更改(否则会破坏客户端库)。Java编译器没有办法知道这一点,对吗?因此,java允许您更改方法定义,因为这对于代码演化是绝对必要的,而且编译器不知道您的代码是如何分发和使用的。我希望我能解释允许对java代码进行这种不兼容更改的理由。
有关更多信息,请查看

,因为我知道您的问题是“为什么”允许这样做?对吗?基本上,对于代码进化来说,应该允许这种更改

实际上,您所做的更改被称为二进制不兼容更改。Java语言规范清楚地列出了可能破坏代码的不兼容更改。是的,这是一个二进制不兼容的更改,但编译器无法知道是否有任何客户端应用程序正确使用它?因此,它至少会给您一个警告,作为一名java开发人员,您应该知道这种二进制不兼容的更改及其影响。作为代码的作者,您知道您的代码可能会被其他库使用,这会阻止您对代码库进行此类不兼容的更改(否则会破坏客户端库)。Java编译器没有办法知道这一点,对吗?因此,java允许