static修饰符可以修饰属性,方法,代码块
1. 静态属性在静态类中,使用static修饰符的属性,就是静态属性
public class Demo{
static int num;
}
静态属性是属于类的,可以直接使用类名来访问,也可以使用对象访问,推荐使用类名访问。
非静态属性,属于对象,一定要使用对象来访问,没有其他方式
静态属性,是属于类的,并且是这个类的所有对象共享的
package toto2.静态抽象内部类7;
public class Demo {
static int num;
public static void main(String[] args) {
Demo.num = 10;
Demo demo1 = new Demo();
Demo demo2 = new Demo();
System.out.println(demo1.num);//输出结果为 10
System.out.println(demo2.num);//输出结果为 10
Demo.num = 20;
System.out.println(demo1.num);//输出结果为 20
System.out.println(demo2.num);//输出结果为 20
demo1.num = 30;
System.out.println(demo1.num);//输出结果为 30
System.out.println(demo2.num);//输出结果为 30
}
}
静态属性的存储位置:
类中的静态属性,跟随着类,一起保存在内存中的方法区。当对象创建的时候,对象中只会保存类中定义的非静态属性,静态属性是不会进入到对象中的。
静态属性的初始化:
- 非静态属性:创建后系统会自动给对象中的非静态属性做初始化默认值,所以非静态属性只有在创建后,使用对象才能访问。
- 静态属性:类加载到内存中(方法区)的时候,系统就会给类中的静态属性做初始化默认值。即使还没有创建对象,只要这个类加载到了内存,就可以直接使用类名来访问静态属性,因为 这个时候静态属性已经完成了初始化赋默认值的操作。
注意1, Demo类,被加载到内存的时候,静态属性num已经完成了默认的初始化赋值操作
注意2, 可以通过类名(Demo.num)来访问,它可以直接找到方法区中存储的静态变量num
注意3, 可以通过对象(demo.num)来访问,引用demo先找到堆区中的对象,再根据对象中存储的 Demo.class信息,找到方法区中存储的静态变量num
注意4,通过上述可知,无论使用类名还是使用对象来访问静态变量num,都是访问的同一个num,但是 官方推荐的是使用类名来访问更加合适。
记录一个类在一段时间内,一共创建了多少个对象?
package toto2.静态抽象内部类7;
public class DemoCount {
public static int count;
public DemoCount() {
count++;
}
public static void main(String[] args) {
DemoCount demoCount1 = new DemoCount();
DemoCount demoCount2= new DemoCount();
DemoCount demoCount3 = new DemoCount();
DemoCount demoCount4 = new DemoCount();
DemoCount demoCount5 = new DemoCount();
System.out.println(count);
System.out.println(DemoCount.count);
}
}
2. 静态方法
在类中,使用static修饰的方法,就是静态方法
静态方法的调用
可以使用类名来调用,也可以使用对象来调用,但推荐使用类名:
package toto2.静态抽象内部类7;
public class Demo2 {
public String num;
public static void test() {
// this.name=10;//编译报错
// this.sayHello();//编译报错
System.out.println("haah");
}
public static void main(String[] args) {
Demo2.test();
Demo2 demo2 = new Demo2();
demo2.test();
}
public void sayHello() {
}
}
静态方法不能调用类中的非静态方法或非静态属性
类加载的时候,JVM会优先给类中的静态属性做初始化,给类中的静态方法分配内存空间。
而类中非静态属性的初始化,非静态方法的分配空间,是要等到创建对象之后才会进行的。 所以类加载完成之后,就可以直接使用类名访问静态属性和静态方法。
所以创建对象之后,才可以使用对象访问非静态属性和调用非静态方法。
但是在类加载完成的时候,往往在内存中,还没有创建这个类的对象,没有对象(也就没有this)就不能 访问类中的非静态属性和非静态方法。
正是因为这个原因,在静态方法中,才不能直接调用类中非静态属性和非静态方法。
3. 静态代码块静态代码块,也叫做静态初始化代码块,它的作用就是给类中的静态属性做初始化的
package toto2.静态抽象内部类7;
import java.net.Socket;
public class StaticTest {
public static int num;
public static int id;
public StaticTest() {
//在构造器中初始化静态变量,值为零,因为static与类一起生成
id=10;
}
static {
num=10;
}
public static void main(String[] args) {
System.out.println(StaticTest.num);
System.out.println(StaticTest.id);
}
}
静态代码块的执行时刻:
由于静态代码块没有名字,所以我们不能主动调用,会在类加载的时候,会自动执行,所以静态代码块,可以很早的给类中多的静态属性进行属性赋值操作。并且,静态代码块只会自动被执行一次,因为jvm在一次运行中只会对类加载一次。
匿名代码块:
和静态代码块类似,非静态代码块,作用是给非静态属性做初始化操作
package toto2.静态抽象内部类7;
public class Demo3 {
public int num;
{
num=10;
}
public static void main(String[] args) {
Demo3 demo3 = new Demo3();
System.out.println(demo3.num);
}
}
注意,类中的构造器,既能给非静态属性进行初始化,又能配合new关键字进行对象的创建,所以匿名 代码块使用的场景较少,它能完成的工作,使用构造器也一样可以完成。
匿名代码块执行的时刻:
由于匿名代码块没有名字,我们并不能主动调用,它会在创建对象的时候,构造器执行之前,自动执 行。 并且每次创建对象之前,匿名代码块都会被自动执行。
package toto2.静态抽象内部类7;
public class Demo4 {
static {
System.out.println("静态代码块走了");
}
{
System.out.println("匿名代码块走了");
}
public Demo4() {
System.out.println("构造器走了");
}
public static void main(String[] args) {
new Demo4();
new Demo4();
}
}
//结果
静态代码块走了
匿名代码块走了
构造器走了
匿名代码块走了
构造器走了
创建和初始化对象的过程:
Student s=new Student();
- 对Student类进行类加载,同时初始化类中静态的属性默认值,给静态方法分配内存空间
- 执行类中的静态代码块
- 堆区中分配对象的内存空间,同时初始化对象中的非静态的属性默认值
- 调用Student类的父类构造器
- 对Student中的属性进行显示赋值
- 执行匿名代码块
- 执行构造器代码
- =号赋值操作,把对象的内存地址赋值给变量s
package toto2.静态抽象内部类7;
public class Persfainon {
private String name="toto";
public Person() {
System.out.println("Person构造器");
print();
}
public void print() {
System.out.println("Person print方法"+name);
}
}
class Student extends Person{
public static String name="toto1";
{
System.out.println("Student匿名代码块");
}
static {
System.out.println("Student静态代码块");
}
public Student() {
System.out.println("Student的构造器");
}
public void print() {
System.out.println("student print方法"+name);
}
public static void main(String[] args) {
new Student();
}
}
测试类:
package toto2.静态抽象内部类7;
public class Test {
public static void main(String[] args) {
new Student();
}
}
//结果:
Student静态代码块
Person构造器
student print方法toto1//当Student类中成员变量为private时,输出student print方法null
Student匿名代码块
Student的构造器
4. final
final修饰符,可以用来修饰类,变量,方法
1.修饰类用final修饰的类不能被继承,这个类没有子类
2. 修饰变量用final修饰过后的变量就变成了常量,并且只能给它赋值一次,第二次赋值会报错
final修饰局部变量
final修饰非静态成员变量
public class Person{
private final int a;
}
这个final成员变量,只有一次赋值的机会
jvm不在为其进行默认赋值,需要手动赋值:
- 声明的同时赋值
- 匿名代码块中赋值
- 构造器中赋值,只是还有额外要求:类中出现的所有构造器都要赋值,否则报错
final修饰静态成员变量
public class Person {
private static final int a;
}
- 声明的时候赋值
- 静态代码块的时候赋值
final修饰引用类型变量
package toto2.静态抽象内部类7;
public class Student1 {
private String name="toto";
public Student1() {
super();
}
public Student1(String name) {
super();
this.name = name;
}
@Override
public String toString() {
return "Student1 [name=" + name + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
final Student1 s = new Student1();
System.out.println(s);
//编译通过,可以修改s指向对象中的属性值
s.setName("haha");
System.out.println(s);
s.setName("heihei ");
System.out.println(s);
// s=new Student1();//报错
}
}



