static静态关键字
1、 什么是static?
static:静态,相对静止的状态。
2、为什么用static?
在一个类中,创建的对象都有的属性,这个属性是大家(所有的创建出来的对象)共享的。也是为了方便大家的使用,以及减少内存的消耗。
3、 什么时候用static?
工具类,记录某个方法调用的次数,声明内部类
4、 static关键字的使用
由static关键字修饰的是与类有关系,可以直接通过"类名.XXX"这种方式去访问。
如果是变量和方法被static修饰的话则称之为静态变量,静态方法
静态变量的测试:
- 测试1: 使用“对象.静态属性"去访问静态变量的数值
- 测试2: 使用"类名.静态属性"去访问静态变量的数值
- 测试3: 使用新创建的对象去访问一个没有赋值的静态变量 (结果是null,没有出现空指针异常)
- 测试4: 其中一个对象修改静态变量后,其它的对象访问的是?(修改后的静态变量)
- 测试5: 将静态变量置一个空的字符串数值。使用类名.静态属性去访问.看结果是
- 测试6: 使用空引用去访问静态变量,看是否会出现空指针异常?(不会)
代码如下:
public class StaticTest {
public static void main(String[] args) {
Person person = new Person();
person.name = "zebra";
person.age = 24;
person.sex = "男";
System.out.println(person);
// 测试1
System.out.println(person.nation);
// 测试2
System.out.println(Person.nation);
// 测试3
System.out.println(person.live); // null
// 测试4
person.nation = "CNINA";
System.out.println(Person.nation); // CHINA
System.out.println(Person.nation); //CHINA
// 测试5
person.nation = "";
System.out.println(Person.nation);
System.out.println("空的数值赋值给静态变量:" + Person.nation);
// 测试6
person = null;
System.out.println(person.nation);
System.out.println(Person.nation);
}
}
class Person{
// 成员变量: 实例变量、静态变量
String name;
int age;
String sex; // 实例变量
static String nation = "CHN" ; // 静态变量
static String live;
public Person() {
}
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
结果图如下:
静态方法的测试:
- 测试1 类名.静态方法
- 测试2 对象.静态方法
- 测试3 空引用调用静态方法
public class StaticTest01 {
public static void main(String[] args) {
Person person = new Person();
person.name = "zebra";
person.age = 24;
//测试1 类名.静态方法
Person.show();
//测试2 对象.静态方法
person.show();
//测试3 空引用调用静态方法
person = null;
person.show();
}
class Person{
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public static void show(){
System.out.println("Test Static Method");
}
}
注意:
1、静态变量的存储位置,在JDK1.6时在方法区,之后的版本是在堆里面(此处是JDK1.6)
2、静态变量存储在方法区,在类加载的时候,进行初始化,不需要娶new对象,此时内存空间已经开辟出来了
5、静态代码块
5.1 什么是静态代码块?
static {
语句块1;
语句块2;
}
5.2 为什么要使用静态代码块?
要添加一些日志信息,
5.3 什么时候使用静态代码块?
在类加载的时候使用静态代码块,并且类加载只执行了一次。
5.4 静态代码块的简单使用
public class StaticTest02 {
static {
System.out.println("A");
}
public static void main(String[] args) {
Person.show();
}
static {
System.out.println("C");
}
}
class Person{
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public static void show(){
System.out.println("Test Static Method");
}
}
测试结果如下:
5.4 静态代码块的常见笔试题
5.4.1 静态代码块、普通代码块,构造器的执行顺序
public class StaticBlockTest03 {
public static void main(String[] args) {
Tiger tiger = new Tiger("虎吼");
System.out.println(tiger);
}
}
class Animal{
// 名称
String name;
// 性别
String sex;
// 年龄
int age;
static{
System.out.println("父类的静态代码块执行了");
}
{
System.out.println("父类的普通代码块执行了");
}
public Animal() {
System.out.println("父类的无参构方法执行了");
}
public Animal(String name, String sex, int age) {
System.out.println("父类的带参数构造方法执行了");
this.name = name;
this.sex = sex;
this.age = age;
}
}
class Tiger extends Animal{
// 声音
String voice;
static{
System.out.println("子类的静态代码块执行了");
}
{
System.out.println("子类的普通代码块执行了");
}
public Tiger() {
System.out.println("子类的无参构方法执行了");
}
public Tiger(String voice) {
System.out.println("子类的带参构方法执行了");
this.voice = voice;
}
}
结果如下图所示:
1、静态代码块的执行是在类加载的时候执行的,类只加载一次,所以静态代码块只执行一次
2、普通的代码块是在对象创建之后执行的,每创建一个对象,就执行一次这个代码块
整个加载过程是这样的:
1. main函数调用Tiger tiger = new Tiger(“虎吼”);类加载器会去找到Tiger类以及Tiger类的所有的父类,所以此时会去加载父类的静态代码块,并打印父类的静态代码块执行了。然后去执行子类的静态代码块,并打印子类的静态代码块执行了
2. 类加载完之后,开始初始化, 然后会去执行这个子类带参数的构造器
3. 又因为所有的类的构造器都会默认调用父类的构造器(super()的原因)
4. 此时子类tiger构造器会去调用父类Animal此时无参的构造器,之后先去执行父类普通代码块,并打印父类普通代码块执行了然后执行父类无参构造方法,并打印父类无参构造方法执行了。
5. 接着调用子类的带参数的构造器,之后调用子类的普通的代码块并打印子类的普通的代码块执行了,调用子类中带参的构造方法并打印子类中带参的构造方法