Java中的static(1)【持续更新】——关于Eclipse的No enclosing instance of type ... 错误的理解和改正
本文链接地址:https://www.cnblogs.com/oberon-zjt0806/p/11632528.html
No enclosing instance of type
SomeClass
is accessible. Must qualify the allocation with an enclosing instance of typeSomeClass
(e.g.x.new A()
wherex
is an instance ofSomeClass
).
这是怎么发现的??
拿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
的内类。
然后错误就发生了……
为什么会这样呢??
如果已经了解了静态的内容,请自行跳转至“静态成员说完了,那跟这你遇到的这个问题有什么关系呢??”子节
好吧,其实说到底都是main
的static
修饰惹的祸。
我们知道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
是“个性”的,这个结果当然也就可能彼此不同。
而Rise
和Reduce
这两个函数,它们要修改的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
的,那么也就意味着这不是一种“个性”的行为,而是“共性”的行为,这也就是说:
这种行为并不能由某一个体单独执行,必须赌上全种族的命运,以种族的名义,去吧!!!
所以,如果不希望金价被某一个金块干扰的话,Rise
和Reduce
也得是static
的:
public static void Rise(float price) //提升黄金单价,增加price元
{
xau += price;
}
public static void Reduce(float price) // 降低黄金单价,减少price元
{
xau -= price;
}
这样一来,Rise
和Reduce
就必须以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
全体的oz
,每个金子都有自己的oz
,所以这个时候调用Gold.GetPrice()
,程序自己也不知道该返回谁的oz
,所以这样是不可以的。
静态成员说完了,那跟这你遇到的这个问题有什么关系呢??
拿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
的内类。
然后错误就发生了……
请注意画线部分!!!
Java里面main
函数强制具备这些修饰:public static void
,也就是说main
理所应当的是个静态成员。
但是,请注意,main
里面试图引入了MainJWindowListener
这个内类并试图调用构造函数进行构造,可是,MainJWindowListener
只是个缺省访问级别的普通动态内类,这就是问题所在了。
那该怎么解决呢??
这里基于使用了Swing这个事实,解决方案有两种,其中一种是推荐的,而另外一种是通用的。
推荐的方法是用于根治在Swing下发生这种问题的一种重构代码的思路,这种方法规避了在静态成员中进行动态内类(这里面动态内类主要指事件侦听器)的引用。
通用的方法是针对我们遇到的这个问题,通过修改代码使得静态成员能够调用动态内类,这里时刻注意一点,内类因为不是静态的,这意味着内类的构造必须在一个外部类(一个非静态类)实例的范畴下进行。
推荐的方法
考虑到我这里的情景,我是要给窗口注册一下窗口关闭的动作,也就是为关闭按钮添加事件侦听器。
但是实际情况是,基本上只要是这个MainJFrame
窗口,我都希望它注册这个关闭按钮的事件侦听器。所以这个过程完全可以不在主函数里进行。
而一个非静态类,无论长成什么样子,其构造函数永远也不会是static
的,所以事件侦听的注册完全可以放到构造函数里去做:
public MainJFrame(String caption)
{
super(caption);
//....Some initial actions...//
this.addWindowListener(new MainJWindowListener());
}
然后main
函数只需要负责构造之就可以了:
public static void main(String args[])
{
//..Others..//
MainJFrame frmBase = new MainJFrame();
//..Others..//
}
这是个非常一劳永逸且合乎逻辑的做法,因为就算有多个MainJFrame
,我们一般都会希望对用户行为的反馈是一致的,也就是说实际上所有的MainJFrame
都会被配备相同的事件侦听器,既然如此的话放到构造函数统一随着构造的时候执行是再好不过的了。
通用的方法
推荐的方法里面规避了在静态成员中调用这个内部类,转到一个非静态成员中进行,而且事实上证明“效果拔群”。
但是说到底“效果拔群”也只是对这类情形“拔群”,假使我们非要这么做,比如说我非要在多个MainJFrame
做不同的事件侦听处理,那就不应该写在构造函数当中,因为这不是统一的构造流程,没法写进一个函数里。
也就是说,我们非得要在main
函数里做侦听绑定,因为main
函数强制具有static
性质,而MainJWindowListener
不是static
的所以像这样是不可以的:
public static void main(String args[])
{
MainJFrame frmBase = new MainJFrame("Hello Swing");
frmBase.setBackground(Color.white);
frmBase.setVisible(true);
// 不行!!!MainJWindowListener不是静态的!!!
frmBase.addWindowListener(new MainJWindowListener());
}
也就是说,MainJWindowListener
必须跟着一个MainJFrame
的实例里面才可以构造,那么我们非要找一个MainJFrame
实例mjfinstance
不可,然后再new mjfinstance.MainJWindowListener()
……
……巧了,这不是有么??frmBase
不就是一个MainJFrame
么??所以把这一句改成:
frmBase.addWindowListener(new frmBase.MainJWindowListener());
就可以了。
Java中的static(1)【持续更新】——关于Eclipse的No enclosing instance of type ... 错误的理解和改正的更多相关文章
- java中的static关键字详解
static对于我们这些初学者在编写代码和阅读代码是一个难以理解的关键字,也是大量公司面试题最喜欢考的之一.下面我就来就先讲述一下static关键字的用法和我们初学者容易误解的地方. static关键 ...
- 深入理解Java虚拟机--个人总结(持续更新)
深入理解Java虚拟机--个人总结(持续更新) 每天按照书本学一点,会把自己的总结思考写下来,形成输出,持续更新,立帖为证 -- 2020年7月7日 开始第一次学习 -- 2020年7月8日 今天在百 ...
- (转)Java中的static关键字解析
转载: http://www.cnblogs.com/dolphin0520/p/3799052.html 一.static关键字的用途 在<Java编程思想>P86页有这样一段话: &q ...
- 关于Java中的static关键字
Java中的 static 关键字,确实是一个关键的字(key word),今天就来总结一下它的用法,说说为什么关键. Java中的 static 关键字主要是用来做内存管理的.理解了这句话才能够比较 ...
- Java中的static关键字解析
Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键 ...
- java中的static使用--静态变量、静态方法
Java 中的 static 使用之静态变量 大家都知道,我们可以基于一个类创建多个该类的对象,每个对象都拥有自己的成员,互相独立.然而在某些时候,我们更希望该类所有的对象共享同一个成员.此时就是 s ...
- (转)Java中的static关键字解析
转自http://www.cnblogs.com/dolphin0520/p/3799052.html 一.static关键字的用途 在<Java编程思想>P86页有这样一段话: “sta ...
- Java中的static的使用
Java中的static使用之静态变量 神话丿小王子的博客主页 1.Java 中被static修饰的成员称为静态成员或类成员.它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享.且优先于对象 ...
- java中的static详解
如果一个类成员被声明为static,它就能够在类的任何对象创建之前被访问,而不必引用任何对象.static 成员的最常见的例子是main( ) .因为在程序开始执行时必须调用main() ,所以它被声 ...
随机推荐
- (五十八)c#Winform自定义控件-管道阀门(工业)
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- 1014 装箱问题 CODE[VS]
1014 装箱问题 2001年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Descripti ...
- codeforces 805 E. Ice cream coloring(dfs)
题目链接:http://codeforces.com/contest/805/problem/E 题意:你有n个节点,这个n个节点构成一棵树.每个节点拥有有si个类型的ice,同一个节点的ice互相连 ...
- 2019icpc南昌网络赛_I_Yukino With Subinterval
题意 给定一个序列,两种操作,单点修改,询问区间\([l,r]\)值域在\([x,y]\)范围内的连续段个数. 分析 原数组为\(a\),构造一个新的数组\(b\),\(b[i]=(a[i]==a[i ...
- MyCat数据库的基础配置及使用
一.为什么需要分布式数据据库 随着计算机和信息技术的迅猛发展,行业应用系统的规模迅速扩大,行业应用所产生的数据量呈爆炸式增长,动辄达到数百TB甚至数百PB的规模,已远远超出传统计算技术和信息系统的处理 ...
- Netty源码分析 (六)----- 客户端连接接入accept过程
通读本文,你会了解到1.netty如何接受新的请求2.netty如何给新请求分配reactor线程3.netty如何给每个新连接增加ChannelHandler netty中的reactor线程 ne ...
- 2018阿里-研发工程师JAVA Software Engineer, Java
岗位描述Job Description如果你想了解JAVA开发在阿里巴巴互联网生态系统中无与伦比的应用广度与深度: 如果你对基础技术感兴趣,你可以参与基础软件的设计.开发和维护,如分布式文件系统.缓存 ...
- Android四大组件初识之Service
Service作为Android四大组件之一,可以与Activity建立双向连接(绑定模式),提供数据和功能.也能够接收Intent单方面请求(调用模式),进行数据处理和调度功能. Service与A ...
- Net基础篇_学习笔记_第十一天_面向对象(析构函数)
析构函数与构造函数 析构函数: ~Student() { Console.WriteLine("我是析构函数"); } 析构函数,当程序结束的时候,析构函数才执行. 帮助我们释放资 ...
- Java 最常见 200+ 面试题答案全解析-面试必备
本文分为十九个模块,分别是: Java 基础.容器.多线程.反射.对象拷贝.Java Web .异常.网络.设计模式.Spring/Spring MVC.Spring Boot/Spring Clou ...