目录
前言
✏️static关键字
1.static修饰成员变量
1.1 调用static修饰的成员变量
2. static修饰成员方法
3.static修饰的成员在内存中的位置
✏️代码块
1.普通代码块
2.构造代码块
3.静态代码块
前言
我的JavaSE语法专栏地址,可以看看哦,可能你会有不一样的收获。JavaSE_会飞的阿喵的博客-CSDN博客https://blog.csdn.net/che__dan/category_11970438.html?spm=1001.2014.3001.5482
JavaSE语法(6)——【类和对象(类的内存模型、访问限定符public、private等、包的导入……)】_虾料的博客-CSDN博客https://blog.csdn.net/Che__dan/article/details/127669373?spm=1001.2014.3001.5501 上一篇文章中static关键字还没有介绍,不过放心,本篇给大家介绍清楚。
在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对象,是所有对象所共享的。
static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。
咱们先来看看案例:假如你是2022年级5班的一名同学。现在你有班级、姓名、性别、年龄这四种属性,同时你的同学也有这四种属性。我们是否就可以定义一个这样的类:
public class Student {
String s_class;
String name;
String sex;
int age;
public Student(){
}
public Student(String s_class, String name, String sex, int age) {
this.s_class = s_class;
this.name = name;
this.sex = sex;
this.age = age;
}
public void print(){
System.out.println("s_class: " + s_class + "name: " + name + " sex: " + sex + " age: " + age);
}
}
每一个同学的信息都可以实例化一个对象来表示。但是如果5班有60位同学,那么我们就需要对s_class赋值50次,且每次都是同一个值。那么我们这么解决这个问题?
我们可以把s_class变为一个静态的s_class:
public class Student {
static String s_class;
String name;
String sex;
int age;
public Student(){
}
public Student(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public void print(){
System.out.println("s_class: " + s_class + " name: " + name + " sex: " + sex + " age: " + age);
}
}
我们实例化几个对象,并对s_class进行赋值:
public class Main{
public static void main(String[] args) {
Student.s_class = "5班";
Student s = new Student("小明","男",19);
Student s2 = new Student("小花","男",20);
Student s3 = new Student("李四","男",21);
Student s4 = new Student("张三","男",20);
s.print();
s2.print();
s3.print();
s4.print();
}
}
结果:
s_class: 5班 name: 小明 sex: 男 age: 19
s_class: 5班 name: 小花 sex: 男 age: 20
s_class: 5班 name: 李四 sex: 男 age: 21
s_class: 5班 name: 张三 sex: 男 age: 20
这里的5班是这个类的属性,是每个实例对象所共有的,当s_class被修改了一次,那么对所有该类的对象都生效。
上面的“Student.s_class”是什么意思呢?其实就是调用这个变量,具体的在。
static变量可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问。
pubic class Main{
public static void main(String[] args) {
//通过类名访问并修改
Student.s_class = "5班";
Student s = new Student("小明","男",19);
Student s2 = new Student("小花","男",20);
Student s3 = new Student("李四","男",21);
Student s4 = new Student("张三","男",20);
s.print();
s2.print();
s3.print();
s4.print();
}
}
class Main{
public static void main(String[] args) {
//通过对象访问并修改
Student s = new Student("小明","男",19);
s.s_class = "5班";
Student s2 = new Student("小花","男",20);
Student s3 = new Student("李四","男",21);
Student s4 = new Student("张三","男",20);
s.print();
s2.print();
s3.print();
s4.print();
}
}
以上都是同一个结果。
s_class: 5班 name: 小明 sex: 男 age: 19
s_class: 5班 name: 小花 sex: 男 age: 20
s_class: 5班 name: 李四 sex: 男 age: 21
s_class: 5班 name: 张三 sex: 男 age: 20
总结:
public class Student {
static String s_class = "5班";
//........
//.......
//.....
}
class Main{
public static void main(String[] args) {
//生命周期开始
System.out.println(Student.s_class);
}
//生命周期结束
}
结果:5班
同样的道理,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的,其调用方法也是通过类名来调用(当然也可以用具体的对象来调用)。
比如:
public class MyMath {
public static int add(int a,int b){
return a + b;
}
}
///
public class Main3{
public static void main(String[] args) {
int c = 10;
int d = 50;
//用类名访问
int sum = MyMath.add(c,d);
System.out.println(sum);
//用对象访问
MyMath math = new MyMath();
int sum2 = math.add(c,d);
System.out.println(sum2);
}
}
结果:
60
60
总结:
原因很好理解:静态方法是属于整个类的,当class文件加载后就已经存在了;非静态变量要在进行实例化的时候才会创建,已经创建的方法引用未创建的变量,这当然不行。
JavaSE语法(6)——【类和对象(类的内存模型、访问限定符public、private等、包的导入……)】_会飞的阿喵的博客-CSDN博客https://blog.csdn.net/Che__dan/article/details/127669373?spm=1001.2014.3001.5502 在上面的文章中提过在非静态方法中有一个隐藏的参数,即this引用,它是方法的第一个参数。
在静态方法中调用非静态方法时候,对于非静态方法我们肯定得要传入相应的this参数(非静态方法的第一个参数),然而事实是静态方法中无法传入this引用,所以我们无法对非静态方法进行传参。
static方法还有一种用法:我们知道对类的属性进行封装时需要用private修饰符,并且需要相应的get与set方法来修改被封装的属性的值,如下:
public class Student {
private static String s_class;
private String name;
private String sex;
private int age;
//获取s_class
public static String getS_class() {
return s_class;
}
//修改 s_class
public static void setS_class(String s_class) {
Student.s_class = s_class;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
对于s_class字段我们不能用普通方法来对其操作,要用static方法才行。
类信息是装在方法区里,类信息又分为静态与非静态区。具体如下:
public class Cat{
public String name;
public String color;
//猫的叫声
public void meow() {
System.out.println(color + "的" + name + ":喵喵喵~");
}
//.......
//特征
public static String trait = "有四条腿";
//习性
public static void habits(){
System.out.println("喜欢吃鱼");
}
}
///
public class Main{
public static void main(String[] args) {
Cat c = new Cat();
c.name = "小白";
c.color = "白色";
c.meow();
System.out.println(Cat.trait);
Cat.habits();
}
}
这个例子在上一篇文章(JavaSE语法(6))中详细介绍过,我们这里只是加了一个静态区。
static成员随着字节码文件的加载而被加载,当JVM将 Cat.class 加载进内存时静态成员变量就存在了,和字节码一样,位于一块叫做方法区的内存空间中,类成员变量被该类的所有对象所共享。
(ps:注意这里的内存图是jdk1.8之前版本的,之后的版本(包括1.8)静态成员在堆里(静态区在堆里))
(jdk1.8之前)
使用{}定义的一段代码称为代码块。代码块有四种:普通代码块、构造块、静态块、同步代码块,同步代码块是一种多线程保护机制。(ps:由于这个知识点涉及到多线程,这儿就不介绍了,留到多线程介绍。)
定义在方法中的代码块叫普通代码块。
public class Main {
public static void main(String[] args) {
//普通代码块(在main方法中)
{
int x = 250;
System.out.println("执行普通代码块!x = " + x);
}
int x = 100;
System.out.println("我在普通代码块外面!x = " + x);
}
}
结果:
执行普通代码块!x = 250
我在普通代码块外面!x = 100
普通代码块里的变量,只要出了代码块,其生命周期就结束了,所以这里重复定义x没有报错。
在类中定义的代码块叫构造代码块,也叫实例代码块。它作用一般用于初始化类里的成员变量(静态的变量也能初始化,但不推荐)。
public class Student {
private String name;
private int age;
private static String s_class;
public Student (){
System.out.println("我是Student的构造方法!!!");
}
//构造代码块(实例代码块)
{
this.name = "张三";
this.age = 20;
s_class = "5班";
System.out.println("我是构造代码块(实例代码块)!!!");
}
public void print(){
System.out.println("name:"+name+"age:" + age + "s_class:" + s_class);
}
}
/
public class Main2{
public static void main(String[] args) {
Student student = new Student();
student.print();
}
}
结果:
我是构造代码块(实例代码块)!!!
我是Student的构造方法!!!
name:张三age:20s_class:5班
注意这里的执行顺序!这里的执行顺序是实例代码块先于构造方法 执行。
使用static定义的代码块称为静态代码块,一般用于初始化静态成员变量。
public class Student {
private String name;
private int age;
public static String s_class;
public Student (){
System.out.println("我是Student的构造方法!!!");
}
//静态代码块
static {
s_class = "5班";
System.out.println("我是静态代码块!!!");
}
//实例代码块
{
this.name = "张三";
this.age = 20;
System.out.println("我是构造代码块(实例代码块)!!!");
}
public void print(){
System.out.println("name:"+name+"age:" + age + "s_class:" + s_class);
}
}
/
public class Main2{
public static void main(String[] args) {
String str = Student.s_class;
System.out.println(str);
}
}
结果:
我是静态代码块!!!
5班
那我new一个实例的时候呢?
public class Student {
private String name;
private int age;
public static String s_class;
//构造方法
public Student (){
System.out.println("我是Student的构造方法!!!");
}
//构造代码块(实例代码块)
{
this.name = "张三";
this.age = 20;
System.out.println("我是构造代码块(实例代码块)!!!");
}
//静态代码块
static {
s_class = "5班";
System.out.println("我是静态代码块!!!");
}
public void print(){
System.out.println("name:"+name+"age:" + age + "s_class:" + s_class);
}
}
/
public class Main2{
public static void main(String[] args) {
Student student = new Student();
student.print();
System.out.println("#################################");
Student student2 = new Student();
student2.print();
}
}
结果:
我是静态代码块!!!
我是构造代码块(实例代码块)!!!
我是Student的构造方法!!!
name:张三age:20s_class:5班
#################################
我是构造代码块(实例代码块)!!!
我是Student的构造方法!!!
name:张三age:20s_class:5班
public class Student {
private String name;
private int age;
public static String s_class;
//构造方法
public Student (){
System.out.println("我是Student的构造方法!!!");
}
//构造代码块(实例代码块)
{
this.name = "张三";
this.age = 20;
System.out.println("我是构造代码块(实例代码块)!!!");
}
//静态代码块
static {
System.out.println("我是静态代码块A!!!");
}
static {
System.out.println("我是静态代码块B!!!");
}
static {
System.out.println("我是静态代码块C!!!");
}
}
/
class Main2{
public static void main(String[] args) {
Student student = new Student();
System.out.println("#################################");
Student student2 = new Student();
}
}
结果:
我是静态代码块A!!!
我是静态代码块B!!!
我是静态代码块C!!!
我是构造代码块(实例代码块)!!!
我是Student的构造方法!!!
#################################
我是构造代码块(实例代码块)!!!
我是Student的构造方法!!!