首先提一个问题,为什么static关键字有静态一说??
下面我举个例子:
我们定义一个学生类:
- 学生类Student这个模板中有姓名(name)、年龄(age)、学号(num)这些属性。
然后我们实例化三个对象:
- 第一个学生对象:小明(name)、18(age)、001(num)、所在班级(1班)
- 第二个学生对象:小红(name)、20(age)、002(num)、所在班级(1班)
- 第三个学生:小王(name)、22(age)、003(num)、所在班级(1班)
在这个例子中,我们发现三个同学姓名年龄学号都不一样,但是他们都是一个班的同学。首先说明一下,定义一个类,就需要在内存里开辟一块空间,而类内部的属性都属于这个内存空间,那么当我们实例化的时候,又在每个对象中添加一个所在班级的属性,那为什么不将所在班级这个属性放在类中呢,而且这样做节省内存,一旦使用了static关键字,那么这个内容就不在属于对象自己,而是属于类,凡是本类的对象,都共享同一份,比如上面例子中的三个对象共享同一份name、age、num。静态,个人感受就是相对于对象来说,调用方法或者变量不需要实例化,在加载类的时候就已经被加载。
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。简而言之:方便在没有创建对象的情况下来进行调用(方法/变量)。
具体定义
在类当中,使用static修饰符的属性(成员变量)成为静态变量,或者称为类变量,常量称为静态常量,方法称为静态方法或者类方法,不论是静态变量还是静态方法,统称为静态成员,归整个类所有。
静态成员不依赖于对象,换句话说就是不依赖类的特定实例,被整个类所共享。也就是说,只要是static修饰的方法或者变量不需要依赖于对象进行访问,只要这个类被加载,JVM(Java虚拟机)就可以根据类名找到它们。
注意事项:
- 1.static修饰的成员变量和成员方法属于改类。
- 2.普通变量和方法从属于对象。
- 3.静态方法不可以调用非静态成员,否则编译会报错。
成员变量
1.静态变量
- 运行时,JVM只为静态变量分配一次内存,在加载类的过程中,完成静态变量的内存分配。
- 在类的内部,可以在任何方法内直接访问静态变量。
- 在其它类当中,可以通过类名访问改类中的静态变量。
静态变量在类中的作用:
- 静态变量可以被类中所有的实例共享,因此静态变量可以作为实例之间所共享的数据,增加实例之间的交互性。
- 如果所有的类都包含一个相同的属性,则可以把该属性定义为类的静态常量类型
2.实例变量
- 每创建一个实例,JVM就会为实例变量分配一次内存。
- 在类的内部,可以在任何方法内直接访问静态变量。
- 在其它类当中,可以通过类名访问该类中的静态变量。
代码演示访问静态变量和实例变量:
public class demo01Static {
// 使用static修饰过的变量,静态变量。
public static String str1 = "shuyv";
public static void main(String[] args) {
// 实例变量
String str2 = "dkl";
// 直接访问静态变量和实例变量
System.out.println("There are two names : " + str1 + " and " + str2);
// 通过类名访问静态变量和实例变量
String strone = demo01Static.str1+ " and " + str2;
System.out.println("There are two names : " + strone);
// 通过对象访问静态变量和实例变量
demo01Static name = new demo01Static();
name.str1 = name.str1 + " and " + str2;
String strtwo = name.str1;
System.out.println("There are two names : " + strtwo);
}
}
三次输出的结果都是:
There are two names : shuyv and dkl
从运行结果来看,静态属性,在main方法中可以直接访问,也可以通过类名访问,还可以实例化对象来访问,总之,静态属性被一个类中的所有实例所共享。
3.静态方法和实例方法
与静态变量相似静态方法即是被static修饰的方法。
反之,实例方法即是没有被static修饰的方法。
静态方法和实例方法的区别:
- 1.静态方法不需要通过实例化对象进行调用,因此在静态方法中不可以使用this关键字,也不可以直接访问所属类的实例变量和实例方法。
- 2.在实例方法中可以直接访问所属类的静态变量、静态方法、和实例方法。
代码演示
public class demo02StaticMethod {
// 定义静态变量
public static int count = 1;
// 定义实例方法method1
public int method1() {
count++;
System.out.println("----------------------------------");
System.out.println(count); // 在实例方法中可以直接访问静态变量
return count;
}
// 定义静态方法method2
public static int method2() {
count += count;
System.out.println("----------------------------------");
System.out.println(count);
return count;
}
// 定义静态方法PrintCount
public static void PrintCount() {
count += 2;
System.out.println("----------------------------------");
System.out.println(count);
}
// 通过实例化对象来调用方法
public static void main(String[] args) {
demo02StaticMethod math = new demo02StaticMethod();
System.out.println("实例方法method1的返回值为:" + math.method1());
System.out.println("静态方法method2的返回值为:" + math.method2());
demo02StaticMethod.PrintCount(); // 通过类名调用静态方法,打印count
}
}
运行结果如下:
----------------------------------
2
method1的返回值为:2
----------------------------------
5
method2的返回值为:5
----------------------------------
7
通过上面代码举例,我们发现,首先count作为静态变量在整个类当中被共享,因此,在各个方法当中调用的值不同。在静态方法medthod2方法和PrintCount方法中是不可以调用非静态方法method1的,而在method1方法中可以调用静态方法medthod2和PrintCount方法的。
在访问非静态方法时,需要通过实例对象来访问,而在访问静态方法时,可以直接访问,也可以通过类名来访问,还可以通过实例化对象来访问。
静态代码块
静态代码块在Java中指的是 static{ } 代码块,主要用于初始化类,为类的静态变量赋值初始值,提升程序性能。
静态代码块的特点:
- 1.静态代码块类似于一个方法,但是它不可以存在于任何代码块中。
- 2.静态代码块可以存在于类中的任何地方,类当中可以有多个静态初始化块。
- 3.Java虚拟机在加载类时执行静态代码块,所以很多时候会将一些只需要执行一次的初始化操作都放在static代码块中进行。
- 4.如果类当中包含多个静态代码块,则Java虚拟机将按它们在类中出现的次序依次执行,而且每个静态代码块只会被执行一次。
- 5.静态代码块和静态方法一样,不可以直接访问类的实例变量和实例方法,而需要通过类的实例化对象来访问。
代码演示:
public class demo03StaticCode {
public static int count = 0; // 静态变量
// 非静态代码块
{
count++;
System.out.println("非静态代码块执行了");
System.out.println("count:" + count);
}
// 静态代码块
static {
count++;
System.out.println("---------------------------");
System.out.println("静态代码块1: " + count);
}
// 静态代码块
static {
count++;
System.out.println("---------------------------");
System.out.println("静态代码块2: " + count);
}
public static void main(String[] args) {
//int count01 = 11;
System.out.println("---------------------------");
demo03StaticCode sta1 = new demo03StaticCode(); // 实例化第一个对象
System.out.println("---------------------------");
demo03StaticCode sta2 = new demo03StaticCode(); // 实例化第二个对象
}
}
运行结果为:
---------------------------
静态代码块1: 1
---------------------------
静态代码块2: 2
---------------------------
非静态代码块执行了
count:3
---------------------------
非静态代码块执行了
count:4
上述代码中的非静态代码块,是在创建对象的时候自动调用。不创建对象不执行该类的非静态代码块。代码域中定义的变量都是局部的,只有域中的代码可以调用。