栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

static以及final的知识点

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

static以及final的知识点

静态 Static

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();//报错
		
	}

}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/489741.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号