8.11 静态属性和静态方法
对象的属性是每个对象都有自己的一份,例如学生类的学号、姓名,每一个学生对象,都有不同的学号姓名,这是很自然的。我们把这些称为对象的属性,前面已经讲过。
但是有一种属性,是所有对象共享的,这种叫做静态属性,或者类属性,它们无需任何对象就能存在,通常都是全部大写的。这类属性需要在前面加关键字static:
public class Mobile{
static int NUM=100;
String name;
String mon;
}
NUM这个属性是所有对象共享的,而使用的话,是这样的:
public static void main(String[]args){
Mobile mobile1=new Mobile();
mobile1.NUM--;
Mobile mobile2=new Mobile();
mobile2.NUM--;
Mobile.NUM--;
System.out.println(Mobile.NUM);
}
最后会打印97。注意这条语句Mobile.num--,表明了num这个属性完全不需要任何对象,就能存在,事实上,读取或者修改静态属性,往往是"类名.静态属性"这样的形式,如果使用“对象.静态属性”,编译器会出警告。
例如学生类,有一个属性是学校名称,这是所有学生对象都相同的,如果学校改名了,所有学生对象的学校名都改了。
修改这类属性,不需要通过对象:
public class Student{ private String name; public String id; private String clazz; static String SCHOOL; public static void main(String[]a){ Student.SCHOOL="清华大学"; }}
Student就是类名。使用这样形式的其实我们已经使用过了,它就是:
System.out.println();
在这里System是一个类,out是它的一个类属性(out的类型是java.io.PrintStream,也就是说out是PrintStream的一个对象)。这里根本没有System对象。
和静态属性类似的,是静态方法。
静态方法,一种不需要对象就能调用的方法。这是一个Math类方法的调用,计算x的绝对值:
int x=-9;
int m=Math.abs(x);
System.out.println(m);
最终打印9,也即是-9的绝对值。绝对值函数abs的调用,不需要Math对象,事实上,Math类全部都是静态方法,它就是一个提供了数学函数的一个集合体。并不需要创建一个对象。
main函数就是静态方法。
1.在同一个类内部,任何方法(静态或者非静态)都可以调用静态方法,都可以使用静态属性。
2.在同一个类内部,静态方法不可以调用非静态方法,不可以使用非静态属性。
关于第二点,可以这样理解:静态方法调用不需要对象,所以不能使用对象才有的属性和方法(也就是非静态的属性和方法)。这也可以解释静态方法里面不能出现this关键字。
对象是类的一个实例,每个对象都有独立的属性值来描述自身,除了静态属性外,其余的属性在每个对象之间是相互独立的。类和对象的关系,就是抽象和具体的关系。马是一个类,这匹马就是一个对象,那匹马也是。
main函数也是静态方法,它只能调用静态函数。所以在第七章的函数,基本都是静态函数,函数声明需要static修饰符。
static关键字修饰的变量、方法,都是不依赖对象而存在的。并且是对象都共用的。
在函数前面增加关键字static,那么这个函数就是静态方法,下面的代码welcome就是静态方法:
public class Mobile{ static int NUM=100; int n=100; String name; String mon; public static void welcome(String name){ System.out.println("欢迎你,"+name); } public Mobile(){ System.out.println("构造函数被调用"); } public static void main(String[]args){ Mobile.welcome("good"); }}
接下来我们接触static另一种用法:
public class Mobile{ static int NUM=100; int n=100; String name; String mon; static{ NUM=0; welcome("abc"); } public static void welcome(String name){ System.out.println("欢迎你,"+name); } public Mobile(){ System.out.println("构造函数被调用"); } public static void main(String[]args){ Mobile.welcome("good"); Mobile f=new Mobile(); Mobile f2=new Mobile(); }}
这里的static{},大括号内部可以给static类型的变量赋值,可以调用static函数,但是这里不能调用非static方法,也不能给非static变量赋值,例如类里面的变量one。
更重要的是:只要类被使用(创建对象、使用静态属性和静态方法),static代码块就会执行,但是只执行一次。
相当于类的静态属性的初始化,这段代码将打印:
欢迎你,abc
欢迎你,good
构造函数被调用
构造函数被调用
class装载完毕,就调用static代码块,里面有一个welcome静态方法,所以打印了“欢迎你,abc”,然后再执行main函数,调用welcom方法以及调用了两个构造函数,打印了两个“构造函数被调用”。
后续再使用Mobile类,只要运行环境没有改变,就不会再运行static{}部分的代码。