文章目录
- 🚀文章导读
- 1.1static修饰成员变量
- 1.2static修饰成员方法
- 1.3代码块
- 1.3.1代码块概念及分类以及不同代码块之间的运行顺序
- 1、普通代码块
- 2、构造代码块
- 3、静态代码块
- static存在的意义
- 面试题:
- 1、static的独特之处
- 2、 静态变量和实例变量的区别
- 3、静态方法和实例方法有何不同
🚀文章导读
本篇文章主要讲解了static的作用,和一些代码块的分类,以及它们之间的先后执行顺序
看完本篇文章,需要理解一下几点:
1、static修饰的变量和方法在内存中是如何分配的
2、static修饰的方法如何调用
3、static存在的意义
4、static的独特之处
1.1static修饰成员变量
在java中被static修饰的成员,称为静态成员,也可以称为类成员,不属于某个具体的对象,是所有对象所共享的
什么意思呢?下面通过代码来进行讲解
假如,这里有三个同班的学生,它们分别有自己的名字和年龄,所以在每次实例化一个对象时,都会对每个学生的属性进行一份保存,例如:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Student student1 = new Student("A", 15);
Student student2 = new Student("B", 17);
Student student3 = new Student("C", 20);
}
分别创建了三个学生对象,通过运行可以看出,每个对象中也都保存了一份学生属性
假如设,在类当中设置一个班级属性,因为这三个学生都是一个班的,所以班级肯定也是相同的,假如设置一个classroom,可以看到,三个学生的classroom都是一样的,但是仍然在内存中也保存了三份,这样就有点浪费了,我们只需要保存一份就行了,所以这里就用到了static。
下面用static对classroom进行修饰,static修饰的成员变量也称为静态成员变量
public class Student {
private String name;
private int age;
private static String classroom;
public Student(String name, int age,String classroom) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Student student1 = new Student("A", 15,"111");
Student student2 = new Student("B", 17,"111");
Student student3 = new Student("C", 20,"111");
Student.classroom = "111";//通过类名访问classroom
//student1.classroom = "111";通过对象的引用访问classroom
}
通过以上代码可以看到两个问题:
1、在创建对象时,对象中只有name和age并没有classroom,那classroom保存到了哪里呢?
2、在对static修饰的成员变量进行访问时,有两种方式,具体哪一种比较好呢?
解答1:当实例化一个对象时,对象中会保存类的成员变量,而对象会保存在栈区,但是当用static修饰时,成员变量就会保存在方法区,所以,static修饰的成员变量是不属于某个具体对象的,是所有对象所共享的。
解答2:对static修饰的变量(静态变量)进行访问时,通过:类名==.成员变量 进行访问,也可以通过先实例化一个对象,通过对象的引用进项访问,但是不建议采用后者这种方式,因为,后者是通过对象的引用去访问的,而静态成员是存储在方法区的,是不依靠对象的,所以建议采用类名.==成员变量进行访问。而非静态成员变量的访问是通过对象的引用进行访问的。
静态成员变量的特性
1、不属于某个具体对象,是类的属性,存放在方法区中,是所有对象所共享的,不存储在某个对象的空间中
2、既可以通过对象访问,也可以通过类名访问,但是建议用类名访问
3、生命周期伴随类的一生(随类的加载而创建,随类的销毁而销毁)
1.2static修饰成员方法
一般大多数类中的成员变量都用private修饰,因为这样就对类中的成员进行了很好的隐秘性,是一种封装的体现,而成员方法一般设置成public,那么问题是,被static修饰的成员成员方法要如何进行访问呢?
public class Student {
private String name;
private int age;
public static String classroom;
public void func1() {
System.out.println("这是一个非静态成员方法");
}
public static void func2() {
System.out.println("这是一个静态成员方法");
System.out.println("这是一个静态方法"+this.name);//这个是错误的,不能使用this
}
public static int add(int a, int b) {//static修饰的成员方法
return a+b;
}
public static void main(String[] args) {//静态成员方法
System.out.println(add(5, 3));//直接调用静态成员方法
Student.func2();
Student stu = new Student();//实例化一个对象
stu.func1();//通过对象的引用对非静态方法进行访问
func1();//这个是错误的,不能直接调用非静态方法
}
对静态成员方法的访问也是通过类名==.==方法名 进行访问的,在静态方法中去调用静态方法时,如果被调用的静态方法有返值,那么是可以直接调用的,如果没有返回值的话需要通过类名==.==方法名进行调用,但是,是不可以直接对非静态方法进行调用的,需要先实例化一个对象,通过对象的引用访问非静态方法。注意,在静态方法中,也不可以使用this,因为静态方法是不依赖对象的。所以:
总结:
在静态方法中,可以直接调用静态方法,但不能直接调用非静态方法,对于非静态方法的调用,需要先实例化一个对象,通过对象的引用调用非静态方法
在非静态方法中,可以直接调用静态方法,也可以直接调用非静态方法、
静态方法特性
1、不属于某个具体对象,是类方法
2、可以通过对象调用,也可以通过类名==.==静态方法名()的方式调用,更推荐后者
3、不能在静态方法中直接访问任何非静态成员变量
1.3代码块
1.3.1代码块概念及分类以及不同代码块之间的运行顺序
**使用这种 {} 定义的代码称为代码块。**代码块又分为四种:
1、普通代码块
2、构造块
3、静态块
4、同步代码块
1、普通代码块
public class Student {
public static void main(String[] args) {
{
int x = 30;
System.out.println(x);
}
System.out.println(x);//这样写是错误的
}
普通代码块是定义在方法中的代码块,因为 int x 是定义在代码块内部的局部变量,所以x的生命周期是在代码块内部,出了代码块x就自动销毁了。
2、构造代码块
构造块:定义在类中的代码块。也称为实例代码块,用于初始化实例成员变量
public class Student {
private String name;
private int age;
private String sex;
//构造方法
public Student() {
System.out.println("这是一个构造方法");
}
//构造代码块
{
this.name = "lisi";
this.sex = "男";
this.age = 15;
System.out.println("这是一个构造块");
}
//成员方法
public void show() {
System.out.println("name:"+name+" "+"age"+age+" "+"sex"+sex);
}
public static void main(String[] args) {
Student stu = new Student();
stu.show();
}
通过运行结构可以看到,代码执行时,首先编译了构造代码块,然后执行了构造方法,最后执行了普通的成员方法,所以排一下顺序是:构造代码块->构造方法->成员方法
3、静态代码块
使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量
public class Student {
private String name;
private int age;
private String sex;
private static int weight;
//构造代码块
{
this.name = "lisi";
this.age = 14;
this.sex = "女";
System.out.println("这是一个构造代码块");
}
//静态代码块
static {
weight = 54;
System.out.println("这是第一个静态代码块");
}
static {
System.out.println("这是第二个静态代码块");
}
//构造方法
public Student() {
System.out.println("这是一个构造方法");
}
public void show() {
System.out.println("这是一个成员方法");
System.out.println("name:"+name+" "+"age:"+age+" "+"sex:"+sex+" "+"weight:"+weight);
}
public static void main(String[] args) {
Student stu = new Student();
stu.show();
}
第一种情况:
由上述代码可以看出,当出现静态代码块时,执行的顺序首先是静态代码库,当有多个静态代码时,按照定义的顺序执行,其次是构造代码块,然后是构造方法,最后是成员方法。
第二种情况:
当在main方法中创建两次对象时,处了静态代码块外,其他代码块都执行了第二次,所以可以得出结论,对于静态成员变量,JVM只会在类首次加载时分配一次内存,而不管生成多少个对象,静态代码块都只执行一次。
第三种情况:
public class Student {
private String name;
private int age;
private String sex;
private static int weight;
//构造代码块
{
this.name = "lisi";
this.age = 14;
this.sex = "女";
System.out.println("这是一个构造代码块");
}
//静态代码块
static {
weight = 54;
System.out.println("这是第一个静态代码块");
}
static {
System.out.println("这是第二个静态代码块");
}
//构造方法
public Student() {
System.out.println("这是一个构造方法");
}
public void show() {
System.out.println("这是一个成员方法");
System.out.println("name:"+name+" "+"age:"+age+" "+"sex:"+sex+" "+"weight:"+weight);
}
public static void main(String[] args) {
//Student stu = new Student();
//stu.show();
//System.out.println("===================");
//Student stu1 = new Student();
//stu.show();
}
由上述代码可知,在不创建对象时,只执行了静态代码块,足以证明:静态代码块是在类初次加载时才会被执行,而构造代码块是依赖于对象的,只有创建了对象,构造代码块、构造方法、成员方法才会被执行。
注意事项:
1、实例代码块只有在创建对象时才执行
2、不管生成多少个对象,静态代码块都只执行一次
3、静态成员变量是类的属性,JVM只会在类首次加载时分配一次空间并初始化
4、如果一个类中包含多个静态代码块,在编译时,编译器会按照定义的先后顺序依次执行
static存在的意义
1、static主要的意义是用于创建独立的不依赖于对象的变量和方法。以至于没有创建对象,也能使用属性和调用方法
2、static关键字还有一个比较关键的作用是用来形成静态代码块已优化程序性能,类中可以有多个静态代码块,在类初次加载的时候,会按照static块的顺序执行每个static代码块,并且只会执行一次,只分配一次内存空间,而且是最先运行的
3、为什么说static块可以用来优化程序性能?因为它的特性:只会在类加载的时候执行一次,因次,很多时候会将一些只需要进行一次的初始化操作都放在静态代码快中
面试题:
1、static的独特之处
1、被static修饰的成员变量或方法是独立与该类的任何对象,也就是说这些变量和方法不属于任何一个实例对象,而是被所有对象所共享的
2、在类被加载时,就会去加载被static修饰的部分,而且在类第一次使用时加载并初始化,注意,第一次用就会被初始化,以后根据需要还可以在进行赋值
3、static变量值在类初次加载的时候分配空间,以后创建类对象的时候不会再重新分配。赋值的话是可以任意赋值的
4、被static修饰的变量或者方法是优先与对象存在的,也就是说当一个类加载完毕以后,几遍没有创建对象,也可以去访问
5、常见的static应用场景:1、修饰成员变量,2、修饰成员方法,3、静态代码块,4、修饰类【只能修饰内部类也就是静态内部类】
2、 静态变量和实例变量的区别
静态变量:静态变量不属于任何实例对象,是属于类的,所以在内存中只会有一份,在类的加载过程中,JVM只会为静态变量分配一次内存空间;
实例变量:每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内存中,创建几次对象,就有几份成员变量
3、静态方法和实例方法有何不同
1、调用方式不同:
在外部调用静态方法时,可以使用“类名.方法名“的方式,也可以使用”对象名.方法名“的方式、而实例方法只能使用后者,也就是说,调用静态方法无需实例化对象
2、访问位置有区别
在静态方法中,可以直接访问静态成员,而不能直接访问非静态成员,在实例方法内部则没有此限制