再学Java 之 interface的成员变量

时间:2024-02-24 07:55:00

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