Java: static,final,代码块 的详解

news/2024/11/25 10:47:39/

Java: static,final,代码块 的详解

在这里插入图片描述


每博一文案

山本文绪说过这样一句话:哪些决定放弃了的事,就请放弃得干干净净。哪些决定再也不见面的人,就真
的不要再见面了,不要再做背叛自己的事,如果想要爱别人,就先好好爱自己。	
人生是一场有去无回的旅行,旧日种种,结成过往,我们只能回过头看,却不能从头走,好的也罢,坏的也罢,
过去的都已成定局了。不管是遗憾还是庆幸,都要带着这份烙印,继续走向漫漫人生。
正如那句极有名的禅语:无论你遇见谁,他都是对的人,无论发生什么事,那都是唯一会发生的事。
不管事情开始于那个时刻都是对的,时刻已经结束的,就是结束了。如果没有失去,就不会懂得珍惜。
但是你知道吗?如果已经失去了,就该学会放弃,没有什么是注定会属于我们的,得到或者失去,都是自有它的安排。
面对哪些注定要说再见到人或物,与其拼命拉扯,泪影婆娑,倒不如落落大方道一句“珍重”。
从从容容德告个别,然后留下一个潇洒离开的背影,从今以后更加坚定自己的路,将自己的人生过得有声有色。
愿你可饮最烈的酒,也能放开该放的手,从前不回头,往后强求。——————   一禅心灵庙语

文章目录

  • Java: static,final,代码块 的详解
    • 每博一文案
    • 1. static 关键字
      • 1.1 static 修饰属性
      • 1.2 static 修饰方法
      • 1.3 static 修饰代码块
      • 1.4 static 修饰内部类
      • 1.5 开发中如何合理的使用 staitc 关键字
    • 2. main 方法的探究
    • 3. 代码块
      • 3.1 程序中成员变量赋值的执行顺序
    • 4. final 关键字
    • 5. 总结:
    • 6. 最后:


1. static 关键字

当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上 的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象, 其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少 对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。这里我们就可以用到 static 关键字的使用了。

static : 表示的含义是 :静态的

在Java类当中, static 可以修饰属性,方法,代码块,内部类

1.1 static 修饰属性

static 修饰属性(变量): 按是否使用 static 修饰,可以分为为 静态属性(类属性) VS 非静态属性(实例属性)

非静态属性(实例属性): 我们创建了类的多个对象,每个对象都独立的拥有一套 类中的 非静态属性,非静态变量对应不同的实例对象(new) 自身的修改,不会影响到其他的 对象当中的一套非静态属性。

静态属性(类属性): 我们创建了类的多个对象,但是多个对象共享同一个静态属性,当通过某一个对象修改静态属性时,会导致其他对象调用此静态变量时,是最后一次修改过的结果。

被 static 修饰的属性的特点:

  • 静态属性随着类的加载而加载,早于 new 对象的加载创建,因为 new 对象,要先加载类,再调用类中的构造方法创建对应的对象。
  • 在访问权限允许的情况下,静态属性可以通过**“类名.静态属性名”** 的方式进行调用。
  • 由于类只会加载一次,则静态属性(静态变量) 在内存(方法区)当中也只会存在一份,存在方法区的静态域当中。
  • 静态属性有:System.out; Math.PI;
package blogs.blog2;public class StaticTest {public static void main(String[] args) {Chinese c1 = new Chinese();c1.nation = "CHN";Chinese c2 = new Chinese();c2.nation = "CHINA";System.out.println("c2.nation: "+c1.nation);System.out.println("c2.nation: "+c2.nation);// 可以通过 类名.静态属性 ()Chinese.nation = "中国";System.out.println("Chinese.nation: "+Chinese.nation);}
}class Chinese{String name;int age;static String nation;     // 被 static 修饰的静态属性}

在这里插入图片描述

在这里插入图片描述


1.2 static 修饰方法

被 staitc 修饰的方法,被称为是 ”静态方法“ 或者是 类方法。

静态方法的特点:

  • 同样静态方法也是和随着类的加载而加载到内存(方法区)当中的。
  • 在访问权限允许的情况下,静态属性可以通过**“类名.静态方法名”** 的方式进行调用。
  • 静态方法只能调用 静态的方法/属性 ,无法调用非静态的方法/属性,除非 实例化对象(new)。因为一个(静态方法)是已经在内存当中存在了的,调用一个(非静态的)还没有加载到内存当中的,JVM 是不允许的。
  • 在静态的方法内:不能使用 'this’关键字 以及 super 关键字,他俩都是表示对象的引用.
  • 非静态方法可以调用非静态方法或属性,也可以调用静态方法或属性。
  • 被 static 修饰的方法无法重写

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

在这里插入图片描述


package blogs.blog2;public class StaticTest {public static void main(String[] args) {// 静态方法可以直接使用  “类名.静态方法”调用Chinese.show();}
}class Chinese{String name;int age;static String nation;     // 被 static 修饰的静态属性public static void show(){System.out.println("我是静态方法");// name = "TOM";  // 静态方法无法直接调用非静态的属性// eat();   // 静态方法无法直接调用非静态的方法,可以通过 new 实例对象,调用/*this.name = "Tom";super.clone();*/  // 静态方法中无法使用 this./super.// 静态方法可以直接调用静态属性,静态方法nation = "Hello";   // 静态属性sleep();            // 静态方法}public void eat(){System.out.println("吃饭");System.out.println("***************************");// 非静态方法可以直接调用 静态方法/属性,因为加载内存的先后原因nation = "World";     // 静态属性sleep();              // 静态方法}public static void sleep() {System.out.println("睡觉");}
}

在这里插入图片描述


被 stiatic 修饰的方法,继承时,无法被重写,就算你按照重写的要求,编写好了没有报错,但是运行的时候,调用的是父类中没有被重写的方法 因为 stiatic 是类方法,和类一起加载到内存当中的,而多态中的重写是,运行时类型,只有运行了。才

package blogs.blog2;public class StaticTest {public static void main(String[] args) {Earth earth = new Chinese();  // 多态earth.human();}}class Chinese extends Earth{public static void human() {System.out.println("中国人");}
}class Earth{public static void human(){System.out.println("人类");}}

在这里插入图片描述


1.3 static 修饰代码块

被 static 修饰的代码块,被称为 “静态代码块”

具体详细,继续往下看,在 3.代码块 这一段有详细说明

1.4 static 修饰内部类

关于这一部分内容,大家可以移步至:🔜🔜🔜

1.5 开发中如何合理的使用 staitc 关键字

开发中:如何确定一个属性是否声明未 static ???

如果一个属性可以被多个对象共享的,不会随着对象不同而不同的,就可以声明为 staitc

一般 static 是和 final 一起修饰 变量的。

开发中:如何确定一个方法是否要声明为 static 的 ???

一般是 stiatic 的属性,通常对应的 set/get 方法也是 stiatic 的

工具类中的方法,习惯上声明为 static 的,比如:Math,Arras,Collections


2. main 方法的探究

在这里插入图片描述

  • public 权限修饰符为什么是 public ???

由于Java虚拟机需要调用类的 main() 方法,所以该方法的访问权限 必须public 才行。

  • 为什么 main 方法的修饰符要是 static 静态的 ???

因为Java虚拟机在执行 main() 方法时,不必创建对象,所以该方法必须是 static ,可以直接调用。

又因为 main 方法是 static 静态的,静态方法无法直接调用非静态的方法/属性,

必须创建对应类的实例对象(new)后,才能通过这个对象去访问该对应类中的非静态方法/属性。

  • main 方法中的形参列表是 string[] args 字符串数组

该形参接收一个 String 类型的数组参数,该字符串数组中保存执行 java 命令时,所传递给所运行类的参数。

在这里插入图片描述


main 也是一个方法,特殊之处就是,它是一个程序入口的方法。不同的类中的是可以相互调用 main 的方法的,如下

因为有两个类,每个类中都有一个 main() 方法,所以执行的时候,你需要选择,想要运行的是哪一个告知编译器。

package blogs.blog2;public class MainTest {public static void main(String[] args) {System.out.println("我是 MainTest 中的 main()方法");}
}class Main2{public static void main(String[] args) {System.out.println("我要调用 MainTest中的main()方法");// 调用 MainTest 中的main()方法MainTest.main(args);}
}

在这里插入图片描述


3. 代码块

在这里插入图片描述

代码块(或初始化块)的作用: 对Java类或者对象进行初始化

代码块的分类:

  • 一个类中代码块中若有修饰符,则只能被 static 修饰,被 static 修饰的代码块被称为 静态代码块
  • 没有任何修饰符,修饰的代码块,被称为非静态代码块

静态代码块的特点:

  • 可以有输出语句
  • 可以对类的属性,类的声明进行初始化操作
  • 不可以对非静态的属性初始化,无法直接调用非静态的的方法/属性,想要 实例化对象 new
  • 静态代码块随着类的加载而加载,并执行,且执行一次。所以静态代码块的执行要先于非静态代码块
  • 一个类中可以有多个静态代码块,若有多个静态的代码块,那么按照从上到下的顺序依次执行。
  • 静态的代码块的诸多限制和 “staitc" 是一样的。

非静态代码块的特点:

  • 和静态代码块一样可以有输出语句
  • 可以对类的数,类的声明进行初始化操作。
  • 不仅可以调用静态的方法/属性,也可以调用非静态的方法 / 属性
  • 一个类中可以有多个非静态代码块,若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
  • 注意的是非静态代码块是,创建对象 (new) 的时候,才会执行,而且每创建一次对象都会执行一次,并且先于构造器执行。

无论是静态代码块/还是非静态代码块,都是加载后并执行的,并不是加载到内存当中不执行的。

在这里插入图片描述


注意: 非静态代码块,不是创建对象 (new) 是不会加载调用执行非静态代码块的

package blogs.blog2;public class BlockTest {public static void main(String[] args) {Person.show();}
}class Person{String name;static String desc;public void eat() {System.out.println("非静态方法");}public static void show(){System.out.println("静态方法");}{System.out.println("非静态代码块");}static{System.out.println("静态代码块");// name = "Tom";  // 静态代码块无法直接调用非静态的// eat();}
}

在这里插入图片描述


静态代码块优先比非静态代码块优先被执行,并且静态代码块仅仅只是执行一次(加载类的那一次)

package blogs.blog2;public class BlockTest {public static void main(String[] args) {Person person = new Person();Person person2 = new Person();}
}class Person{String name;static String desc;public void eat() {System.out.println("非静态方法");}public static void show(){System.out.println("静态方法");}{System.out.println("非静态代码块");}static{System.out.println("静态代码块");// name = "Tom";  // 静态代码块无法直接调用非静态的// eat();}
}

在这里插入图片描述


练习: 观察如下代码的运行结果:

先执行父类,再执行静态代码块

package day15;public class LeafTest {public static void main(String[] args) {new Leaf();System.out.println("*************************");new Leaf();}
}class Root{static {System.out.println("Root的静态初始化块");}{System.out.println("Root的普通初始化块");}public Root(){super();System.out.println("Root的无参数的构造器");}}class Mid extends Root{static{System.out.println("Mid的静态初始化块");}{System.out.println("Mid的普通初始化块");}public Mid() {super();System.out.println("Mid的无参数的构造器");}public Mid(String msg) {// 通过this调用一类中的重载的构造器this();System.out.println("Mid的带参数构造器,其参数数值: "+msg);}
}class Leaf extends Mid{static{System.out.println("Leaf的静态初始化块");}{System.out.println("Leaf的普通初始化块");}public Leaf() {// 通过super调用父类中有一个字符串参数的构造器super("尚硅谷");System.out.println("Leaf的构造器");}
}

在这里插入图片描述


package day15;public class Son extends Father {static {System.out.println("44444444444444444");}{System.out.println("55555555555555");}public Son() {System.out.println("66666666666666");}public static void main(String[] args) {System.out.println("77777777777");System.out.println("**********************************");new Son();System.out.println("*********************************");/*new Son();System.out.println("*************************************");new Father();*/}
}class Father{static{System.out.println("11111111111");}{System.out.println("222222222222");}public Father() {System.out.println("33333333333333");}
}

在这里插入图片描述


3.1 程序中成员变量赋值的执行顺序

如下是对属性赋值的先后所执行的顺序

  1. 默认初始化
  2. 显式初始化
  3. 在代码块中赋值
  4. 构造器中初始化
  5. 有了对象以后,可以通过 ”对象.属性,或对象.方法“ 的方式,进行赋值。
    在这里插入图片描述
public class OrderTest {public static void main(String[] args) {Order order = new Order();System.out.println(order.orderId);}
}class Order{{orderId = 4;}int orderId = 3;public Order() {this.orderId = 5;}}

在这里插入图片描述


把构造器初始化注释掉,结果是

在这里插入图片描述


4. final 关键字

final : 最终的含义。

final 可以用来修饰:类,方法,变量,局部变量(形参)

final 修饰一个,此类就不能被其他类所继承了

比如:System 类,String 类,StringBuffer类:因为里面的方法基本都实现了,没有必要再通过继承扩展了。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


final 修饰方法:表明此方法不可以被重写,比如:Object 类中的 getClass()

在这里插入图片描述


在这里插入图片描述


final 修饰属性:可以考虑赋值的位置有:显示初始化,代码块初始化,构造器,注意是:赋值不是修改,被 final 修饰的变量无法被修改了。

显示初始化

package blogs.blog2;public class FinalTest {final int num = 10;public static void main(String[] args) {FinalTest f = new FinalTest();System.out.println(f.num);}
}

在这里插入图片描述


代码块初始化:

package blogs.blog2;public class FinalTest {final int LEFT;{LEFT = 100;}public static void main(String[] args) {FinalTest f = new FinalTest();System.out.println(f.LEFT);}
}

在这里插入图片描述


构造器初始化:

package blogs.blog2;public class FinalTest {final int num;public FinalTest(int n) {num = n;}public static void main(String[] args) {FinalTest f = new FinalTest(1000);System.out.println(f.num);}
}

在这里插入图片描述


final 修饰局部变量(形参) 表明此形参时一个常量,当我们调用此方法时,给常量形参赋值一实参,一旦赋值以后,就只能在方法体中使用此形参,并且不能再进行重新的赋值操作了。

在这里插入图片描述


package blogs.blog2;public class FinalTest {final int num;public FinalTest(final int n) {num = n;}public static void main(String[] args) {FinalTest f = new FinalTest(1000);System.out.println(f.num);}
}

一般是 static, final 用来修饰属性,全局常量,需要注意的是一般 static 的成员属性,方法也是 static 的

练习:

观察如下代码是否会出现报错,如果不会报错,运行的结果又是什么???

package blogs.blog2;public class FinalTest {public static void main(String[] args) {AA aa = new AA();aa.test(aa);}}class AA {String name;int age ;public void test(final AA aa) {aa.age = 10;   // 这里是否或报错,能否编译成功System.out.println(aa.age);}
}

在这里插入图片描述


解析:

答:不会报错,结果是 10 。

因为 final 修饰的是 AA 这个引用类型的形参,并不会作用于 AA 类中的属性。

如果我修改 AA 这个引用类型的地址,可能就会报错了。


5. 总结:

  1. static 修饰属性,方法,代码块,内部类的不同的作用,
  2. static 静态的随着类一起加载到内存(方法区)当中(仅仅加载一次,所有对象共有),早于 new 对象的加载创建,因为 new 对象,要先加载类,再调用类中的构造方法创建对应的对象。
  3. static 静态的属性,方法,代码块 都无法直接的访问非静态的方法/属性,需要通过 创建实例对象(new)的方式访问
  4. 被 static 修饰的方法,无法被重写,就算编写成了重写的方式了,但是调用的时候,执行的不是子类重写的方法,而是父类中没有被重写的方法。
  5. main 方法的 public , static ,String[] args 的作用。
  6. 代码块:静态代码块,非静态代码块。
  7. 静态代码块:随着类一起加载到内存(方法区)当中,加载的同时,并执行代码块,并且(无论加载多少次类)只执行一次(加载类的那一次)。优先于非静态代码块,优先于构造器。
  8. 非静态代码块:只有当创建实例对象(new)的时候才会被加载并执行,创建多少次对象就会执行多少次非静态代码块。
  9. final 最终的,可以修饰:属性(不可修改),形参(不可修改),方法(无法重写),类(无法继承)。

6. 最后:

限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,后会有期,江湖再见!!!


在这里插入图片描述


http://www.ppmy.cn/news/6107.html

相关文章

【SpringMVC】请求参数的绑定

1.绑定说明 1.1 绑定的机制 我们都知道&#xff0c;表单中请求参数都是基于 keyvalue 的。SpringMVC 绑定请求参数的过程是通过把表单提交请求参数&#xff0c;作为控制器中方法参数进行绑定的。 例如&#xff1a; <a href"account/findAccount?accountId10"&…

基于防火墙双击热备三层网络规划_ensp综合实验

作者&#xff1a;BSXY_19计科_陈永跃BSXY_信息学院注&#xff1a;未经允许禁止转发任何内容基于防火墙双击热备三层网络规划_ensp综合实验前言及技术/资源下载说明&#xff08; **未经允许禁止转发任何内容** &#xff09;插曲&#xff1a;基于eNSP中大型校园/企业网络规划与设…

机器学习 | 决策树

一.基本原理 决策树是一种树状结构模型&#xff0c;每一个根节点都是一个特征判断&#xff0c;它的叶子节点就是它的特征分类结果 决策树是一种分类和回归的基本模型&#xff0c;是一棵树的形式&#xff0c;其实就是将平时所说的 if-else 语句构建成了树的形式。决策树主要包…

阿里灵杰:与开发者一起推动AI创新落地

对于人工智能领域而言&#xff0c;“AIGC”无疑是贯穿2022年的热点。12月16日&#xff0c;Science杂志发布了2022年度科学十大突破&#xff0c;AIGC赫然在列。以文生图&#xff0c;对话机器人等AI创新应用的落地&#xff0c;引发一轮又一轮的全民狂欢热潮。AI技术蓬勃发展&…

微信小程序之实时聊天系统——页面介绍

目录 系统结果展示&#xff1a; 系统的页面说明&#xff1a; 1.我们首先再app.json中创建四个tabBar页面&#xff08;消息、联系人、用户列表、我的&#xff09; 2.消息页面&#xff1a; 3.联系人页面&#xff1a; 4.用户列表页面&#xff1a; 5.我的页面&#xff1a; 欢…

【C++】PCL对大容量点云进行体素降采样

文章目录0.引言1.普通体素降采样2.OcTree体素降采样0.引言 \qquadPCL的体素滤波器如果对超大容量点云进行降采样&#xff0c;要求降采样后的格点数目必须在整型的范围&#xff0c;不然就会报[pcl::VoxelGrid::applyFilter] Leaf size is too small for the input dataset. Inte…

整理各种Vue项目在IE浏览器白屏报错 SCRIPT1002:语法错误

目录 一、关于 sockjs-client 依赖包 二、关于 highlight 依赖包 三、关于 swiper 依赖包 四、IE 不支持 ES6 语法 五、第三方插件引入导致 六、本地环境正常&#xff0c;生产环境仍旧白屏 这篇文章主要介绍了 Vue 项目在 IE 浏览器显示白屏并报错 SCRIPT1002: 语法错误 …

7、操作系统之间的文件传输

Windows 与 Linux 在Windows与Linux中传输文件的常用方式有两种&#xff0c;一种是使用使用XFTP工具&#xff0c;另一种是使用rz sz 命令的方式进行 lrzsz 安装 yum install lrzsz -y 1&#xff09;rz 将文件从window上传到Linux 2&#xff09;sz 将文件从linux传输到window …