接口的常量 默认 public static finalpublic 和 final很好理解,一个是为了实现【对扩展开放】,一个是为了对【修改关闭】。那么static呢?
查看了一些解释,其中有说如果没有static了就和抽象类一下,个人认为没有说服力,java不会为了区别接口和抽象类而设置这种多余的功能,肯定是为了实现某个目的而定。
还有一个说法是说,担心多个接口中,常量重名的问题,为了区分是那个接口的常量而设置static,那么这样一来,就不用担心多个接口中方法重名的问题吗?而且如果给接口种的方法加static的话,反而不允许。
查看了一些解释,其中有说如果没有static了就和抽象类一下,个人认为没有说服力,java不会为了区别接口和抽象类而设置这种多余的功能,肯定是为了实现某个目的而定。
还有一个说法是说,担心多个接口中,常量重名的问题,为了区分是那个接口的常量而设置static,那么这样一来,就不用担心多个接口中方法重名的问题吗?而且如果给接口种的方法加static的话,反而不允许。
在Java程序里面,所有的东西都是对象,而对象的抽象就是类,对于一个类而言,如果要使用他的成员,那么普通情况下必须先实例化对象后,通过对象的引用才能够访问这些成员,但是有种情况例外,就是该成员是用static声明的(在这里所讲排除了类的访问控制),例如:
未声明为static
class ClassA{
int b;
public void ex1(){
…
}
}
class ClassB{
void ex2{
int i;
ClassA a = new ClassA();
i = a.b; //这里通过对象引用访问成员变量b
a.ex1; //这里通过对象引用访问成员函数ex1
}
} 声明为static
class ClassA{
static int b;
static void ex1(){
…
}
}
class ClassB{
void ex2{
int i;
i = ClassA.b; //这里通过类名访问成员变量b
ClassA.ex1; //这里通过类名访问成员函数ex1
}
}
通过以上两种比较,就可以知道static用来修饰类成员的主要作用了,在java类库当中有很多类成员都声明为static,可以让用户不需要实例化对象就可以引用成员,最基本的有Integer.parseInt(),Float.parseFloat()等等用来把对象转换为所需要的基本数据类型。这样的变量和方法我们又叫做类变量和类方法。
接下来讲一下被static修饰后的变量的值的问题,刚才在前面讲过,被static修饰后的成员,在编译时由内存分配一块内存空间,直到程序停止运行才会释放,那么就是说该类的所有对象都会共享这块内存空间,看一下下面这个例子:
class TStatic{
static int i; public TStatic(){
i = 4;
} public TStatic(int j){
i = j;
} public static void main(String args[]){
TStatic t = new TStatic(5); //声明对象引用,并实例化
TStatic tt = new TStatic(); //同上
System.out.println(t.i);
System.out.println(tt.i);
System.out.println(t.i);
}
}
这段代码里面Tstatic类有一个static的int变量I,有两个构造函数,第一个用于初始化I为4,第二个用于初始化i为传进函数的值,在main中所传的值是5,程序首先声明对象的引用t,然后调用带参数的构造函数实例化对象,此时对象t的成员变量I的值为5,接着声明对象tt,调用无参数的构造函数,那么就把对象tt的成员变量i的值初始化为4了,注意了,在这里i是static,那就是说该类的所有对象都共享该内存,那也就是说在实例化对象tt的时候改变了i的值,那么实际上对象t的i值也变了,因为实际上他们引用的是同一个成员变量。最后打印的结果是三个4。呵呵,写到这里大家是否明白了呢?不明白就再看看书或者多写几个例子印证一下,呵呵。
但是,我问的是为什么 接口的常量要必须是static的,感觉你没有说到点上。、
而且我问的是接口,你是用类局里。
就表示属于对象的,只有建立对象时才有它,而接口是不能建立对象的,所以
接口的常量必须定义为static
就表示属于对象的,只有建立对象时才有它,而接口是不能建立对象的,所以
接口的常量必须定义为static言简意赅
1.接口中的变量如果不是static,就必须初始化一个接口的实例才能访问接口中的变量,初始化一个接口的实例就要实现接口所有的方法,代价很大。而接口中的变量都是final的,即所有实现接口的实例拥有的变量值都是一样的,用一个代价很大的方式(初始化一个接口的实例)去访问一个所有实例都相同的值,得不偿失
那为什么接口中的变量是final修饰呢?
2. 因为接口本身就是用来定义一个标准、规范,是用来设计用户可用的细节(public)且不能随意更改的(final),那么接口中的任何东西都应该被定义成统一,那么定义的数值应该是常量
假如接口中可以定义非final,而仅仅是public和static修饰的变量,那么被实现的类可以随便修改接口中的变量,这样会造成标准不统一
反证:银行的提款机
银行的提款机中的插卡口可以看做是一个接口,所有的提款机插卡口是被统一的标准(大小尺寸)所约束的,方便每个卡可以插入各个提款机中。假如可以随便修改插卡口接口的数值,某行在当地修改了插卡口的尺寸,当你去提款机取钱,却发现插卡口小了点,那么......
就表示属于对象的,只有建立对象时才有它,而接口是不能建立对象的,所以
接口的常量必须定义为static
老哥,稳
正因为接口是无状态的,所以接口中不允许出现实例成员,这是一个原则。
带有static修饰的成员属于类成员,不属于实例成员(不是跟着对象走的),不属于接口的状态。
如果接口支持状态的话,那么抽象类还有其存在的价值么?
刚刚试了下,好像可以哦~
2、static修饰的方法是静态方法,静态方法不能被重写,可以不实例化就调用,但是接口里都是抽象方法,而且接口就是用来实现的,接口中的方法就是用来重写的,所以接口里不能有static方法
实际上,Java8就已经允许接口定义默认方法了
2. 假设接口有非静态字段, 那么情况会是怎样
3. 接口的非静态不应该是public, 这样对成员属性的直接访问会破坏封装性, 就像我们最简单的一个javabean也是通常会把属性写成private然后提供getter/setter方法来访问
4. 当接口的非静态字段是private的情况下, 那么这个字段失去了直接被访问的途径, 只剩下两种访问途径
5. 一种是在构造方法中进行初始化, 而由于接口的多继承特性, 导致不可能有构造方法存在, 那么失去了构造方法, 这些属性无法被灵活的初始化, 在所有子类中都只能在初始化时设置一个固定值(进一步说只能是默认值)
6. 在非静态方法中进行访问, 但是接口的方法都是抽象, 因此在接口这一级别是没有任何地方能够使用和初始化这些非静态字段的
7. 这两种访问途径都是行不通的, 所以在接口级别提供这些非静态字段, 既不能被外部访问, 又不能被接口本身所使用, 其实没有什么意义, 与其如此倒不如将定义字段的这一步骤推迟到子类(就算是protected字段子类可以访问, 但是在接口中无法提供语法强制子类利用这个字段, 而在抽象类中可以通过构造方法强制传参初始化这个字段或者通过非抽象方法强制使用这个字段, 只有被使用字段才有意义)
8. 简单的来讲, 由于接口没有构造方法并且全是抽象方法的特性, 定义非静态字段没有实际的意义
9. 既然如此, 为什么不从语法上进行修改, 让接口支持非抽象的非静态方法呢(实际上java8的接口已经支持静态方法和非静态的非抽象方法)
10. 问题的进一步就是为什么不把接口和抽象类进行合并呢
11. 这个问题我认为至少有两个方面
12. 第一, 抽象类的本质是类, 单继承, 所以可以有构造方法, 至少是有参构造方法, 而接口多继承无法做到
13. 第二, 从设计的角度来讲, 接口原本的设计目的就是倾向于提供规范, 例如最常见的JDBC规范里的Statement, ResultSet, Connection, Servlet规范里的HttpSession, HttpServletRequest, HttpServletResponse, Servlet等等, 这些都是接口, 而规范只需要指定一个抽象的功能(入参, 出参, 方法名, 异常列表), 具体实现是不关注的, 而抽象类的设计目的更加倾向于提供模版, 在提供部分非抽象的逻辑实现的基础上, 结合一部分抽象的部分, 模版就像我们写年终总结网上抄来的范文, 大部分写好了不需要改动的部分就是抽象类里的非抽象部分, 而需要改动的年月日, 姓名, 公司名等细节就是抽象类里的抽象方法部分, 交给具体的子类来实现, 正是由于他们设计的出发点不同, 所以他们才有不同的语法限制
14. 更进一步, 为何要设计出这样两种语言特性呢, 为何不合并呢(就算是多继承导致无法提供有参构造, 但是真有心改动也是可以实现的)
15. 这个问题的进一步问题就是一个语言为什么要设计出这么多细化的特性, 为什么不把多个特性融合在一起让用户在使用时自己选择需要用到的部分
16. 这个问题就像java里的基础数据类型byte char short int一样, 为什么要设计设计出一个字节, 两个字节, 四个字节这么多种整数? 可能有人觉得目的是节约内存, 但是实际上在虚拟机中进行数学运算的时候, 所有这几种类型都会转为int然后利用int类型的字节码来进行运算, 并不存在所谓的short比int更节省内存的所以, 至少在方法内的局部变量是这样
17. 问题的答案就在与细化, 把功能和特性进行更加严格的细化和区分, 让结构更清晰, 更利于管理, 就像面向对象的设计原则中的高内聚低耦合一样, 把功能细化, 保持每个功能点的职责单一, 而不是所有功能一团混沌让用户自己来进行取舍, 减少用户犯错的机会18. 问题到了这里我想总结出来就是, 为什么是这样呢? 因为语法就是这么设计的, 那么为什么这么设计呢? 因为接口的设计目的是提供规范, 而抽象类是提供模版, 那么为什么不把他们合并到一起让用户自己选择是否需要提供非抽象内容呢? 因为语法特性细化是一种好的设计, 不应该把所有特性糅合在一起让用户来选择并承担犯错成本
先说接口中的方法:void ooxx().默认就是public abstratct,抽象方法必须被子类实现才有意义.为什么不能用static?static修饰符说明这个方法属于类,不属于对象.在多态思想中,把子类对象赋值给父类/接口变量,那么此时就存在多态.而多态是属于对象级别的特性.接口中的方法如果用static 修饰,那么怎么也不会被实现,所以编译就报错.
再说字段,字段也不存在多态的特征.要访问接口中的字段,只有通过类来访问(因为接口不能创造对象),所以字段必须用static修饰.为什么用finnal,因为是定义规范,不能被修改~
static int i;
public TStatic() {
i = 4;
}
public TStatic(int j) {
i = j;
}
@SuppressWarnings("static-access")
public static void main(String[] args) {
TStatic t = new TStatic(5);
TStatic tt = new TStatic();
System.out.println(t.i);//为什么在这里就是打印的4?
//System.out.println(tt.i);
//System.out.println(t.i);
}
}