Java中的static(1)【持续更新】——关于Eclipse的No enclosing instance of type … 错误的理解和改正

  • 2019 年 10 月 7 日
  • 筆記

No enclosing instance of type SomeClass is accessible. Must qualify the allocation with an enclosing instance of type SomeClass (e.g. x.new A() where x is an instance of SomeClass).

这是怎么发现的??

拿Eclipse编写Java的AWT/Swing程序时,编写了一个public class MainFrame extends JFrame然后在其中放入一个主函数写入了如下内容:

public static void main(String args[])  {      MainJFrame frmBase = new MainJFrame("Hello Swing");      frmBase.setBackground(Color.white);      frmBase.setVisible(true);      frmBase.addWindowListener(new MainJWindowListener());    // <--- Error occured here !!!  }

也就是我在主函数创建了窗口之后想要继续在主函数里为frmBase这个JFrame窗口添加窗口监听器(class MainJWindowListener implements WindowListener),其中MainJWindowListener作为MainFrame内类
然后错误就发生了……

为什么会这样呢??

好吧,其实说到底都是mainstatic修饰惹的祸。
我们知道static的成员也好,类也好,所谓的“静态”其实说的都是“为整个程序所共享”的意思,说的直白一点,static的东西都非常的“大公无私”
当然,其实我写C#写的比较多,对Java的规则还不是很了解,似乎Java并不像C#那样允许public static class SomeClass,所以对于Java而言更多的是针对静态成员讨论的。

作为一个大公无私的内容,static的成员里面除了自己再构造一些临时对象以外,直接援引的类、函数都不能为某一对象所特有的。

不能为某一对象所特有??但是既然是定义到类里的属性,那类的所有对象不是都有这个属性么??

不,这里说的“特有”并不是这个意思,或许我换个词语会更好一些——对象“个性”的属性。

个性化……但这是什……

打住,我知道你要问这件事,所以我这里举个糖炒栗子:
比如说类Gold被定义为:

public class Gold  {      // Properties      private static float xau = 1504.35f;  // 金单价,也就是每盎司黄金在国际市场的价格,我随便编的数请别在意……      private float oz;    // 该黄金实例(理解成金块金锭金碎末金戒指金项链都可以)的质量(盎司数)        // Constructor      public Gold(float oz)      {          this.oz = oz;      }      // Methods ...  }

我们看到金单价xau是静态的,因为无论那个金子多沉,长成什么样子,金单价对所有金子都是一样的,而且当xau变动的时候,所有Gold的价格也都会随着xau变动。所以这种属性就不具备“个性”,因为你用我用大家一起用,也就是说,这是全体的“共性”。

而重量oz就不一样了,一座金山(Kingsoft)可能有1e+xxx的oz,而一个金粒可能只有1e-xxx的oz,我可能用一个new Gold(1e+500)表示我构建了一个黄金星球,我也可能用new Gold(1e-500)表示我构造了一个金分子之类的。
但总之,他们都是Gold,他们都有oz,可是每个人的oz都不一样,这就是个性

你有Freestyle嘛

我们接下来再看看它的方法想定义些什么(但我现在暂时不定义):

public class Gold  {      // Properties ...        // Constructor ...        // Methods      // GetPrice() 能够获得该金块的具体价格,按金单价*盎司数计算      // Rise(float price) 提升黄金单价,增加price元      // Reduce(float price) 降低黄金单价,减少price元      // ...  }

先看这些函数,很明显我们能看出一些规律:
GetPrice这种函数,它的结果是“个性”的,xau*oz当中oz是“个性”的,这个结果当然也就可能彼此不同。
RiseReduce这两个函数,它们要修改的xau是共性的,而且仅仅牵涉到“共性”,也就是说,它们是能够影响整个黄金国度每一个金子的命运的函数。

嗨,要是我嘛,全都定义成平常的就可以了吧

啊,确实可以,因为非静态的成员能够访问类内所有的其他成员,无所谓静态和非静态。
当然,对于GetPrice来说,这无所谓,而且其结果本身就是“个性”的:

public class Gold  {      // Properties ...        // Constructor ...        // Methods      public float GetPrice() // 能够获得该金块的具体价格,按金单价*盎司数计算      {          return xau*oz;      }      public void Rise(float price) //提升黄金单价,增加price元      {          xau += price;      }      public void Reduce(float price) // 降低黄金单价,减少price元      {          xau -= price;      }      // ...  }

这么写的话当然没有问题,不犯任何语法错误而且编译是通过的,而且你只要实例化一个金子你也确实能够正确地调用这些函数并得到正确的结果。
像这样:

public void main(String args[]) //主函数,在哪个类里就别管了  {      Gold gNugget = new Gold(0.01f);      System.out.println(String.format("%.2f", gNugget.GetPrice()));      gNugget.Rise(10.0f);      System.out.println(String.format("%.2f", gNugget.GetPrice()));      gNugget.Reduce(20.0f);      System.out.println(String.format("%.2f", gNugget.GetPrice()));  }

输出结果:

15.04  15.14  14.94

结果确实没问题

……当然你也可以弄好多个金子这么玩……

只不过……

gNugget.Rise()或者gMountain.Reduce()被调用的时候,所有金子(当然包含它们自身)都是受到影响的。
想像一下:

gNugget.Reduce(1000.0f);

结果一个小小的金粒导致了黄金市场遭受了惨重的金融危机,你不觉得这个小金粒的能耐忒大了点么??
当然,这也就同将Rise()/Reduce()改成public也差不多了。

好吧,是挺危险的,那我不希望这样,该怎么办呢

一个普通的,不是static的函数,意味着它是一种“个性”的行为,这也就是说:

这种行为谁都可以做,想来就来我行我秀u can u up

当然,如果一个函数被声明为static的,那么也就意味着这不是一种“个性”的行为,而是“共性”的行为,这也就是说:

这种行为并不能由某一个体单独执行,必须赌上全种族的命运,以种族的名义,去吧!!!

所以,如果不希望金价被某一个金块干扰的话,RiseReduce也得是static的:

    public static void Rise(float price) //提升黄金单价,增加price元      {          xau += price;      }      public static void Reduce(float price) // 降低黄金单价,减少price元      {          xau -= price;      }

这样一来,RiseReduce就必须以Gold.Rise()Gold.Reduce()调用,而不能让Gold的实例来调用,也就是说,这一举措会导致下面的语句出错:

gNugget.Rise(10.0f);  gNugget.Reduce(20.0f);

因为这两个函数是“共性”的,想涨价降价你一个小小的gNugget说了不算的,必须是以Gold全体的名义来说:Gold.Rise()

当然,共性行为也会有这样的约束,比如,共性的行为不允许引入个性的内容(书面上来说就是静态方法中不允许调用非静态的属性和方法和内部类),因为如果一个行为牵扯到个性的因素,那么它就不能以这个类全体的名义去做,比如我把GetPrice改成static的就会出错:

    public static float GetPrice() // 不行!!!!      {          return xau*oz;      }

因为这个时候调用Gold.GetPrice()的时候,并不存在属于Gold全体的oz,因为一个金子一个样。