为什么类成员方法只能访问类成员变量,而不能访问实例成员变量?

时间:2021-03-16 15:10:11
为什么类成员方法只能访问类成员变量,而不能访问实例成员变量?
类成员变量和实例成员变量在内存分配上的区别我知道;但是类成员方和和实力成员方法的访问变量的机制不明白。
请大家指点~

13 个解决方案

#1


 内部类的存在是基于外部类的实例存在的,内部类就好像是跟这个外部类的成员变量或方法一样存在   
  他的存在是为了extends一些类或实现某些接口   
  试想一个成员方法怎么可以访问到人家的变量,   
  她能访问的就是类的成员和方法,如果真的要访问到就要通过间接访问(通过该局部变量的方法或其它来访问)

  内部类在编译后都会产生一个新的Class文件的.   
    
  匿名类在概念上与命名内类一样,即完全在另一个类的界限内定义的类.只是在句法上与命名的内部类不同

#2


   public class Hello{ 
public static void main(String[] args){ //(1) 
System.out.println("Hello,world!"); //(2) 



看过这段程序,对于大多数学过Java 的从来说,都不陌生。即使没有学过Java,而学过其它的高级语言,例如C,那你也应该能看懂这段代码的意思。它只是简单的输出“Hello,world”,一点别的用处都没有,然而,它却展示了static关键字的主要用法。 

在1处,我们定义了一个静态的方法名为main,这就意味着告诉Java编译器,我这个方法不需要创建一个此类的对象即可使用。你还得你是怎么运行这个程序吗?一般,我们都是在命令行下,打入如下的命令(加下划线为手动输入): 

javac Hello.java 
java Hello 
Hello,world! 

这就是你运行的过程,第一行用来编译Hello.java这个文件,执行完后,如果你查看当前,会发现多了一个Hello.class文件,那就是第一行产生的Java二进制字节码。第二行就是执行一个Java程序的最普遍做法。执行结果如你所料。在2中,你可能会想,为什么要这样才能输出。好,我们来分解一下这条语句。(如果没有安装Java文档,请到Sun的官方网站浏览J2SE API)首先,System是位于java.lang包中的一个核心类,如果你查看它的定义,你会发现有这样一行:public static final PrintStream out;接着在进一步,点击PrintStream这个超链接,在METHOD页面,你会看到大量定义的方法,查找println,会有这样一行: 

public void println(String x)。 

好了,现在你应该明白为什么我们要那样调用了,out是System的一个静态变量,所以可以直接使用,而out所属的类有一个println方法。 

静态方法 

通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法。如下所示: 

class Simple{ 
static void go(){ 
System.out.println("Go..."); 


public class Cal{ 
public static void main(String[] args){ 
Simple.go(); 



调用一个静态方法就是“类名.方法名”,静态方法的使用很简单如上所示。一般来说,静态方法常常为应用程序中的其它类提供一些实用工具所用,在Java的类库中大量的静态方法正是出于此目的而定义的。 

静态变量 

静态变量与静态方法类似。所有此类实例共享此静态变量,也就是说在类装载时,只分配一块存储空间,所有此类的对象都可以操控此块存储空间,当然对于final则另当别论了。看下面这段代码: 

class Value{ 
   static int c=0; 
   static void inc(){ 
      c++; 
    } 

class Count{ 
   public static void prt(String s){ 
      System.out.println(s); 

   public static void main(String[] args){ 
      Value v1,v2; 
      v1=new Value(); 
      v2=new Value(); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
      v1.inc(); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
    } 


结果如下: 

v1.c=0 v2.c=0 
v1.c=1 v2.c=1 

由此可以证明它们共享一块存储区。static变量有点类似于C中的全局变量的概念。值得探讨的是静态变量的初始化问题。我们修改上面的程序: 

class Value{ 
   static int c=0; 
   Value(){ 
    c=15; 

Value(int i){ 
   c=i; 

static void inc(){ 
   c++; 


class Count{ 
   public static void prt(String s){ 
      System.out.println(s); 

      Value v=new Value(10); 
      static Value v1,v2; 
    static{ 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
      v1=new Value(27); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
      v2=new Value(15); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 


public static void main(String[] args){ 
      Count ct=new Count(); 
      prt("ct.c="+ct.v.c); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
      v1.inc(); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
      prt("ct.c="+ct.v.c); 
    } 


运行结果如下: 

v1.c=0 v2.c=0 
v1.c=27 v2.c=27 
v1.c=15 v2.c=15 
ct.c=10 
v1.c=10 v2.c=10 
v1.c=11 v2.c=11 
ct.c=11 

这个程序展示了静态初始化的各种特性。如果你初次接触Java,结果可能令你吃惊。可能会对static后加大括号感到困惑。首先要告诉你的是,static定义的变量会优先于任何其它非static变量,不论其出现的顺序如何。正如在程序中所表现的,虽然v出现在v1和v2的前面,但是结果却是v1和v2的初始化在v的前面。在static{后面跟着一段代码,这是用来进行显式的静态变量初始化,这段代码只会初始化一次,且在类被第一次装载时。如果你能读懂并理解这段代码,会帮助你对static关键字的认识。在涉及到继承的时候,会先初始化父类的static变量,然后是子类的,依次类推。 

通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。如下代码所示: 

public class StaticCls{ 
   public static void main(String[] args){ 
       OuterCls.InnerCls oi=new OuterCls.InnerCls(); 
     } 

class OuterCls{ 
   public static class InnerCls{ 
       InnerCls(){ 
    System.out.println("InnerCls"); 
     } 
  } 


输出结果会如你所料: 

InnerCls 

#3


实例变量只有在创建实例的时候才会被创建,而静态成员是加载类的时候被创建。所以有了静态成员未必据有实例变量,即使有了实例变量,那么多实例,它哪知道访问哪个实例变量

#4


还是不明白~

#5


你能明白什么是类变量,什么是成员变量吗?

#6


在static里(不管是域还是方法)都只能访问static成员,可以看一下类加载过程

#7


你能明白什么是类变量,什么是成员变量吗?

如果你能理解它们的区别,你就能搞懂你那问题了。

之所以称类变量和方法,因为他们属于类,他们可以不实例化,直接调用;

称成员变量和方法,那是因为他们属于成员,也就是要实例化。

你没实例化就调用成员变量和方法,就会出问题的。你调用类方法的时候,类方法间调用了成员变量(没实例化吧),那该报错吧?

#8


要理解三个区域:方法区 栈 堆

类的方法信息和类的static变量放在 方法区 
对象的实例变量以及对方法地址的引用放在 堆
方法执行时局部变量及对象的引用地址压入 栈

为什么类成员方法只能访问类成员变量,而不能访问实例成员变量? static方法的执行不依赖对象,因此跟堆区没有联系,自然不能调用位于堆区的实例变量。

如果想深入理解 建议读下 《深入JAVA虚拟机》中类与对象生命周期几章
孙卫琴的JAVA基础的书也参考这本书讲了点

 

#9


找本基础点的教程看看 你会明白很多

#10


谢谢babybabyface,我就是想知道他们在内存中的关系。

也谢谢楼上的其他朋友

#11


该回复于2015-05-26 09:53:10被管理员删除

#12


该回复于2015-05-26 09:52:31被管理员删除

#13


类成员变量和类方法一般指的是类中的静态方法或静态变量,或者是静态内部类。静态成员是在java虚拟机加载类时,初始化的。可以全局通过类名访问,试想一下当你掉用了一个类的静态方法时,而这个方法用到了类的实例成员,而这个类的实例你还没有new出来,岂不是不安全了,所以编译器在编译的时候会检查你是否在静态成员里用到了实例成员,如果有责编译通不过的。

#1


 内部类的存在是基于外部类的实例存在的,内部类就好像是跟这个外部类的成员变量或方法一样存在   
  他的存在是为了extends一些类或实现某些接口   
  试想一个成员方法怎么可以访问到人家的变量,   
  她能访问的就是类的成员和方法,如果真的要访问到就要通过间接访问(通过该局部变量的方法或其它来访问)

  内部类在编译后都会产生一个新的Class文件的.   
    
  匿名类在概念上与命名内类一样,即完全在另一个类的界限内定义的类.只是在句法上与命名的内部类不同

#2


   public class Hello{ 
public static void main(String[] args){ //(1) 
System.out.println("Hello,world!"); //(2) 



看过这段程序,对于大多数学过Java 的从来说,都不陌生。即使没有学过Java,而学过其它的高级语言,例如C,那你也应该能看懂这段代码的意思。它只是简单的输出“Hello,world”,一点别的用处都没有,然而,它却展示了static关键字的主要用法。 

在1处,我们定义了一个静态的方法名为main,这就意味着告诉Java编译器,我这个方法不需要创建一个此类的对象即可使用。你还得你是怎么运行这个程序吗?一般,我们都是在命令行下,打入如下的命令(加下划线为手动输入): 

javac Hello.java 
java Hello 
Hello,world! 

这就是你运行的过程,第一行用来编译Hello.java这个文件,执行完后,如果你查看当前,会发现多了一个Hello.class文件,那就是第一行产生的Java二进制字节码。第二行就是执行一个Java程序的最普遍做法。执行结果如你所料。在2中,你可能会想,为什么要这样才能输出。好,我们来分解一下这条语句。(如果没有安装Java文档,请到Sun的官方网站浏览J2SE API)首先,System是位于java.lang包中的一个核心类,如果你查看它的定义,你会发现有这样一行:public static final PrintStream out;接着在进一步,点击PrintStream这个超链接,在METHOD页面,你会看到大量定义的方法,查找println,会有这样一行: 

public void println(String x)。 

好了,现在你应该明白为什么我们要那样调用了,out是System的一个静态变量,所以可以直接使用,而out所属的类有一个println方法。 

静态方法 

通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法。如下所示: 

class Simple{ 
static void go(){ 
System.out.println("Go..."); 


public class Cal{ 
public static void main(String[] args){ 
Simple.go(); 



调用一个静态方法就是“类名.方法名”,静态方法的使用很简单如上所示。一般来说,静态方法常常为应用程序中的其它类提供一些实用工具所用,在Java的类库中大量的静态方法正是出于此目的而定义的。 

静态变量 

静态变量与静态方法类似。所有此类实例共享此静态变量,也就是说在类装载时,只分配一块存储空间,所有此类的对象都可以操控此块存储空间,当然对于final则另当别论了。看下面这段代码: 

class Value{ 
   static int c=0; 
   static void inc(){ 
      c++; 
    } 

class Count{ 
   public static void prt(String s){ 
      System.out.println(s); 

   public static void main(String[] args){ 
      Value v1,v2; 
      v1=new Value(); 
      v2=new Value(); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
      v1.inc(); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
    } 


结果如下: 

v1.c=0 v2.c=0 
v1.c=1 v2.c=1 

由此可以证明它们共享一块存储区。static变量有点类似于C中的全局变量的概念。值得探讨的是静态变量的初始化问题。我们修改上面的程序: 

class Value{ 
   static int c=0; 
   Value(){ 
    c=15; 

Value(int i){ 
   c=i; 

static void inc(){ 
   c++; 


class Count{ 
   public static void prt(String s){ 
      System.out.println(s); 

      Value v=new Value(10); 
      static Value v1,v2; 
    static{ 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
      v1=new Value(27); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
      v2=new Value(15); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 


public static void main(String[] args){ 
      Count ct=new Count(); 
      prt("ct.c="+ct.v.c); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
      v1.inc(); 
      prt("v1.c="+v1.c+" v2.c="+v2.c); 
      prt("ct.c="+ct.v.c); 
    } 


运行结果如下: 

v1.c=0 v2.c=0 
v1.c=27 v2.c=27 
v1.c=15 v2.c=15 
ct.c=10 
v1.c=10 v2.c=10 
v1.c=11 v2.c=11 
ct.c=11 

这个程序展示了静态初始化的各种特性。如果你初次接触Java,结果可能令你吃惊。可能会对static后加大括号感到困惑。首先要告诉你的是,static定义的变量会优先于任何其它非static变量,不论其出现的顺序如何。正如在程序中所表现的,虽然v出现在v1和v2的前面,但是结果却是v1和v2的初始化在v的前面。在static{后面跟着一段代码,这是用来进行显式的静态变量初始化,这段代码只会初始化一次,且在类被第一次装载时。如果你能读懂并理解这段代码,会帮助你对static关键字的认识。在涉及到继承的时候,会先初始化父类的static变量,然后是子类的,依次类推。 

通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。如下代码所示: 

public class StaticCls{ 
   public static void main(String[] args){ 
       OuterCls.InnerCls oi=new OuterCls.InnerCls(); 
     } 

class OuterCls{ 
   public static class InnerCls{ 
       InnerCls(){ 
    System.out.println("InnerCls"); 
     } 
  } 


输出结果会如你所料: 

InnerCls 

#3


实例变量只有在创建实例的时候才会被创建,而静态成员是加载类的时候被创建。所以有了静态成员未必据有实例变量,即使有了实例变量,那么多实例,它哪知道访问哪个实例变量

#4


还是不明白~

#5


你能明白什么是类变量,什么是成员变量吗?

#6


在static里(不管是域还是方法)都只能访问static成员,可以看一下类加载过程

#7


你能明白什么是类变量,什么是成员变量吗?

如果你能理解它们的区别,你就能搞懂你那问题了。

之所以称类变量和方法,因为他们属于类,他们可以不实例化,直接调用;

称成员变量和方法,那是因为他们属于成员,也就是要实例化。

你没实例化就调用成员变量和方法,就会出问题的。你调用类方法的时候,类方法间调用了成员变量(没实例化吧),那该报错吧?

#8


要理解三个区域:方法区 栈 堆

类的方法信息和类的static变量放在 方法区 
对象的实例变量以及对方法地址的引用放在 堆
方法执行时局部变量及对象的引用地址压入 栈

为什么类成员方法只能访问类成员变量,而不能访问实例成员变量? static方法的执行不依赖对象,因此跟堆区没有联系,自然不能调用位于堆区的实例变量。

如果想深入理解 建议读下 《深入JAVA虚拟机》中类与对象生命周期几章
孙卫琴的JAVA基础的书也参考这本书讲了点

 

#9


找本基础点的教程看看 你会明白很多

#10


谢谢babybabyface,我就是想知道他们在内存中的关系。

也谢谢楼上的其他朋友

#11


该回复于2015-05-26 09:53:10被管理员删除

#12


该回复于2015-05-26 09:52:31被管理员删除

#13


类成员变量和类方法一般指的是类中的静态方法或静态变量,或者是静态内部类。静态成员是在java虚拟机加载类时,初始化的。可以全局通过类名访问,试想一下当你掉用了一个类的静态方法时,而这个方法用到了类的实例成员,而这个类的实例你还没有new出来,岂不是不安全了,所以编译器在编译的时候会检查你是否在静态成员里用到了实例成员,如果有责编译通不过的。