黑马程序员技术交流社区

标题: 分析一下代码,静态方法是否可以间接访问非静态成员... [打印本页]

作者: Shimano    时间: 2014-4-11 13:14
标题: 分析一下代码,静态方法是否可以间接访问非静态成员...
static关键字可以用来修饰成员变量、方法以及代码块。用static修饰过的变量和方法称为静态成员。
静态成员附属于类本身,而不附属于类的实例对象。该成员在类创建好后便一直存在,其生命周期与所在类相同。

若一个类有多个实例对象,那么这些实例对象都会公用这些静态成员。
同时类在不创建实例对象的情况下,可以用类名访问静态成员。
在使用static关键字的时候,都知道:静态方法只能访问静态成员变量。

静态方法附属于类,非静态成员变量附属于类的实例对象,
因为先有类再有该类的实例对象,所以静态方法不能访问非静态成员变量。

我在书上看到“静态方法不能直接访问非静态的成员变量。”那么我在想意思就是可以间接访问。以下这段代码:
  1. public class Test
  2. {
  3.         int num = 20;
  4.         static int temp;
  5.        
  6.         public static int getTemp()
  7.         {
  8.                 return temp;
  9.         }
  10.        
  11.         public int getNum()
  12.         {
  13.                 return num;
  14.         }
  15.        
  16.         public static void main(String args[])
  17.         {
  18.                 Test d = new Test();
  19.                 temp = d.getNum();
  20.                 //temp = num;
  21.                 System.out.println(d.getTemp());//打印出:20
  22.         }
  23. }
复制代码

似乎通过temp = d.getNum();这个操作,让getTemp();这个静态方法,最终间接访问到了num这个非静态成员变量,这是怎么做到的?
另外如果我把temp = d.getNum();改为temp = num;编译时提示 “无法从静态上下文中引用非静态 变量 num”,这两者有什么区别?



作者: Monkey·D·Chas    时间: 2014-4-11 13:28
你主函数第一句不就是创建了test类的对象 。此对象可以访问所有的test的方法。
作者: H._张_♂    时间: 2014-4-11 13:30
第一种
  1. package com.itheima;

  2. public class Test1
  3. {
  4.         int num = 20;//非静态成员变量,在类创建实例对象是加载
  5.         static int temp;//静态成员变量,和类一起加载,可以用类名调用
  6.         
  7.         public static int getTemp()
  8.         {
  9.                 return temp;
  10.         }
  11.         
  12.         public int getNum()
  13.         {
  14.                 return num;
  15.         }
  16.         
  17.         public static void main(String args[])
  18.         {
  19.                 Test1 d = new Test1();//创建实例对象,现在存在了num 值为20
  20.                 temp = d.getNum();//temp一直都存在,这里只是给他赋值
  21.                 //temp = num;
  22.                 System.out.println(temp);//打印出:20,这里可以不调用getTemp
  23.         }
  24. }
复制代码

第二种
package com.itheima;

public class Test1
{
        int num = 20;//非静态成员变量,在类创建实例对象是加载
        static int temp;//静态成员变量,和类一起加载,可以用类名调用
        
        public static int getTemp()
        {
                return temp;
        }
        
        public int getNum()
        {
                return num;
        }
        
        public static void main(String args[])
        {
                Test1 d = new Test1();//创建实例对象,现在存在了num 值为20
                temp = num;//错误,因为这里的num是静态代码块中的成员,意思就是在类加载就必须有这个num,
                                //但是你前面的num是非静态,这里的num初始化还没有,非静态成员必须用对象调用
                System.out.println(temp);//打印出:20
        }
}
作者: ò壞尛孩    时间: 2014-4-11 13:55
因为静态方法在类加载的时候就初始化了,而非静态的成员变量不一定已初始化,而且即便是初始化了,静态方法也不知道该访问哪个实例的变量。
你把temp=num肯定是不行,num是非静态成员,必须要由类对象访问才行,temp在类对象声明时就被加载,而num并没有初始化。我总结了两句话:(仅供参考)
1、非静态方法可以在方法内任意访问静态成员方法或者静态成员变量。
2、静态方法中不可以访问非静态成员变量和非静态成员方法,也就是this和super关键字为什么在静态中无法使用的原因。
Test d = new Test();
temp = d.getNum();
这是通过类的对象赋值给静态成员变量,这在main里面肯定是可以的。
我帮你改了下代码,可以解释你的问题:
class Test
{
        int num ;
        static int temp=40;

        Test(int num)
        {
                this.num=num;
        }
       
        public static int getTemp()//静态方法访问静态变量
        {
                        return temp;
        }
       
        public int getNumSum()//非静态方法可以访问非静态成员变量和静态变量
        {
                        return this.num+temp;
        }
}

public class StaticDemo
{
        public static void main(String args[])
        {
                        Test d = new Test(20);
                        //temp = num;
                        System.out.println(d.getTemp());
                        System.out.println(d.getNumSum());//打印出:20
        }
}

作者: 491138002    时间: 2014-4-11 14:16
static的成员 是在类加载的时候初始化的 ,jvm的ClassLoader加载,首次主动使用加载
而非static的成员是在创建对象的时候,即 new操作的时候才初始化的

先后顺序是,先加载 后初始化,那么加载的时候初始化static的成员,此时非static还没有初始化,必然不能使用,而非static的成员是在类加载之后 ,通过new操作符创建对象的时候初始化的,此时static已经初始化 ,即已经分配内存空间,就可以访问
作者: Shimano    时间: 2014-4-11 15:12
Monkey·D·Chas 发表于 2014-4-11 13:28
你主函数第一句不就是创建了test类的对象 。此对象可以访问所有的test的方法。 ...

我问的问题是:getTemp();这个静态方法最终还是访问到了,num这个非静态数据!
是如何通过temp = getNum();这个赋值语句做到的?为什么temp = num;这样赋值不行?
作者: Shimano    时间: 2014-4-11 15:40
H._张_♂ 发表于 2014-4-11 13:30
第一种
第二种
package com.itheima;

我明白你的意思了!也就是说,temp = getNum();这句,相当于temp = 20;把20赋给temp,
System.out.println(temp);//打印出:20,这里可以不调用getTemp

最终getTemp();这个静态方法只是返回了20这个数,与num这个非静态成员变量无关,所以最终静态方法还是没能访问到非静态成员。

我还是不太明白,当Demo d = new Demo();创建对象后,num也就被初始化了,并且num = 20;此时,temp这个static静态变量早在类加载的时候出现,当num = 20; temp这个静态变量在内存中都同时存在的时候,为什么不能有temp = num;这个操作?
作者: H._张_♂    时间: 2014-4-11 15:57
Shimano 发表于 2014-4-11 15:40
我明白你的意思了!也就是说,temp = getNum();这句,相当于temp = 20;把20赋给temp,
System.out.println ...

记住最重要的一点就行了,非静态成员必须使用对象调用哦。好好理解他,其实这个num是属于新new出来的对象的,你要使用他,首先必须找到拥有这个成员的对象,使用对象调用他,其实关键不是你有没有定义getNum方法。这个方法一般是在num是私有的时候才需要,如果不是私有,你直接使用   temp=d.num就可以了




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2