前言:本人作为一名刚进入java一段时间的菜鸟,觉得java中这些修饰符中,static与final还是比较难懂的,所以在这里写下这篇博客,供大家学习与讨论,
一、首先是static关键字吧。
首先static可以修饰变量、常量、方法还有静态语句块,下面,我会用代码来介绍一下
①静态变量
public class Person {
static int age;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
Person.age = 16;
}
}
可以看出静态变量是可以直接被类名直接调用的,不需要创建对象去调用(当然也可以)
1. 可以直接被类名调用原因:静态变量是在类加载时初始化的
2. 不需要创建对象去调用原因:静态变量会在该类的任何对象创建之前就完成了初始化
还有静态变量会在该类的任何静态方法执行之前就完成初始化
------------------------------------------------------------------------------------
public class Person {
static int age;
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
p1.age = 16;
System.out.println(p2.age);//16
}
}
也可以看出静态变量是共享的,同一类的所有实例共享一份静态变量
这里和实例变量区别一下吧:实例变量(每个实例一个),静态变量(每个类一个)
②静态常量我放在后面和final一起说吧
③静态方法,同样可以直接访问,其不能访问非静态的属性,也不能使用this
原因:静态方法是在无关特定类的实例情况下执行的,没对象,所以不能使用this
我还在一本书上看这样解释的,生命周期去理解,静态优先于费静态存在于内存中,静态是前人而非静态是后人
public class Person {
public static void a() {
System.out.println("静态方法a");
}
public static void main(String[] args) {
a();//静态方法a
Person.a();//静态方法a
}
}
④静态代码块
public class Person {
static{
System.out.println("静态代码块");
}
public void a() {
System.out.println("实例方法a");
}
public static void main(String[] args) {
Person p = new Person();
p.a();
}
}
输出结果:
静态代码块
实例方法a
这个想必大家都知道,静态代码块,类加载就会执行,并且只会执行一次,自上而下进行,而且要在构造方法之前执行
二、final修饰符
final可以理解为最终、不可变
final可以修饰类、方法、局部变量、成员变量、数据类型,下面我分开说明
①修饰类,这个类不能被继承,不能定义为抽象类;可以理解为最终类
public final 类名
②修饰方法:无法被重写,不能被定义为抽象类
③修饰局部变量:一旦赋值,就无法修改
④修饰成员变量:因为必须在对象存在时给定值,所以必须初始化,所以这里就存在两种情况,一是在声明时給值或者在构造方法給值;这里区分下:
1.在声明时给值,产生的对象的该变量的值全部相等并且不能改变
2.在构造方法中赋值产生的结果是不同的对象可以有该变量的不同值并且不能改变
那么有些同学可能会问,为什么不能调用set方法给其赋值?原因很简单,构造器的赋值是在创建对象的时候赋值,用set方法,是在创建对象之后赋值,所以不能这样赋值呀
上面static部分没有说常量,这里说一下吧
static final 类型 变量 = 初始值;这里,必须在声明的时候赋值,原因自己想的:
逆推法:假设在构造方法赋值,首先考虑static,那么这个值就变成了公共的(一个修改会影响另外一个),那么再加上final(不变的),在构造方法里肯定不能同时满足以上条件。反之,在声明的时候则可以。
*⑤修饰的基本数据类型,值不能改变;修饰的引用数据类型,地址不能改变,但是对象里面的值是可以改变的(这里比较重要,用代码解释下)
public class Test {
public static void main(String[] args) {
final Person p1 = new Person("张三",18);
p1 = new Person("李四",19);//报错的:无法分配最终的局部变量P1。它必须是空白的,不使用复合赋值
}
}
上面证明了,引用数据类型,地址是不能改变的
public class Test {
public static void main(String[] args) {
final Person p1 = new Person("张三", 18);
p1.setName("王五");
p1.setAge(20);
System.out.println(p1.getName() + "..." + p1.getAge());// 王五...20
}
}
结果:
王五...20
这里,证明了引用数据类型,其对象里面的值是可以改变的