文章目录
- 一、什么是static成员
- 二、static修饰的成员有何意义
- 三、static修饰成员变量
- 四、static修饰成员方法
- 4.1、静态成员变量不可以在方法内创建
- 4.2、静态成员方法内部不可以访问非静态成员变量
- 4.3、总结
- 五、static成员变量的初始化
- 5.1、就地初始化
- 5.2、静态代码块初始化
- 六、代码块
- 6.1、普通代码块
- 6.2、构造代码块
- 6.3、静态代码块
- 6.4、总结
一、什么是static成员
在Java的类中一般定义有成员属性,以及成员方法两种,但实际上两种可以算为一类,但还可以定义另外一种,就是被static修饰的变量和方法,被static修饰的变量称之为静态变量,也可以叫类变量;被static修饰的方法被称之为静态方法,也可以叫类方法。
被static修饰的成员,最大的特性就是其不属于对象,不依靠对象,这也就意味着被static修饰的成员在没有实例化对象的情况下就可以使用,被static修饰的成员其属于类,是所有对象所共享的,可以直接使用类名访问并调用。随着类的加载而创建并执行有关于static的成员变量,成员方法,静态代码块,静态成员变量可以理解为类的属性,静态成员方法可以理解为类的行为
二、static修饰的成员有何意义
当我们在定义一个学生类的时候,我们想要找到并抽象出学生类的成员变量以及成员方法,从而定义的类能够描述出学生这么一个对象,经而实例化才可以真正的在程序世界里面形成一个学生实体。
public class Sdutent {
private String name;
private int age;
private String classRoom;
public Sdutent(String name, int age, String classRoom) {
this.name = name;
this.age = age;
this.classRoom = classRoom;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getClassRoom() {
return classRoom;
}
public void setClassRoom(String classRoom) {
this.classRoom = classRoom;
}
}
public static void main(String[] args) {
Sdutent sdutent1 = new Sdutent("小明",10,"405");
Sdutent sdutent2 = new Sdutent("小红",13,"405");
Sdutent sdutent3 = new Sdutent("小李",9,"405");
}
代码中sdutent1,sdutent2,sdutent3,三个对象,每个对象都有自己的姓名,年龄,班级,但是当三个同学都属于同一个班级是的时候,每个学生对象中都含有一个相同的成员变量,那么在堆中就需要为每个对象的班级开辟空间,但是在三个对象空间中都有一个相同的内容,当学生对象的数量很多的时候,对于内存的利用率大大降低,不同的对象中都有一个的空间存储的内容都是相同的,那不就相当于用不同的空间存储相同的内容,内存的利用率从而下降。
那么我们如何节省内存空间的使用呢?此时static的作用就显示出来了,我们可以把成员变量classRoom定义为静态变量,此时我们只需要将该变量直接定义为某个班级,当我们在实例化对象的时候就不需要再通过对象给班级赋予初始值,直接给其他的信息赋予初始值即可。
此时对象的堆栈图:
此时我们就通过将classRoom变量定义为静态变量从而节省了堆空间的消耗,提高了内存利用率。
三、static修饰成员变量
static修饰的成员变量称之为静态成员变量,又称类变量,静态成员变量最大的特性就是:不属于任意一个对象,是所有对象共享的。
1、不属于任意对象的成语,是类的属性,是所有对象共享的,不存储在某个对象的空间内
2、既可以通过对象访问也可以通过类名访问,但一般建议通过类名访问
3、类变量存储在方法区当中,不存储在堆中
4、静态成员变量的生命周期伴随类的一生,当类被加载时,静态成员变量也被创建,类被销毁时,静态成员变量也被销毁
对于静态成员变量来说,它本质上是属于类的,不属于对象,通过类名进行访问,但是通过对象进行访问也是可以的,但是并不合理,因为静态成员变量它是属于类的,而对象是通过类实例化创建的,从某个层次来说,静态成员变量和对象应该是同等级的,类是两者的上一等级,同等级之间应该是无法互相调用访问的,应该是通过上一等级调用访问下一等级,所以说通过对象进行调用访问是不合理的
四、static修饰成员方法
既然成员变量可以被修饰为静态成员变量,那么成员方法也可以被修饰为静态成员方法。
public static String getclssRoom1() {//静态成员方法
return classRoom;
}
被static修饰的成员方法被称之为静态成员方法,是类的方法,不是某个对象所特有的,静态成员一般通过类名进行访问
但是需要注意的有几点:
4.1、静态成员变量不可以在方法内创建
在方法内创建的变量叫做局部变量,被static修饰的变量叫做静态成员变量。
第一:两者都生命周期不同,静态成员变量的生命周期和类的生命周期相同,局部变量的生命周期和方法的生命周期相同,当方法结束运行时在方法内定义的局部变量也会被JVM回收。
第二:两者的创建时间不同,静态成员变量随着类的加载而创建,局部变量随着方法的调用而开始创建,并且静态成员变量一般情况下在一个工程中只会创建一次,因为在一个工程中对象一般不会销毁,这也就意味着静态成员变量只会创建一次,而基本变量不同,一个方法在一个工程中有可能会只调用,也可能会调用多次,无论该方法调用多少次,只要该方法调用,基本变量就会创建,所以局部变量和静态成员变量两者的区别就在于:局部变量可以创建多次,但静态变量只会创建一次。
第三:两者都加载顺序不同,静态成员变量随着类的加载而创建,而局部变量需要通过对象的调用才可以创建,这也就意味着在没有实例化的情况下只要加载类,静态变量就会创建,即便在实例化对象的情况下,如果对象不调用方法,那么局部变量就不会创建。如果令对象等于null时:
Sdutent sdutent = null;//对象等于null
sdutent.getclssRoom2();//调用普通成员方法
sdutent.getclssRoom1();//调用静态成员方法
该代码表示引用sdutent不指向任何对象,此时通过该引用调用成员方法时,系统会报错,但是可以调用静态成员方法,因为静态成员不依赖于对象,并且静态成员随着类的加载而创建,不管引用是否正常指向对象,都不会影响到静态成员。即便对象没有实例化完成,只要类被加载了,都是可以同过类创建的引用去调用静态方法,所以类引用是否正常指向实例化对象,都不影响类引用调用静态方法
所以在Java里面静态成员变量只能在类内创建,不能在方法内创建,在方法内创建的是局部变量,包括在静态方法内创建的也是局部变量,这也就意味着:静态成员变量只能在类内方法外创建。
4.2、静态成员方法内部不可以访问非静态成员变量
非静态成员变量需要通过对象的引用才能够调用,在调用成员方法的时候,编译器会自动将对象的引用传递给方法,this进行接收,this相当于对象的引用,在方法内部会有隐藏的this进行实际访问成员变量
但是静态成员是不依靠对象的,这也就意味着:在调用静态成员方法的时候,因为是直接通过类名调用的,编译器不会将对象引用传递给方法,那就没有办法通过引用访问成员变量。所以在静态成员方法中是没有办法访问非静态成员的,但是在非静态成员方法中是可以访问静态成员的。
静态成员方法内不能访问非静态成员
非静态成员方法内可以访问静态成员
4.3、总结
总结:
1、静态成员方法不属于某个对象,是类方法
2、可以通过对象调用,也可以通过类名调用,但是更推荐通过类名调用
3、不能在静态方法中访问任何非静态成员变量
4、静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时无法传递this参数
五、static成员变量的初始化
静态成员变量一般不会通过构造方法进行初始化,构造方法中初始化的是与对象相关的实例属性
静态成员变量的初始化分为两种:就地初始化 和 静态代码块初始化
5.1、就地初始化
就地初始化是指在定义该变量的时候直接赋予初始值
private String name;
private int age;
public static String classRoom = "405班";
5.2、静态代码块初始化
六、代码块
使用{ }包围起来的叫做代码块,根据代码块定义的位置以及关键字可分为以下几种:
1、普通代码块
2、构造代码块
3、静态代码块
4、同步代码块
6.1、普通代码块
普通代码块:没有任何关键字修饰,直接使用{ }的代码块
public class MAin {
public static void main(String[] args) {
{
int i = 0;
String str = "不哈哈哈";
System.out.println("xixi");
}
}
和普通的方法一样,在{ }定义的变量属于局部变量,出了{ }内部的变量同样会被销毁。
6.2、构造代码块
构造代码块:定义在类中的代码块,同样是没有任何关键字修饰,只有{ }包围的代码,构造代码块也被称之为实例代码块。
与普通代码块不同的是,构造代码块是定义在类中的,并且一般用于初始化成员变量,普通代码块不一定是在类中定义的,只能说普通代码块里面包含有构造代码块。
构造代码块实际上既可以初始化成员变量也可以初始化静态成员变量,但一般用于初始化成员变量,静态成员变量一般用静态代码块初始化。
需要注意的是:构造代码块先执行,然后才会执行构造方法,构造代码块实际上可以理解为一种默认的初始化, 因为当我们使用了构造代码块的时候,构造代码块里面的成员变量就已经固定了,除非我们更改代码,否则在调用默认无参构造方法的情况下,每次实例化对象,对象的数据都是构造代码块的数据,此时我们想要定义不同数据的代码块时,就可以通过构造方法,在重载构造方法的情况下调用含参的构造方法,从而达到实例化不同数据的对象的目的。
这也就意味着:构造方法的数据会将构造代码块的数据覆盖掉,但是Java默认提供的无参构造方法不会将构造代码块的数据覆盖。
6.3、静态代码块
使用static修饰的{ },称之为静态代码块,一般用于初始化静态成员变量。
private String name;
private int age;
public static String classRoom;
static {
classRoom = "405班";
}
静态代码块在整个工程中,只会调用一次,无论实例化多少个对象,静态代码块只会在第一次实例化对象的时候调用。
如图,实例化4个对象,静态代码块只调用了一次
并且仔细观察可以发现,静态代码块优先执行与构造代码块
因为有关于static的东西,比如静态成员变量,静态成员方法,静态代码块,都是随着类的加载而创建或者实行的,在类被加载的时候,静态成员变量被定义了,随后就是静态方法也被加载了,但是不会直接给静态方法开辟空间,只有当静态方法被调用的时候JVM才会为其开辟空间,随后就是执行静态代码块。和静态成员变量一样,不论是否实例化了对象还是仅通过类创建引用但没有指向对象,只要使用了类,类就会被加载,被加载的过程中有关于静态的都会被执行。
6.4、总结
1、静态代码块不管生成多少个对象,其都只会实行一次
2、静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
3、如果一个类中包含有多个静态代码块或者构造代码块,在编译代码的时候,编译器会按照定义的顺序依次执行。 因为类中定义的静态代码块相当于同一等级到代码,没有执行的先后顺序,编译器就会按照定义的顺序依次执行,构造代码块也是如此。
4、实例代码块只有在实例化对象时才会执行。 当通过类创建类类型的引用时,如果没有通过new关键字实例化对象,那么构造代码块一样不会执行
5、先执行静态代码块,然后执行构造代码块,最后执行构造方法。