static关键字的四种⽤法
在java的关键字中,static和final是两个我们必须掌握的关键字。不同于其他关键字,他们都有多种⽤法,⽽且在⼀定环境下使⽤,可以提⾼程序的运⾏性能,优化程序的结构。下⾯我们先来了解⼀下static关键字及其⽤法。
static关键字
1.修饰成员变量
在我们平时的使⽤当中,static最常⽤的功能就是修饰类的属性和⽅法,让他们成为类的成员属性和⽅法,我们通常将⽤static修饰的成员称为类成员或者静态成员,这句话挺起来都点奇怪,其实这是相对于对象的属性和⽅法来说的。请看下⾯的例⼦:(未避免程序太过臃肿,暂时不管访问控制)
public class Person {
String name;
int age;
public String toString() {
return "Name:" + name + ", Age:" + age;
}
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "zhangsan";
p1.age = 10;
Person p2 = new Person();
p2.name = "lisi";
p2.age = 12;
System.out.println(p1);
System.out.println(p2);
}
/**Output
* Name:zhangsan, Age:10
* Name:lisi, Age:12
*///~
}
上⾯的代码我们很熟悉,根据Person构造出的每⼀个对象都是独⽴存在的,保存有⾃⼰独⽴的成员变量,相互不会影响,他们在内存中的⽰意如下:
从上图中可以看出,p1和p2两个变量引⽤的对象分别存储在内存中堆区域的不同地址中,所以他们之间相互不会⼲扰。但其实,在这当中,我们省略了⼀些重要信息,相信⼤家也都会想到,对象的成员属性都在这了,由每个对象⾃⼰保存,那么他们的⽅法呢?实际上,不论⼀个类创建了⼏个对象,他们的⽅法都是⼀样的:
从上⾯的图中我们可以看到,两个Person对象的⽅法实际上只是指向了同⼀个⽅法定义。这个⽅法定义是位于内存中的⼀块不变区域(由jvm划分),我们暂称它为静态存储区。这⼀块存储区不仅存放了⽅法的定义,实际上从更⼤的⾓度⽽⾔,它存放的是各种类的定义,当我们通过new来⽣成对象时,会根据这⾥定义的类的定义去创建对象。多个对象仅会对应同⼀个⽅法,这⾥有⼀个让我们充分信服的理由,那就是不管多少的对象,他们的⽅法总是相同的,尽管最后的输出会有所不同,但是⽅法总
是会按照我们预想的结果去操作,即不同的对象去调⽤同⼀个⽅法,结果会不尽相同。
我们知道,static关键字可以修饰成员变量和⽅法,来让它们变成类的所属,⽽不是对象的所属,⽐如我们将Person的age属性⽤static进⾏修饰,结果会是什么样呢?请看下⾯的例⼦:
public class Person {
String name;
static int age;
/* 其余代码不变... */
/**Output
* Name:zhangsan, Age:12
* Name:lisi, Age:12
*///~
}
我们发现,结果发⽣了⼀点变化,在给p2的age属性赋值时,⼲扰了p1的age属性,这是为什么呢?我们还是来看他们在内存中的⽰意:
我们发现,给age属性加了static关键字之后,Person对象就不再拥有age属性了,age属性会统⼀交给Person类去管理,即多个Person对象只会对应⼀个age属性,⼀个对象如果对age属性做了改变,其他的对象都会受到影响。我们看到此时的age和toString()⽅法⼀样,都是交由类去管理。
虽然我们看到static可以让对象共享属性,但是实际中我们很少这么⽤,也不推荐这么使⽤。因为这样会让该属性变得难以控制,因为它在任何地⽅都有可能被改变。如果我们想共享属性,⼀般我们会采⽤其他的办法:
public class Person {
private static int count = 0;
int id;
String name;
int age;
public Person() {
id = ++count;
}
public String toString() {
return "Id:" + id + ", Name:" + name + ", Age:" + age;
}
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "zhangsan";
p1.age = 10;
Person p2 = new Person();
p2.name = "lisi";
p2.age = 12;
System.out.println(p1);
System.out.println(p2);
}
/**Output
* Id:1, Name:zhangsan, Age:10
* Id:2, Name:lisi, Age:12
*///~
}
上⾯的代码起到了给Person的对象创建⼀个唯⼀id以及记录总数的作⽤,其中count由static修饰,是Person类的成员属性,每次创建⼀个Person对象,就会使该属性⾃加1然后赋给对象的id属性,这样,count属性记录了创建Person对象的总数,由于count使⽤了private修饰,所以从类外⾯⽆法随意改变。
2.修饰成员⽅法
static的另⼀个作⽤,就是修饰成员⽅法。相⽐于修饰成员属性,修饰成员⽅法对于数据的存储上⾯并没有多⼤的变化,因为我们从上⾯可以看出,⽅法本来就是存放在类的定义当中的。static修饰成员⽅法最⼤的作⽤,就是可以使⽤"类名.⽅法名"的⽅式操作⽅法,避免了先要new出对象的繁琐和资源消耗,我们可能会经常在帮助类中看到它的使⽤:
public class PrintHelper {
public static void print(Object o){
System.out.println(o);
}
public static void main(String[] args) {
PrintHelper.print("Hello world");
}
}
上⾯便是⼀个例⼦(现在还不太实⽤),但是我们可以看到它的作⽤,使得static修饰的⽅法成为类的⽅法,使⽤时通过“类名.⽅法名”的⽅式就可以⽅便的使⽤了,相当于定义了⼀个全局的函数(只要导⼊该类所在的包即可)。不过它也有使⽤的局限,⼀个static修饰的类中,不能使⽤⾮static修饰的成员变量和⽅法,这很好理解,因为static修饰的⽅法是属于类的,如果去直接使⽤对象的成员变量,它会不知所措(不知该使⽤哪⼀个对象的属性)。
3.静态块
在说明static关键字的第三个⽤法时,我们有必要重新梳理⼀下⼀个对象的初始化过程。以下⾯的代码为例:
package com.dotgua.study;
class Book{
public Book(String msg) {
static修饰的变量
System.out.println(msg);
}
}
public class Person {
Book book1 = new Book("book1成员变量初始化");
static Book book2 = new Book("static成员book2成员变量初始化");
public Person(String msg) {
System.out.println(msg);
}
Book book3 = new Book("book3成员变量初始化");
static Book book4 = new Book("static成员book4成员变量初始化");
public static void main(String[] args) {
Person p1 = new Person("p1初始化");
}
/**Output
* static成员book2成员变量初始化
* static成员book4成员变量初始化
* book1成员变量初始化
* book3成员变量初始化
* p1初始化
*///~
}
上⾯的例⼦中,Person类中组合了四个Book成员变量,两个是普通成员,两个是static修饰的类成员。我们可以看到,当我们new⼀个Person对象时,static修饰的成员变量⾸先被初始化,随后是普通成员,最后调⽤Person类的构造⽅法完成初始化。也就是说,在创建对象时,static修饰的成员会⾸先被初始化,⽽且我们还可以看到,如果有多个static修饰的成员,那么会按照他们的先后位置进⾏初始化。
实际上,static修饰的成员的初始化可以更早的进⾏,请看下⾯的例⼦:
class Book{
public Book(String msg) {
System.out.println(msg);
}
}
public class Person {
Book book1 = new Book("book1成员变量初始化");
static Book book2 = new Book("static成员book2成员变量初始化");
public Person(String msg) {
System.out.println(msg);
}
Book book3 = new Book("book3成员变量初始化");
static Book book4 = new Book("static成员book4成员变量初始化");
public static void funStatic() {
System.out.println("static修饰的funStatic⽅法");
}
public static void main(String[] args) {
Person.funStatic();
System.out.println("****************");
Person p1 = new Person("p1初始化");
}
/**Output
* static成员book2成员变量初始化
* static成员book4成员变量初始化
* static修饰的funStatic⽅法
* ***************
* book1成员变量初始化
* book3成员变量初始化
* p1初始化
*///~
}
在上⾯的例⼦中我们可以发现两个有意思的地⽅,第⼀个是当我们没有创建对象,⽽是通过类去调⽤类⽅法时,尽管该⽅法没有使⽤到任何的类成员,类成员还是在⽅法调⽤之前就初始化了,这说明,当我们第⼀次去使⽤⼀个类时,就会触发该类的成员初始化。第⼆个是当我们使⽤了类⽅法,完成类的成员的初始化后,再new该类的对象时,static修饰的类成员没有再次初始化,这说明,static修饰的类成员,在程序运⾏过程中,只需要初始化⼀次即可,不会进⾏多次的初始化。
回顾了对象的初始化以后,我们再来看static的第三个作⽤就⾮常简单了,那就是当我们初始化static修饰的成员时,可以将他们统⼀放在⼀个以static开始,⽤花括号包裹起来的块状语句中:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。