Static
在类中声明的实例变量,其值是每一个对象独立的。但是有些成员变量的值不需要或不能每一个对象单独存储一份,即有些成员变量和当前类的对象无关。
在类中声明的实例方法,在类的外面必须要先创建对象,才能调用。但是有些方法的调用和当前类的对象无关,那么创建对象就有点麻烦了。
此时,就需要将和当前类的对象无关的成员变量、成员方法声明为静态的(static)。
成员变量分为两种:
- 静态变量(有static)
- 实例变量(没有static)
1、语法格式
有static修饰的成员变量就是静态变量。
【修饰符】 class 类{
【其他修饰符】 static 数据类型 静态变量名;
}
2、静态变量的特点
- 静态变量的默认值规则和实例变量一样。
- 静态变量值是所有对象共享。
- 静态变量的值存储在方法区。
- 静态变量在本类中,可以在任意方法、代码块、构造器中直接使用。原则:对象可以使用类的信息,类不能反过来使用对象的信息。
- 如果权限修饰符允许,在其他类中可以通过“类名.静态变量”直接访问,也可以通过“对象.静态变量”的方式访问(但是更推荐使用类名.静态变量的方式)。
- 静态变量的get/set方法也静态的,当局部变量与静态变量重名时,使用“类名.静态变量”进行区分。
案例:编写一个员工类型,希望有一个变量可以统计员工对象的数量(即创建了多少个员工对象)。员工里面有属性:员工编号、员工姓名,希望员工编号是从1开始自增。第一个员工就是1,第二个员工就是2...。
>遇到的问题:之前的非静态的成员变量是每一个对象“独立”的,无法实现“共享”。
>
>解决方案:静态。成员变量用static修饰。
```Java
public class Employee {
static int total;//默认值还是0
private int id;
private String name;
private int score;
{
//非静态代码块,两个构造器共同代码的提取,
//为什么要抽取?因为有两个构造方法,
//不抽取的话,分别用不同的构造方法构造对象,数据不会被共享
total++;
this.id = total;
}
public Employee(String name) {
this.name = name;
}
public Employee(String name, int score) {
this.name = name;
this.score = score;
}
public static int getTotal() {
return total;
}
public static void setTotal(int total) {
Employee.total = total;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + ''' +
",total = " + total +
'}' ;
}
}
public class TestStatic {
public static void main(String[] args) {
System.out.println("一开始,员工对象的数量有:" + Employee.getTotal());//0
Employee e1 = new Employee("张三");
System.out.println(e1);
Employee e2 = new Employee("李四");
System.out.println(e2);
Employee e3 = new Employee("王五", 89);
System.out.println(e3);
System.out.println("创建完3个员工对象后,员工对象的数量:" + Employee.getTotal());//推荐 输出3
//通过对象,访问静态方法
System.out.println("通过e1对象调用静态方法,获取员工的数量:" + e1.getTotal());//不推荐
//下面两个使用,需要total不是private的,即权限修饰符允许
System.out.println("获取total,不通过方法:" + Employee.total);//推荐
System.out.println("获取total,不通过方法:" + e1.total);//不推荐
}
}
2、静态方法的特点
【修饰符】 class 类{
【其他修饰符】 static 返回值类型 方法名(形参列表){
方法体
}
}
- 静态方法在本类中,任意的方法、代码块、构造器都可以使用,没有限制。
- 静态方法在类的外面,只要权限修饰符允许,可以通过:“对象.静态方法” 或 “类名.静态方法”,推荐使用 "类名.静态方法"
- 在静态方法中千万不要直接使用本类的 非静态属性、非静态方法、this、super。
- 静态方法不允许被子类重写,但是可以被子类继承。
- 静态方法不是“虚”方法。既然不是虚方法,就没有多态现象(只看变量的编译时类型)。
public class Father {
public static void method(){
System.out.println("Father.method");
}
public static void fun(){
System.out.println("Father.fun");
}
}
public class Son extends Father{
// @Override //尝试重写静态方法,加上@Override编译报错,去掉Override不报错,但是也不是重写
public static void fun(){
System.out.println("Son.fun");
}
}
public class TestStaticMethod {
public static void main(String[] args) {
Father.method();
Son.method();//继承静态方法
Father f = new Son();
f.method();//执行Father类中的method
}
}
3、静态代码块
在代码块前面加static,就是静态代码块
【修饰符】 class 类{
static{
静态代码块
}
}
静态代码块的特点
- 每一个类的静态代码块只会执行一次。非静态代码块在实例初始化时执行,每次new对象都会执行。
- 静态代码块的执行优先于非静态代码块和构造器。