Java零基础(十一)之static和fianl关键词

  1. Static(重点)

java中的五大存储区域:
栈、堆、方法区、寄存器区、本地方法区
寄存器区:主要是线程的存储区域
本地防区:第三方语言的存储区域,例如:c/c++

重点分析三大区域:堆,栈,方法区
栈:存局部变量 (引用对象,基本变量)
堆:new对象,成员属性
方法区:class文件,静态区(static修饰),常量池(字符串常量)-往往方法区的东西只有一份

1.1 静态属性

成员属性案例

class MyClass{
    
    
	int a;  //成员属性
}


public class Test1 {
    
    
	public static void main(String[] args) {
    
    
		MyClass obj1 = new MyClass();
		MyClass obj2 = new MyClass();
		
		obj1.a = 3;
		obj2.a = 5;
		
		System.out.println(obj1.a+"---"+obj2.a);
	}
}

在这里插入图片描述

静态属性案例

实例属性 VS 静态属性
实例属性: 在堆区,属于对象,通过对象调用;每个对象独有的一份
静态属性: 在方法区,属于类,推荐使用类名调用;所有对象共享同一份

class MyC{
    
    
	static int a;
}
public class Test2 {
    
    
	public static void main(String[] args) {
    
    
		MyC obj1 = new MyC();
		MyC obj2 = new MyC();
		
		//The static field MyC.a should be accessed in a static way
		obj1.a = 3;  //MyC.a = 3; 静态属性属于类,推荐通过类名调静态属性
		obj2.a = 5;
		
		System.out.println(obj1.a+"---"+obj2.a);
	}
}



在这里插入图片描述

静态属性课堂案例

//案例: 统计对象new了多少次
//分析: 先编写面向对象; 每new一次,则次数++
class A{
    
    
	static int count;  //初始为0
	public A(){
    
    
		count++;  //使用静态属性进行统计
	}
}
public class Test3 {
    
    
   public static void main(String[] args) {
    
    
	  new A();
	  
	  new A();
	  
	  new A();
	  
	  System.out.println("总共new了"+A.count+"次");
   }
}


1.2 静态方法

静态方法应用


//问题:在静态方法中,能否使用成员属性;--不能  
      //在成员方法中能否使用静态属性?--能  为什么?

//思考: 函数入口为何要这么设计?    public  static void main()
//public:公开权限,使得外部jvm有权限调用
//static:优先加载,无需new对象,提高性能
//void:  无需反馈结果到jvm 

class MyClass{
    
    
	static int a;   //静态属性
	int  b;         //成员属性
	
	//静态方法中不能使用this与super关键字--加载时机问题
	//静态方法可以继承,但不能重写
	public static void test() {
    
      //静态方法
		System.out.println("测试的方法...");
		//加载时机问题,静态区在类加载时就进行加载了,这时还不知道对象属性; 静态区优先对象加载
		//System.out.println(b); 
	}
	
	public void print() {
    
    
		System.out.println(a);
	}
}

class Son extends MyClass{
    
    
	/*@Override   
	public static void test() {  //静态方法,不能重写
	}*/
}
public class Test1 {
    
    
	public static void main(String[] args) {
    
    
		//之前方法调用,因为是调当前类的方法,所有省略了类名的调用
		System.out.println(add(1,2));  //调当前类的方法  等价Test1.add(1,2);
		
		//The static method add(int, int) from the type Test1 should be accessed in a static way
		System.out.println(new Test1().add(3, 5)); //可以通过对象调静态方法,但是不推荐
		
		//调用系统提供的静态方法
		int[] a = {
    
    1,2,3};
		System.out.println(Arrays.toString(a)); //调其他类的方法: 类名.方法
		
		MyClass.test();  //调用自定义类的静态方法
		
		//new Son().test();  //静态方法具有继承性
	}

	//静态方法:属于类,推荐使用类名调用
	public static int add(int a, int b) {
    
    
		return a+b;
	}
}

静态的应用场景

//静态属性和静态方法的应用场景:
//静态属性: 一般作为状态值去使用(往往变量全大写)---固定值,不用更改,直接使用-做逻辑判断
//状态值的好处: 可读性更强 ,可维护性更强(变更数值了,不用每个地方都去改)

//静态方法:作为工具类来使用(工具类:统一供外部调用的公共类;例如:Arrays,所有数组操作的静态方法都放到该类)

class MyC{
    
    
	static int SEX_MAN = 11;  //代表男
	static int SEX_WOMAN = 10;  //代表女
}

public class Test2 {
    
    
	public static void main(String[] args) {
    
    
		Scanner sc = new Scanner(System.in);
		System.out.print("请输入性别:1.男性,0.女性:  ");
		int sex = sc.nextInt();
		if(sex==MyC.SEX_MAN) {
    
    
			System.out.println("你输入的是男性");
		}else if(sex==MyC.SEX_WOMAN) {
    
    
			System.out.println("你输入的是女性");
		}
		
		
		/*
		if(sex==MyC.SEX_MAN) {
			System.out.println("你输入的是男性");
		}else if(sex==MyC.SEX_WOMAN) {
			System.out.println("你输入的是女性");
		}*/
	    	
	}
}


1.3 动态代码块与类加载
动态代码块案例

//动态代码块: 就是类中的一块区域,只要在类中加入{},就是一个代码块;
//通过实例化对象可以触发到动态代码块
//执行流程:
//成员属性>动态代码块>构造方法
//作用: 给属性赋予初始值

//类加载过程:
//jvm根据classpath查找class文件,并将class文件中的所有信息(包名,类名,对象,属性,方法等)加载到内存中
//需要在入口main中触发执行类加载

class MyClass{
    
    
	String a = "成员属性";
	static String b = "静态属性";
	
	{
    
    
		System.out.println(a);
		System.out.println("动态代码块");
	}
	
	public MyClass() {
    
    
		System.out.println("构造方法");
	}
	
	public static void show() {
    
    
		System.out.println("调用静态方法");
	}
}

class Son extends MyClass{
    
    
	
}
public class Test1 {
    
    
	public static void main(String[] args) throws ClassNotFoundException {
    
    
		//new MyClass();  //实例化对象触发
		//new Son();        //实例化子类对象
		//System.out.println(MyClass.b);  //静态属性触发类加载
		//MyClass.show();   //使用静态方法触发类加载
		Class.forName("com.qf.c_statickuai.MyClass");  //加入全限定名,触发类加载-反射后面学
	}
}

静态代码块的执行

//静态代码块的执行:
//先执行静态属性>静态代码块(通过反射触发)
class MyC{
    
    
	static String a = "静态属性";
	//静态代码块
	static {
    
    
		System.out.println(a);
		System.out.println("静态代码块");
	}
	
}

public class Test2 {
    
    
	public static void main(String[] args) throws ClassNotFoundException {
    
    
		Class.forName("com.qf.c_statickuai.MyC");
	}
}

动态代码块与静态代码块

//对象的执行过程(动态代码块+静态代码块):
//规则: 先静态,后动态     静态属性->静态代码块->成员属性->动态代码块->构造方法
//再new一个对象: 再执行一次,成员属性->动态代码块->构造方法
//结论:static与对象无关,静态代码块只加载一次,优先于非静态的执行
class Super{
    
    
	static String a = "父类静态属性";
	String  b = "父类成员属性";
	static {
    
    
		System.out.println(a);
		System.out.println("父类静态代码块");
	}
	
	{
    
    
		System.out.println(b);
		System.out.println("父类动态代码块");
	}
	
	public Super() {
    
    
		System.out.println("构造方法");
	}
}

public class Test1 {
    
    
	public static void main(String[] args) {
    
    
		new Super();  //实例化当前类的构造方法    先静态,后动态
		System.out.println("===============");
		new Super();  //再new一个对象
	}
}

子类的实例化过程

//案例:子类继承Super类,观察子类实例化过程
//规则: 先父类,再子类,先静态,后动态

//执行流程:父类静态属性>父类静态代码块>子类静态属性>子类静态代码块>父类成员属性>父类动态代码块
      // 父类构造方法>子类成员属性>子类动态代码块>子类构造方法
class Son extends Super{
    
    
	static String a = "子类静态属性";
	String b = "子类成员属性";
	{
    
    
		System.out.println(b);
		System.out.println("子类动态代码块");
	}
	
	static {
    
    
		System.out.println(a);
		System.out.println("子类静态代码块");
	}
	
	public Son() {
    
    
		System.out.println("子类构造方法");
	}
}

public class Test2 {
    
    
	public static void main(String[] args) {
    
    
		 new Son();
	}
}
  1. final(重点)

final:表示最终的,可以修饰类,方法,属性
修饰类:最终类(太监类),被final修饰的类不能有子类
修饰方法: 该方法不能被重写
修饰属性: 变量变为了常量,往往在静态属性中final与static配合使用(状态值)-静态常量

//final修饰类,该类不能有子类
/*final*/ class Super{
    
    
	//静态常量必须初始化时要赋值
	//静态常量赋值时机:1.初始时赋值   2.静态代码块
	public final static int COUNT=1;  //状态值往往是不能被改变的,+final修饰则变为了常量
	/*static {
		COUNT = 2;
	}*/

	//成员常量必须初始化时要赋值
	//成员常量赋值时机: 1. 初始时赋值   2.动态代码块   3.构造方法
	public final int d=1;
	/*{
		d = 3;
	}*/
	
	/*public Super() {
		d = 5;
	}*/
	
	
	
	//final修饰方法,该方法不能被重写
	public /*final*/ void test(){
    
    
		
	}
}

//The type Son cannot subclass the final class Super
class Son extends Super{
    
    
	int b;
	@Override
	//Cannot override the final method from Super
	public void test(){
    
    
		
	}
}
public class Test1 {
    
    
	public static void main(String[] args) {
    
    
		//Super.COUNT = 5;  //The final field Super.COUNT cannot be assigned
		
		//基本类型的局部变量中的final修饰: 该变量值不能改变
		final int a = 3;
		//a = 5;  不能改变
		
		//引用类型的局部变量中加final修饰: 该变量地址不能改变,与属性值无关
		final Son son = new Son();
		//son.b = 6;
		//son = new Son();  //地址不能改变
		
		//数组也是引用类型,修饰数组后,地址不能变,里面的元素值可以变
		final int[] c = {
    
    1,2,3};
		//c = new int[]{4,5};  //地址不能改变
		c[0] = 6;
		
	}
}



猜你喜欢

转载自blog.csdn.net/weixin_45682261/article/details/125132464