static关键字用于修饰类的成员,如成员变量以及代码块等。
1.静态变量
class Student{
static String schoolName;
}
public class test2 {
public static void main(String[] args) {
Student student1 = new Student();
Student student2 = new Student();
Student.schoolName="清华大学";
System.out.println("我是student1,来自"+student1.schoolName);
System.out.println("我是student2,来自"+student2.schoolName);
}
}
由程序可以看出,所有学生对象共享一个schoolName的变量,在Java类中,要实现这种功能可以使用static关键字来修饰成员变量,该变量被称为静态变量。
静态变量的访问方式:
(1)类名.变量名
(2)定义类的对象,使用对象.成员变量名访问。
静态变量具有“记忆”功能,即一个被声明为静态的变量只会被初始化一次,该函数在调用过程中,其值保持不变。一个变量被定义为静态变量就会将其放到静态数据区,而不是栈区。
class student{
static int num=10;
int number=10;
public int getNum() {
return num;
}
public int addNum(){
return num++;
}
public int addNumber(){
return number++;
}
public int getNumber() {
return number;
}
}
public class test {
public static void main(String[] args) {
student student1 = new student();
student student2 = new student();
student1.addNum();
student2.addNum();
student1.addNum();
student2.addNum();
student1.addNumber();
student2.addNumber();
student1.addNumber();
student2.addNumber();
System.out.println("student1 :"+"num="+ student1.getNum()+" number="+student1.getNumber());
System.out.println("student2 :"+"num=" + student2.getNum()+" number="+student2.getNumber());
}
}
从上述代码中我们看出,静态成员变量与非静态成员变量的区别。。
注意:
static关键字只能用于修饰成员变量,不能用于修饰局部变量,否则编译会报错,如下代码时不合法的。。
class Person{
public void add(){
static int num=10;
}
}
2.静态方法
如果想要使用类中的成员方法,就需要先将这个类实例化,而在实际开发时,开发人员希望在不创建对象的情况下就开始调用这个方法,这种情况就可以使用静态方法。
静态方法的访问方式:
(1)类名.方法
(2)实例化对象名.方法(不推荐)
class Person{
public static void say(){
System.out.println("hello world");
}
}
public class test {
public static void main(String[] args) {
//用类名.方法 的方式调用静态方法
Person.say();
//实例化对象
Person person = new Person();
//用实例化对象名.方法的方式调用静态方法
person.say();
}
}
在第十行代码中通过Person.say()的形式调用了静态方法,由此可见,静态方法不需要创建对象就可以直接通过类名调用。
注:在一个静态方法中只能访问用static修饰的成员,原因是在于没有被static修饰的成员需要先创建对象才能被访问,而静态方法在被调用时不创建任何对象。
3.静态代码块和初始化块
3.1 静态代码块
在Java中,使用一对大括号包围起来的若干行代码被称为一个代码块,用static关键字修饰打代码块被称为静态代码块,语法如下:
static{
....
}
当类被加载时,静态代码块会执行,由于类只加载一次,因此静态代码块也只执行一次。
在程序中,通常使用静态代码块对类的成员变量进行初始化。
class Person{
String name="张三";
//静态代码块
static {
System.out.println("执行了Person中的静态代码块");
}
}
public class test {
static {
System.out.println("执行测试类中的静态代码块1");
}
public static void main(String[] args) {
Person person1 = new Person();
Person person2 = new Person();
}
static {
System.out.println("执行测试类中的静态代码块2");
}
}
可以看出,程序中的三段代码块全部执行了,在运行程序的时候,Java虚拟机首先会加载类test,在加载类的同时就会执行该类的静态代码块,紧接着会调用main()方法,在main()方法中创建了两个Person对象,但是在实例化的时候,静态代码块的内容只输出了一次,这就说明静态代码块在类第一次使用的时候才会被加载,并且只会加载一次。
3.2 实例初始化块
3.2.1 实例初始化块介绍
初始化块就是在类的内部直接用{}括起来的一段代码(注意这段代码必须在方法外,方法内的是代码块)。初始化块用于对象的初始化。
原则上讲,一个类可以有多个初始化块,按照定义的先后顺序依次执行。但实际上根本没必要定义多个初始化块。
初始化块内部可以放任何可执行性语句,它和构造器都是用于初始化对象。只是构造器是一个方法,根据传入参数的不同,不同对象的构造器执行结果会不同。但初始化块不接受任何参数,所以,初始化块执行的内容相对死板。
实例初始化块会在初始化类的一个实例时执行,而且在构造函数之前就执行。并且每次创建类的对象时它们都会执行。
class Person{
String name="张三";
//初始化块
{
System.out.println("执行了初始化块:" + name);
}
//构造方法
public Person() {
System.out.println("执行了构造方法"+name);
}
}
public class test {
{
String name="张三";
System.out.println("name = " + name);
}
public static void main(String[] args) {
Person person1 = new Person();
Person person2 = new Person();
{
String name="张三";
System.out.println("name = " + name);
}
}
}
实例初始化块和类初始化块:
(1)初始化块作为类的第四个成员,它的修饰符只有一个static。
(2)如果在{}之前加上static修饰符,就表明这是类初始化块。
(3)如果没有修饰符,就是实例初始化块。
实例初始化块与对象相关,会在对象初始化阶段执行代码,帮助对象初始化。
而类初始化块与类相关,在类初始化阶段就会执行,帮助类的初始化。
(4)由于类的初始化早于对象初始化,所以类初始化块一定会先于实例初始化块执行。
类初始化块也是类成员,要遵循类成员不能访问实例成员的原则。这很好理解,凡是和类相关的成员,都不能出现和对象相关的代码,否则系统根本不知道选择哪个对象。
3.2.2 父类中的初始化块
class A{
{
System.out.println("父类中的实例初始化块");
}
public A() {
System.out.println("父类的构造函数");
}
}
public class test extends A{
{
System.out.println("子类中的实例初始化块");
}
public test() {
System.out.println("子类的构造函数");
}
public static void main(String[] args) {
test test = new test();
}
}
由上述程序运行结果可知:
在继承体系中,实例初始化块和构造函数的执行顺序如下:
执行父类的实例初始化块
执行父类的构造函数
执行当前类的实例初始化块
执行当前类的构造函数
3.3 静态代码块,实例初始化块,构造函数的执行顺序
class Person{
String name="张三";
//静态代码块
static {
System.out.println("执行了Person中的静态代码块");
}
//初始化块
{
System.out.println("执行了初始化块:" + name);
}
//构造方法
public Person() {
System.out.println("执行了构造方法"+name);
}
}
public class test {
static {
System.out.println("执行测试类中的静态代码块1");
}
{
String name="张三";
System.out.println("name = " + name);
}
public static void main(String[] args) {
Person person1 = new Person();
Person person2 = new Person();
{
String name="张三";
System.out.println("name = " + name);
}
}
static {
System.out.println("执行测试类中的静态代码块2");
}
}
由上述程序执行情况可以看出:
静态初始化块最先被执行
其次执行,实例初始化块
最后执行,构造方法
静态成员变量 = 静态代码块 > 非静态成员变量 = 非静态代码块 > 构造函数
4.静态类
通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。
class Person{
//静态内部类
public static class Student{
public void sayStudent(){
System.out.println("hello student");
}
public static void sayHelloStudent(){
System.out.println("say hello student");
}
}
public static void say(){
System.out.println("hello world");
}
}
public class test {
public static void main(String[] args) {
//用类名.方法 的方式调用静态方法
Person.say();
//调用内部类
Person.Student student = new Person.Student();
//调用内部类中的非静态方法
student.sayStudent();
//调用内部类中的静态方法
Person.Student.sayHelloStudent();
}
}