8.12 静态属性和静态方法

对象的属性是每个对象都有自己的一份,例如学生类的学号、姓名,每一个学生对象,都有不同的学号姓名,这是很自然的。我们把这些称为对象的属性,前面已经讲过。 但是有一种属性,是所有对象共享的,这种叫做静态属性,或者类属性,它们无需任何对象就能存在,通常都是全部大写的。这类属性需要在前面加关键字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{}部分的代码。

练习题

  • 选择题
    1.以下哪个方法不适合成为类方法 (2分) [选择]
    A.
    B. 接受一个任意数字,计算这个数字的开平方
    C. 接受一个字符串和两个数字,按两个数字截取这个字符串
    D. 接受一个学号,计算这个学号对应的姓名
    E. 不需要参数,可以得到int类型所能容纳的最大值
    2.以下哪个属性适合成为一个类属性 (2分) [选择]
    A.
    B. 假设有一个整数类,8位字节保存整数,它能表达的最大值适合作为类属性
    C. 假设有一个学生类,全校学生都是它的对象,班级名适合作为类属性
    D. 假设有一个教师类,教师上课的班级适合作为类属性
    E. 假设有一个茶杯类,茶杯的容量适合作为类属性
  • 判断题
    1.非静态方法可以调用静态方法,也可以使用静态属性 (2分) [判断]
    2.已知Some类的定义如下,那么Some.GOOD这样的写法会有语法错误 (2分) [判断]
    public class Some{    private int id;    public int GOOD;}
    
    3.Some s=new Some();s.GOOD=100;会有语法错误 (2分) [判断]
    public class Some{    private int id;    public int GOOD;}
    
    4.main是静态函数,它不能使用类里面的非静态属性 (2分) [判断]
    5.静态方法不需要对象就能调用,就算使用对象调用,静态方法也不能读取、修改对象的属性 (2分) [判断]
    6.非静态方法不能使用静态属性 (2分) [判断]
    7.静态方法只能被静态方法调用,非静态方法只能调用非静态方法 (2分) [判断]
    8.非静态方法不能调用静态方法 (2分) [判断]
  • 编程题
    1.***已知Student类,完成静态方法Check(此题需要用到9.1String类的知识) (10分) [编程填空]
    这个方法接受一个字符串id为参数,测试这个字符串是否符合规范:
    (1)id长度为10位
    (2)id全部是数字字符
    (3)第5、6位表示学院,必须是01到12之间(可以等于01和12),假设这个学校只有12个二级学院
    符合上诉条件,check返回true,表示id合法,否则返回false。
    例如这是一个id:2019080301,它符合上面的三个规范;如果是“20190803012”就不符合了,它长度超过10位。
    提示:判断是否数字,可以使用String的charAt,遍历整个字符串,然后用Character的isDigit方法判断,具体看常用类的包装类。
    截取字符串的某一部分,请参考常用类字符串String类。截取后的字符串,可以用Integer.parseInt(str)转换成整数,str是截取出来的部分如“05”,再判断这个整数。
    public class Student{    private String name;    private String id;    private String gender;    private String clazz;    private String major;    public Student(String id){        this.id=id;    }    /**    (1)id长度为10位    (2)id全部是数字字符    	(3)第5、6位表示学院,必须是01到12之间(可以等于01和12)    id符合上述条件,返回true;否则返回false     */    public static boolean check(String id){                  }    public static void main(String[]args){        String id="2019080301";        System.out.println(Student.check(id));        id="20190803012";        System.out.println(Student.check(id));        id="201a080308";        System.out.println(Student.check(id));        id="201908030b";        System.out.println(Student.check(id));        id="2019000303";        System.out.println(Student.check(id));        id="2019130304";        System.out.println(Student.check(id));        id="201913030";        System.out.println(Student.check(id));    }}