Java开发之道
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

陷阱5 无风起浪——初始化静态成员的陷阱

1.陷阱产生的场景

静态成员在应用程序开发中经常使用,在成员变量的类型或者方法返回值类型的前面加上关键字static,就能将该成员定义为静态成员,静态成员属于类而不属于实例。静态成员的应用范围很广泛,比如,可在应用程序的全局内获取或设置公共的静态成员的值,这非常类似于C++的全局变量,但如果应用不当,会给应用程序带来很多麻烦。

例3.5 初始化静态成员时产生的陷阱。(光盘位置:光盘\MR\Instance\3\05\InitStaticMember)

在本实例中定义一个名为Test 的类,该类要实现的功能是这样的,当使用无参的构造器实例化该类时,调用该类的getName ()方法获取类内私有字段的默认值,当使用有参的构造器实例化该类时,调用该类的getName ()方法获取构造器传入的参数值,具体代码如下:

    private static String strStaticName = "明日";
    //无参构造器
    public Test ()
    {
 
    }
    //有参构造器
    public Test (String strName)
    {
      strStaticName = strName;
    }
    //自定义方法,用于返回字段strStaticName的值
    public String getName ()
    {
      return strStaticName;
    }

注意

上面代码中的strStaticName字段是静态的。

本实例创建的是一个控制台应用程序,在main ()方法中创建了两个Test 类的实例,一个使用无参构造器实例化,另一个使用有参构造器实例化,具体代码如下:

    public static void main (String[] args)
    {
      //创建实例t1
      System.out. println ("创建t1实例时,名称设置为东方");
      Test t1 = new Test ("东方");
      System.out. println ("所以使用GetName方法获取的名称为:"+t1. getName ());
      System.out. println ("");
      //创建实例t2
      System.out. println ("创建t2实例时,名称未设置");
      Test t2 = new Test ();
      String strName = t2. getName ();
      System.out. println ("但通过GetName方法获取的名称却为:"+strName);
    }

按照最初的设计思路,程序的运行结果应该是这样,t1实例调用getName ()方法的返回值应该为“东方”, t2实例调用getName ()方法的返回值应该为默认的值“明日”,但结果却完全出乎意料,运行结果如图3.3所示。

图3.3 运行结果

说明

由于静态成员变量strStaticName 在类的两次实例化过程中,只被初始化一次,也就是说,第二次实例化Test类时,静态成员变量strStaticName仍然保留第一次实例化Test类时的值,这就是问题的所在,所以在设计程序时,不要乱用静态成员,否则会适得其反。

注意

在一个应用程序中,无论创建了一个类的多少个实例,该类的静态字段都只被初始化一次。

2.陷阱的解决方法

本实例产生的陷阱,并不是什么系统错误或程序异常,而是对静态概念认识不够所造成的,相信很多有经验的程序员也犯过类似的错误.。本实例的解决办法很多,这里列出以下三种比较简单的解决方法。

· 取消静态关键字static。

· 当创建Test类对象时,都使用有参的构造器。

· 在无参构造器内,给静态字段strStaticName赋值,可以使用如下代码:

    public Test ()
    {
      strStaticName = "明日";
    }

技巧

在程序中,由于静态成员被类的所有实例所共享,因此可以将静态成员变量作为全局变量使用。