再学Java 之 interface的成员变量

前言:最近在学多线程,写“哲学家就餐问题(Dining Philosophers)”的时候,需要定义一个全局的变量,即哲学家的人数。常用的做法是在其中一个类中定义一个static final的变量,然后让其他类通过类名访问他。在这里,想使用之前实训项目的第一版应用层协议的设计想法,即使用一个接口类来定义所有子类都会使用到的变量。然后,就引出了一个interface成员变量和static final的问题。

(一)一个简单的问题  

  首先,看一段代码:

 1  //Variable.java
 2  public interface Variable {
 3      public int NUM_PHILOSOPHERS = 5;
 4  }
 5
 6  //DiningPhilosophers.java
 7  public class DiningPhilosophers implements Variable{
 8      public static void main(String[] args) {
 9          Lock[] chopsticks = new ReentrantLock[NUM_PHILOSOPHERS];
10          System.out.println(chopsticks.length);
11      }
12  }

  上述代码中,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 的,它允许我们在声明时指定所有或者部分修饰符。同时,任何字段的声明必须有一个初始化表达式,它可以不用一定是一个常量表达式,它的计算和赋值只会进行一次,然后这个接口字段就被初始化了(注:这是一个很有趣的特性,有兴趣可以一起聊聊:-))。

  

时间: 2024-08-21 20:52:33

再学Java 之 interface的成员变量的相关文章

再学Java 之 private、protected、public和default的作用域

前言:如果提到protected的访问控制级别,您的第一反应是"只能是子类才可以访问",那么您很可能需要往下看. 首先,大致介绍一下各个访问控制符的访问控制级别(具体的介绍很多大牛的博文都有介绍,我就不细说了,可以点击这里查看),如下图:   private default protected public 同一个类中 √ √ √ √ 同一个包中   √ √ √ 子类中     √ √ 全局范围内       √ 在这里,很多人都存在一个误区,就是,认为protected修饰的方法只能

再学Java 之 foreach循环

从Java 5 之后,Java提供了一种新的循环:foreach循环,这种循环遍历数组和集合更加简洁. foreach循环语法格式如下: for ( type variableName : array | collection){ //variableName自动迭代访问每个元素 } 在很多书籍中,都能找到这么一句话"使用foreach循环迭代数组元素时,并不能改变数组元素".如: String books = {"a","b","c&

C#的HttpModule中及Java的Servlet中成员变量乱用导致的不易重现的BUG

3年前写的在HttpModule中记录访问日志的代码,在最近使用日志数据分析登录账号的IP情况时,才发现了一个不易重现的BUG——日志中记录的登录账号出现串掉的情况.之所以这个时候才发现该问题,是因为部分用户的IP是固定的,但是日志里却出现了别人的IP.而之所以3年后才发现,是因为这块日志数据一直没怎么用过.回头想想,根本原因还是在用成员变量的时候没考虑到多线程的情况,或者说多用户同时访问的情况.因为HttpModule里的事件,是所有页面实例共用的. 问题代码: string dateBegi

java之j2se:再学java对象容器

今天是开学第一天,按照上学期的讲课进度,本该是可以开始学习多线程了,但是由于换了老师,可能交接方面有点出入,又给我们讲授了一遍java对象容器,所以这也是为什么题目为"再学". 本文目录: 集合的主要用途 单值类集合:List类与Set类 键值对类集合:Map类 集合的主要用途:集合主要在查询数据返回的时候常用.比如要使用jsp做一个学生信息管理系统,需要从数据库中返回查询学生的结果,把这些结果放入一个集合里,再通过方法返回,在显示层(view)可以使用jsp标签来把他们显示出来. 单

再学Java 之 Integer 包装类缓存

前言:本博文将涉及的Java的自动装箱和自动拆箱,可以参考 这篇文章 和 官方教程 ,这里不再赘述. 首先,先看一个小程序: public class Main { public static void main(String[] args){ Integer i1 = new Integer(1); Integer i2 = new Integer(1); System.out.println(i1 == i2); Integer i3 = 1; Integer i4 = 1; System.

再学Java 之 形参个数可变函数

自Java 5后,Java允许定义形参个数可变的方法,从而允许运行过程中,为方法指定不确定个数的形参. 其定义方法的格式如下: void function_name ( type ... variables){ //对variables数组进行操作 } 在上面格式中,系统将输入的参数全部存储到variables数组中.也就是说,下面的定义方式,其实是相同的: void function_name ( type ... variables); void function_name ( type[]

什么是java的局部变量,成员变量,全局变量?

public class Test { private String name;//成员变量,也是全局变量 public void changeName() { String n = "tomoya";//n就是局部变量 name = n; }} 总的来说,定义在类里的,也就是name那个位置,就是成员变量,在JAVA里全局变量和成员变量是一个意思.定义在方法里或域里就叫做局部变量,所谓域就是{}里面,比如public void show() { int b = 2;//局部变量 if

Java接口里定义成员变量 说明

首先你要弄清接口的含义.接口就是提供一种统一的'协议',而接口中的属性也属于'协议'中的成员.它们是公共的,静态的,最终的常量.相当于全局常量. 在interface里面的变量都是public static final 的.所以你可以这样写: public static final int i=10; 或则 int i=10;(可以省略掉一部分,在接口里的成员变量默认就是public static final) 注意在声明的时候要给变量赋予初值 解释: 首先你要弄清接口的含义.接口就是提供一种统

《java中局部变量和成员变量的区别》

1 class Car 2 { 3 String color; 4 int number; 5 6 void run() 7 { 8 System.out.println(color+"::"+number); 9 } 10 } 11 12 class CarDemo 13 { 14 public static void main(String[] agrs) 15 { 16 Car c = new Car();//c是类类型的变量. 17 //c.color = "blue