static关键字
一、用法
1、static关键字表示静态。能与属性,方法,代码块,内部类等一起使用。
2、static修饰属性和方法时,可以直接通过类名.属性或类名.方法来访问。
3、 静态变量:
• 一个类中,静态的变量只分配一块内存空间。多个实例对象共享该内存空间。
• 静态的变量在类加载的时候,被初始化。也就是说,只要类被加载,不管是否使用该静态变量,则都会自动的为其开辟空间,并初始化。
4、静态方法
• 在类加载时,加载到JVM。直接使用类名.方法名调用。
5、 静态代码块
• 是类的组成部分,在类第一次被加载的时候,执行一次。也就说,静态代码块在程序运行时,只能被执行一次。
• 用于初始化静态的属性。
下面来看示例一:
StaticDemo类
package com.jcxy.demo02;
public class StaticDemo
{
//静态变量
static int a = 10;
static String str = "jack";
//静态方法
public static void show()
{
System.out.println("this is static demo!");
}
}
Test类
package com.jcxy.demo02;
public class Test
{
/**
* 测试static关键字的用法
* <功能详细描述>
* @param args
* @see [类、类#方法、类#成员]
*/
public static void main(String[] args)
{
System.out.println(StaticDemo.a);
System.out.println(StaticDemo.str);
StaticDemo.show();
}
}
打印输出:
10
jack
this is static demo!
示例二:静态代码块的用法
包含普通成员变量,静态成员变量,静态代码块,动态代码块以及构造函数的类
package com.jcxy.demo02;
public class StaticDemo3
{
int age = 21;
static String school = "清华";
static
{
// school = "北大";
System.out.println("这是静态代码块");
}
{
System.out.println("这是非静态代码块");
}
public StaticDemo3()
{
System.out.println("这是对象初始化的构造方法");
}
}
测试类Test
package com.jcxy.demo02;
public class Test
{
/**
* 测试static关键字的用法
* <功能详细描述>
* @param args
* @see [类、类#方法、类#成员]
*/
public static void main(String[] args)
{
StaticDemo3 sd = new StaticDemo3();
System.out.println(StaticDemo3.school);
}
}
打印结果:
这是静态代码块
这是非静态代码块
这是对象初始化的构造方法
清华
通过打印结果,我们不难看到,
1、当我们new一个对象的时候,是静态变量最先开辟内存(在赋值的情况下),未赋值则跳过。
2、接下才静态代码块。
3、接着调用我们的构造方法,注意,调用构造方法的时候,在执行方法体之前。
4、先对普通成员变量进行初始化(当初赋值的情况下),如果没赋值则跳过。
5、接着才执行非静态方法。
6、最后才执行我们构造方法的方法体。
示例三:静态变量定义在静态代码块后与前的区别
看下面这种的输出结果
package com.jcxy.demo02;
public class StaticDemo1
{
static
{
school = "aaa";
//System.out.println(school); 编译错误。在定义前无法引用school
}
public static String school = "清华";
}
Test:
package com.jcxy.demo02;
public class Test
{
/**
* 测试static关键字的用法
* <功能详细描述>
* @param args
* @see [类、类#方法、类#成员]
*/
public static void main(String[] args)
{
// System.out.println(StaticDemo.a);
// System.out.println(StaticDemo.str);
// StaticDemo.show();
System.out.println(StaticDemo1.school);
}
}
打印输出为:清华
为什么呢?
这种情况:
相当于以下代码:
public static String school;
static{
school = “aaa”;
//System.out.println(school);报错
}
school = “清华”;
1- 类加载时,为静态属性分配内存空间,且以默认值填充;
2- 从上向下执行,先为school赋值aaa,再为school赋值清华
但此时要注意的是,声明语句在静态代码块下面,在静态代码块中的如果获得静态属性的值,则会报错。
看第二种情况:
package com.jcxy.demo02;
public class StaticDemo1
{
public static String school = "清华";
static
{
school = "aaa";
System.out.println(school);
}
}
Test:
package com.jcxy.demo02;
public class Test
{
/**
* 测试static关键字的用法
* <功能详细描述>
* @param args
* @see [类、类#方法、类#成员]
*/
public static void main(String[] args)
{
System.out.println(StaticDemo1.school);
}
}
打印:
aaa
aaa
原因分析:
第二种情况:
1- 类加载时,为静态属性分配内存空间,且以默认值填充;
2- 将清华赋值给school
3- 执行静态代码块内容。
因为声明在获得school值之前,所以,可以System.out.println(school);
二、static特点:
1、static可以修饰属性,方法,代码块。此时属性,方法,代码块就成了类变量,静态方法,静态代码块。注意:静态不能修饰局部变量。
2、类变量,静态方法,静态代码块与具体某个对象无关,是属于类级别。如果访问权限允许,通过类名.方法名或类名.属性名访问。
3、静态变量,静态代码块都是在类加载时,执行并初始化。
4、一个类的静态方法或静态代码块,只能访问静态的属性和静态方法,不能直接访问非静态的属性和方法。对于非静态的方法或代码块,可以直接访问静态的或非静态的属性和方法。
5、静态方法或静态代码块中,不能使用this,super关键字。因为this,super是对象,对象在静态之后创建的。
6、静态方法可以被覆盖,但不体现多态;父类如果是静态方法,子类不能覆盖为非静态方法;父类如果是非静态方法,子类不能覆盖为静态方法。
7-构造方法不允许声明为static。因为构造方法是在创建对象时,自动调用;而static属于类级别的。
三、关于静态的用法:
1、静态属性:(类变量)
• 节省内存空间。但生命周期从类加载分配内存开始,到程序结束。
• 实际使用中,当多个对象共享某些数据时,可以将这些设置为静态的变量; 定义常量;
2、 静态方法:
• 不需要创建对象,直接通过类名.方法。静态方法中不能使用非静态的属性和方法。
• 在实际使用中,定义一些和非静态的属性和方法无关的功能时,使用。比如工具类。
3、静态代码块
• 在类加载的时候,只运行一次。
• 实际的使用中,比较少。比如,JDBC时,数据库驱动的加载,可以放在静态代码块中,仅加载一起,后续就可以直接使用。
总的来说,对于static关键字的理解就是要能够理解static修饰的属性或者方法的加载的顺序。那要理解加载的顺序,我们可以通过debug调试来追踪发现。如果想要更深入了解的话,可以通过内存分析来看更加的直观。