目录
static关键字作用
1.static修饰成员变量
成员变量和静态变量的区别?
2.static修饰方法
3.static修饰代码块(静态代码块)
4.加载顺序
5.静态什么时候用?
被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
static可以用来修饰类的成员方法、类的成员变量,另外也可以编写static代码块来优化程序性能
static关键字: 用于修饰成员( 成员变量和成员函数) 。
被修饰后的成员具备以下特点:
1、 随着类的加载而加载。
2、 优先于对象存在。
3、 被所有对象所共享。
4、 可以直接被类名调用
static变量也称为静态变量,静态变量和非静态变量的区别:
静态变量被所有对象共享,在内存中只有一个副本,在类初次加载的时候才会初始化
非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响
当程序中使用了static关键字进行定义之后,那么此属性将不会保存在堆内存里面,会保存在一个全部数据区的内存空间之中.
静态成员属性对象也可以进行修改,修改后所有的对象的属性都发生变化
:
01. class Person{
02. //成员变量, 实例变量
03. String name;
04. //静态变量, 类变量
05. //所有对象共享的属性用static修饰
06. static String country = "CN";
07. public void show(){
08. System.out.println(country + ":" + name);
09. //等效语句: System.out.println(Person.country + ":" + this.name);
10. }
11. }
12.
13. class StaticDemo{
14. public static void main(String[] args){
15. Person p = new Person();
16. System.out.println(p.country);
17. //可以用类名直接调用
18. System.out.println(Person.country);
19. }
20. }
1.两个变量的生命周期不同
成员变量随着对象的创建而存在, 随着对象被回收而释放。
静态变量随着类的加载而存在, 随着类的消失而消失。
2.调用方式不同
成员变量只能被对象调用。
静态变量可以被对象调用, 还可以被类名调用。
3.别名不同
成员变量也称为实例变量。
静态变量也称为类变量。
4.数据存储位置不同
成员变量存储在堆内存的对象中, 所以也叫对象的特有数据。
静态变量数据存储在方法区( 共享数据区) 的静态区, 所以也叫对象的共享数据。
// 所有的static方法不允许调用非static定义的属性或方法。
// 所有的非static方法允许访问static属性或方法
//
// 因为所有的static方法可以在没有实例化对象的时候访问,而所有的非static方法在有实例化对象产生之后才可以操作。
// 一个对象如果对静态属性做了改变,其他的对象都会受到影响。
//static修饰成员方法最大的作用,就是可以使用"类名.方法名"的方式操作方法,避免了先要new出对象的繁琐和资源消耗
public static void setCountry(String c) {
//this.country = country;这样调用报错,因为country是静态属性,this代表对象,此时可能还没有this
// country = country; //这样使用同名的参数与类属性不好
country = c;
//getInfo();//报Non-static method 'getInfo()' cannot be referenced from a static context
}
1.静态方法只能访问静态成员, 如果访问非静态成员, 就会报错
2.静态方法中不可以写this, super关键字。
原因: 静态方法存在的时候, 对象还不存在
随着类的加载而执行, 而且只执行一次。
作用: 用于给类进行初始化。提升程序性能
很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行
静态初始化块可以置于类中的任何地方,类中可以有多个静态初始化块。
在类初次被加载时,会按照静态初始化块的顺序来执行每个块,并且只会执行一次。
public class Test extends Base{
static{
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
public static void main(String[] args) {
new Test();
}
}
class Base{
static{
System.out.println("base static");
}
public Base(){
System.out.println("base constructor");
}
}
base static
test static
base constructor
test constructor
分析下这段代码的执行过程:
找到main方法入口,main方法是程序入口,但在执行main方法之前,要先加载Test类
加载Test类的时候,发现Test类继承Base类,于是先去加载Base类
加载Base类的时候,发现Base类有static块,而是先执行static块,输出base static结果
Base类加载完成后,再去加载Test类,发现Test类也有static块,而是执行Test类中的static块,输出test static结果
Base类和Test类加载完成后,然后执行main方法中的new Test(),调用子类构造器之前会先调用父类构造器
调用父类构造器,输出base constructor结果
然后再调用子类构造器,输出test constructor结果
public class Test {
Person person = new Person("Test");
static{
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
public static void main(String[] args) {
new MyClass();
}
}
class Person{
static{
System.out.println("person static");
}
public Person(String str) {
System.out.println("person "+str);
}
}
class MyClass extends Test {
Person person = new Person("MyClass");
static{
System.out.println("myclass static");
}
public MyClass() {
System.out.println("myclass constructor");
}
}
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor
为什么输出结果是这样的?我们来分析下这段代码的执行过程:
总结:一个类的加载顺序:静态代码块--初始化成员变量--执行构造函数
1.静态变量
当分析对象中所具备的成员变量的值都是相同时, 这时这个成员就可以被静态修饰。
只要数据在对象中都是不同的, 就是对象的特有数据, 必须存储在对象中, 是非静态的。
如果是相同的数据, 对象不需要做修改, 只需要使用即可, 不需要存储在对象中, 定义成静态的。
2.静态函数
函数是否用静态修饰, 就参考一点, 就是该函数功能是否需要访问到对象中的特有数据。
简单点说, 从源代码看, 该功能是否需要访问非静态的成员变量, 如果需要, 该功能就是非静态的。
如果不需要, 就可以将该功能定义成静态的。 当然, 也可以定义成非静态, 但是非静态需要被对象调用。
如果没有访问特有数据的方法, 该对象的创建是没有意义。
示例