前言:最近在学多线程,写“哲学家就餐问题(Dining Philosophers)”的时候,需要定义一个全局的变量,即哲学家的人数。常用的做法是在其中一个类中定义一个static final的变量,然后让其他类通过类名访问他。在这里,想使用之前实训项目的第一版应用层协议的设计想法,即使用一个接口类来定义所有子类都会使用到的变量。然后,就引出了一个interface成员变量和static final的问题。
(一)一个简单的问题
首先,看一段代码:
//Variable.java
public interface Variable {
public int NUM_PHILOSOPHERS = 5;
} //DiningPhilosophers.java
public class DiningPhilosophers implements Variable{
public static void main(String[] args) {
Lock[] chopsticks = new ReentrantLock[NUM_PHILOSOPHERS];
System.out.println(chopsticks.length);
}
}
上述代码中,DiningPhilosophers类的static方法直接使用接口中的public int变量,是否会出错?
(二)解析
可能会有人第一反应是不可以,因为静态方法不能直接使用类的非静态成员变量。我的一部分朋友也是这么想的(好吧,不排除我的误导)。
实际上,上面的程序并没有问题。
(1)首先,静态方法的确不能直接使用类的非静态成员变量。我曾经写过一篇类似的博文《再学Java 之 解决No enclosing of type * is accessable》大家可以参考一下。
(2)其次,所有的interface成员变量都必须是public static final 的(原因后面会解释),所以我们在写代码的时候可以省略一部分修饰符,所以上面的NUM_PHILOSOPHERS就算声明语句为 int NUM_PHILOSOPHERS=5;它依然是一个public static final变量(所以,这也解释了,如果我们不对其赋初始值,为什么会报错)。我们可以使用javap工具查看Variable类的编译信息:
(3)最后解释一下为什么interface的成员变量必须是public static final的。
我在Google上搜到了一篇比较不错的文章《Why do we have only public static final variables in interfaces?》,下面大概翻译一下(有改动):
接口定义了行为的协议,而不是行为如何执行实现。实现接口的类支持该接口中定义的行为协议。
接口中声明的所有字段都是public static final的。为什么?
- 如果一个变量没有被定义为final,任何类的实现都可以改变变量的值。同时他就会变成类的实现的一部分,而接口是一个不带任何实现的纯粹的规范;
- 如果变量是静态的,那么这个变量就是属于接口的,而不是属于实例对象或者运行时的对象的。(注:由于接口不能被实例化,所以,定义为非静态,其实也没有意义。);
- 接口定义了调用者如何跟接口的实现类的实例对象交互,所以如果成员不是public,那么调用者没办法去方法它;
接口的每一个字段的声明都必须是pubic static final 的,它允许我们在声明时指定所有或者部分修饰符。同时,任何字段的声明必须有一个初始化表达式,它可以不用一定是一个常量表达式,它的计算和赋值只会进行一次,然后这个接口字段就被初始化了(注:这是一个很有趣的特性,有兴趣可以一起聊聊:-))。
再学Java 之 interface的成员变量的更多相关文章
-
JAVA中局部变量 和 成员变量有哪些区别
JAVA中局部变量 和 成员变量有哪些区别 1.定义的位置不一样<重点>***局部变量:在方法的内部成员变量:在方法的外部,直接写在类当中 2.作用范围不一样<重点>***局部 ...
-
假如java类里的成员变量是自身的对象
假如java类里的成员变量是自身的对象,则新建该类对象时内存中怎么分配空间,我感觉似乎死循环了. 不过我想的肯定是错的,因为很多类的成员变量是自身对象,并且绝对无错,举个例子: Class A{ pr ...
-
Java接口中的成员变量默认为(public、static、final)、方法为(public、abstract)
interface”(接口)可将其想象为一个“纯”抽象类.它允许创建者规定一个类的基本形式:方法名.自变量列表以及返回类型,但不实现方法主体.接口也可包含基本数据类型的数据成员,但它们都默认为publ ...
-
C#的HttpModule中及Java的Servlet中成员变量乱用导致的不易重现的BUG
3年前写的在HttpModule中记录访问日志的代码,在最近使用日志数据分析登录账号的IP情况时,才发现了一个不易重现的BUG——日志中记录的登录账号出现串掉的情况.之所以这个时候才发现该问题,是因为 ...
-
java类里的成员变量是自身的对象问题
今晚看单例模式饿汉时想到一个问题:假如java类里的成员变量是自身的对象,则新建该类对象时内存中怎么分配空间,我感觉似乎死循环了.于是上网搜索了下,哈哈,果然有人早就思考过这个问题了,站在巨人的肩膀上 ...
-
《java中局部变量和成员变量的区别》
class Car { String color; int number; void run() { System.out.println(color+"::"+number); ...
-
java子类对象和成员变量的隐写&;方法重写
1.子类继承的方法只能操作子类继承和隐藏的成员变量名字类新定义的方法可以操作子类继承和子类新生命的成员变量,但是无法操作子类隐藏的成员变量(需要适用super关键字操作子类隐藏的成员变量.) publ ...
-
测试 Java 类的非公有成员变量和方法
引言 对于软件开发人员来说,单元测试是一项必不可少的工作.它既可以验证程序的有效性,又可以在程序出现 BUG 的时候,帮助开发人员快速的定位问题所在.但是,在写单元测试的过程中,开发人员经常要访问类的 ...
-
Java接口中的成员变量的意义
转自:http://blog.csdn.net/ameyume/article/details/6189749 在interface里面的变量都是public static final 的.所以你可以 ...
随机推荐
-
知识积累:CA详解
所有证书有多种文件编码格式,主要包括: CER编码(规范编码格式):是BER(基本编码格式)的一个变种,比BER规定得更严格DER编码(卓越编码格式):是BER(基本编码格式)的一个变种, 比BER ...
-
StartFP
1.INODS执行完成时间为13:06:04分, 从日志信息无法知道STARTFP执行到哪一步 从INODS执行完成时间可知道startFp执行时间为13:06:05分开始, 执行StartFP中的e ...
-
js中的console很强大
今天闲来没事,瞎逛, 发现了淘宝首页的这个: 想起来之前在百度的 页面中也曾看到过.于是乎自己试一试. 于是便见识到了console对象其实很强大,用好它对调试真的有很大帮助. 代码: <!DO ...
-
hdu1251在词典里统计前缀出现的个数
banana band bee absolute acm ba b band abc #include<iostream> using namespace std; //数据结构 s ...
-
SQL 相关
SET STATISTICS TIME ON 记录查询的相关数据 生成随机Guid SELECT NewID() 按照某一列排序并生成序号 select Row_Number() OVER (ORDE ...
-
我们都遇到过的 Replace Blank Space
题目描述: 请实现一个函数,将一个字符串中的空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 分析: 看到这个题目,我们都会有 ...
-
通过spring.net中的spring.caching CacheResult实现memcached缓存
通过spring.net中的spring.caching CacheResult实现memcached缓存1.SpringMemcachedCache.cs2.APP.config3.Program. ...
-
【django】request
request.GET request.POST
-
java basic
//java 声明常量 //final 数据类型 常量名=值; //as: final float PI=3.14f;/ PI=3.14002F //默认浮点为 double //break:跳出多重 ...
-
linux export将PATH环境变量误删了的解决办法
今天新增环境变量的时候不小心把冒号错打成了分号 export PATH=/usr/local/php5/bin;$PATH; 导致PATH变量为/usr/local/php/bin 解决办法:[ubu ...