博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
009Java基础之静态成员、代码块及final关键字
阅读量:3957 次
发布时间:2019-05-24

本文共 11340 字,大约阅读时间需要 37 分钟。

1、类变量

类变量也叫做静态变量或者静态属性,是该类所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样,任何一个该类的对象去修改它时,修改的也是同一个变量。

静态变量在JDK8之前,存放在方法区的静态域,JDK8以后,存放在堆的Class对象中(官方没有明确的说法)
定义语法
访问修饰符 static 数据类型 变量名 ;或者
static 访问修饰符 数据类型 变量名 ;
推荐第一种方式。
注意事项和细节
(1)什么时候使用静态变量?
当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用静态变量
(2)类变量与实例变量的区别:
类变量是该类所用对象共享的,而实例变量是每个对象独享的
(3)加上static的变量称为类变量或静态变量,否则称为实例变量、普通变量或非静态变量等
(4)类变量可以通过类名.属性名或者变量名.属性名访问,推荐使用类名.属性名来访问
在这里插入图片描述

(5)实例变量不能通过类名.属性名方式访问

(6)类变量是在类加载的时候就初始化了,也就是说,即使没有创建对象,只要类加载了,就可以使用类变量了,所以构造器参数中不能有静态变量。
(7)类变量的生命周期是随类的加载开始,随着类的消亡而销毁

2、类方法

类方法的定义规则和使用与类属性一致,不再重复。类方法有一个重要的应用即是在工具类中的使用。

注意事项和细节
(1)类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区:
类方法中无this的参数,普通方法中隐含着this的参数。
在这里插入图片描述
(2)与类属性一样,类方法可以通过类名调用,也可以通过对象名调用,但推荐使用类名调用。
在这里插入图片描述

(3)普通方法与对象有关,需要通过对象名调用,不能通过类名调用

(4)类方法中不允许使用和对象有关的关键字,比如this、super,普通方法可以
在这里插入图片描述

(5)类方法中,如果访问的是本类中的成员,只能访问静态变量或静态方法,如果非要访问非静态的成员,自己new自己,通过对象去访问。

在这里插入图片描述

(6)普通成员方法,既可以访问非静态成员,也可以访问静态成员

在这里插入图片描述

/** * @author Francis * @create 2021-07-01 10:39 */public class StaticMethod {
public static void main(String[] args) {
//创建 2 个学生对象,叫学费 Stu tom = new Stu("tom"); tom.payFee(100);// tom.fee=100; Stu.payFee(100);//对不对?对 Stu mary = new Stu("mary");//mary.payFee(200); Stu.payFee(200);//对//输出当前收到的总学费 Stu.showFee();//300//如果我们希望不创建实例,也可以调用某个方法(即当做工具来使用)//这时,把方法做成静态方法时非常合适 System.out.println("9 开平方的结果是=" + Math.sqrt(9)); System.out.println(MyTools.calSum(10, 30)); }}class MyTools {
//求出两个数的和 public static double calSum(double n1, double n2) {
return n1 + n2; }//可以写出很多这样的工具方法...}class Stu {
private String name;//普通成员 //定义一个静态变量,来累积学生的学费 public static double fee = 0; public Stu(String name) {
this.name = name; } //说明//1. 当方法使用了 static 修饰后,该方法就是静态方法//2. 静态方法就可以访问静态属性/变量 public static void payFee(double fee) {
Stu.fee += fee;//累积到// this.fee+=fee; } public static void showFee() {
// test(); System.out.println("总学费有:" + Stu.fee); } public void test() {
System.out.println(Stu.fee); } public void test2(){
showFee(); test(); }}

3、main方法

1、理解main方法

**public static void main(String[] args) {} **

(1)main方法是由虚拟机调用
(2)java虚拟机需要调用类的main方法,所以main方法必须是public的
(3)java虚拟机在执行main方法时不必创建对象,所以该方法必须是static的
(4)main方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数
在这里插入图片描述
(5)既然main方法是public的,static的,其遵循这两个属性的基本规则
在idea中给main方法传参
(1)编译源文件,(默认是没有MainTest01的)在这里插入图片描述
(2)编辑
在这里插入图片描述
在这里插入图片描述

(3)在此运行,参数顺利传给了main方法

在这里插入图片描述

4、代码块

1、基本介绍

代码块又称初始代码块,属于类中的成员(即是类的一部分),类似于方法,将逻辑语句封装在方法体中,通过{}包裹起来,但和方法不同,没有方法名,没有返回值,没有参数,只有方法体, 而且不用通过对象或类显式调用,而是类加载时,或创建对象时隐式调用

2、基本语法

[修饰符] {
代码};

说明

(1)修饰符,可选,如果要写的话,也只能是static
(2)代码块分为两类,使用static修饰的叫做静态代码块,没有static修饰的,叫做普通代码块
(3)逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)
(4);号可以写上,也可以省略
理解
(1)普通代码块相当于另一种形式的构造器(对构造器的补充机制),可以做初始化操作
(2)使用场景:如果多个构造器中都有重复语句,可以抽取到初始化块中,提高代码的重用性
例如:
在这里插入图片描述
在这里插入图片描述

/** * @author Francis * @create 2021-07-01 17:15 */public class CodeBlock01 {
public static void main(String[] args) {
Movie movie = new Movie("你好,李焕英"); System.out.println("==============="); Movie movie2 = new Movie("唐探 3", 100, "陈思诚"); } } class Movie {
private String name; private double price; private String director;//3 个构造器-》重载//老韩解读//(1) 下面的三个构造器都有相同的语句//(2) 这样代码看起来比较冗余//(3) 这时我们可以把相同的语句,放入到一个代码块中,即可//(4) 这样当我们不管调用哪个构造器,创建对象,都会先调用代码块的内容//(5) 代码块调用的顺序优先于构造器.. {
System.out.println("电影屏幕打开...");System.out.println("广告开始...");System.out.println("电影正式开始..."); } public Movie(String name) {
// System.out.println("电影屏幕打开...");// System.out.println("广告开始...");// System.out.println("电影正式开始..."); System.out.println("Movie(String name) 被调用..."); this.name = name; } public Movie(String name, double price) {
// System.out.println("电影屏幕打开...");// System.out.println("广告开始...");// System.out.println("电影正式开始..."); this.name = name; this.price = price; } public Movie(String name, double price, String director) {
System.out.println("Movie(String name, double price, String director) 被调用..."); this.name = name; this.price = price; this.director = director; }}

3、注意事项和细节

(1)static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次,如果是普通代码块,没创建一个对象,就会执行一次

在这里插入图片描述
(2)类被加载的三种情况
①创建对象实例时(new)
在这里插入图片描述
②创建子类对象实例,父类也会被加载
在这里插入图片描述

③使用类的静态属性(成员变量和方法)(当然,也包括子类的静态方法)

在这里插入图片描述

/** * @author Francis * @create 2021-07-01 19:48 */public class CodeBlockDetail {
public static void main(String[] args) {
//类被加载的情况举例//1. 创建对象实例时(new)// AA aa = new AA();//2. 创建子类对象实例,父类也会被加载, 而且,父类先被加载,子类后被加载// AA aa2 = new AA();//3. 使用类的静态成员时(静态属性,静态方法)// System.out.println(Cat.n1);//static 代码块,是在类加载时,执行的,而且只会执行一次. // DD dd = new DD();// DD dd1 = new DD();// DD dd2 = new DD();//普通的代码块,在创建对象实例时,会被隐式的调用。// 被创建一次,就会调用一次。// 如果只是使用类的静态成员时,普通代码块并不会执行 System.out.println(DD.n1);//8888, 静态模块块一定会执行 } } class DD {
public static int n1 = 8888;//静态属性 //静态代码块 static {
System.out.println("DD 的静态代码 1 被执行...");// } //普通代码块, 在 new 对象时,被调用,而且是每创建一个对象,就调用一次//可以这样简单的,理解 普通代码块是构造器的补充 {
System.out.println("DD 的普通代码块..."); } } class Animal {
//静态代码块 static {
System.out.println("Animal 的静态代码 1 被执行...");// } } class Cat extends Animal {
public static int n1 = 999;//静态属性 //静态代码块 static {
System.out.println("Cat 的静态代码 1 被执行...");// } } class BB {
//静态代码块 static {
System.out.println("BB 的静态代码 1 被执行...");//1 } } class AA extends BB{
//静态代码块 {
System.out.println("AA 的静态代码 1 被执行...");//2 } }

(3)普通打代码块,在创建对象时,会被隐式的调用,被创建一次,就会被调用一次,如果只是使用类的静态成员时,普通代码块并不会执行(这里可以理解为普通代码块是构造器的补充,类都没有实例化,所以构造器不会执行)

在这里插入图片描述
(4)创建一个对象时,在一个类中,成员的执行顺序是):
①调用静态代码块、静态属性初始化(注意静态代码块与静态属性初始化优先级一样,如果有多个静态代码块和多个静态属性,则按其定义的顺序调用)
在这里插入图片描述
②调用普通代码块、普通属性初始化(注意普通代码块与普通属性初始化优先级一样,如果有多个普通代码块和多个普通态属性,则按其定义的顺序调用)
在这里插入图片描述
③调用构造器
在这里插入图片描述

/** * @author Francis * @create 2021-07-01 20:16 */public class CodeBlockDetail01 {
public static void main(String[] args) {
A a = new A();// (1) A 静态代码块 01 (2) getN1 被调用...(3)A 普通代码块 01(4)getN2 被调用...(5)A() 构造器被调 } } class A {
//无参构造器 public A() {
System.out.println("A() 构造器被调用"); } {
//普通代码块 System.out.println("A 普通代码块 01"); } static {
//静态代码块 System.out.println("A 静态代码块 01"); } private int n2 = getN2();//普通属性的初始化 //静态属性的初始化 private static int n1 = getN1(); public static int getN1() {
System.out.println("getN1 被调用..."); return 100; } public int getN2() {
//普通方法/非静态方法 System.out.println("getN2 被调用..."); return 200; } }

(5)构造器的最前面其实隐藏了super()和调用普通代码块,静态相关的代码块,属性初始化,在类加载时,就执行完毕因此是优于构造器和普通代码块执行的。

在这里插入图片描述

/** * @author Francis * @create 2021-07-01 20:38 */public class CodeBlockDetail02 {
public static void main(String[] args) {
new BBB();//(1)AAA 的普通代码块(2)AAA() 构造器被调用(3)BBB 的普通代码块(4)BBB() 构造器被调用 } } class AAA {
//父类 Object {
System.out.println("AAA 的普通代码块"); } public AAA() {
//(1)super() //(2)调用本类的普通代码块 System.out.println("AAA() 构造器被调用...."); } } class BBB extends AAA {
{
System.out.println("BBB 的普通代码块..."); } public BBB() {
//(1)super() //(2)调用本类的普通代码块 System.out.println("BBB() 构造器被调用...."); } }

(6)当子类父类都存在静态属性、静态代码块、普通属性、普通代码块、构造器时,每个成分执行的先后顺序:

父类静态代码块和静态属性(优先级一样,按定义的顺序执行)
子类静态代码块和静态属性(优先级一样,按定义的顺序执行)
③父类的普通代码块和普通属性(优先级一样,按定义的顺序执行)
④父类的构造方法
⑤子类的普通代码块和普通属性(优先级一样,按定义的顺序执)
⑥子类的构造方法
(7)静态代码块只能直接调用本类的静态成员(属性和方法),普通代码块可以调用任意成员
在这里插入图片描述
对应代码如下:

/** * @author Francis * @create 2021-07-01 21:15 */public class CodeBlockDetail03 {
public static void main(String[] args) {
//老师说明//(1) 进行类的加载//1.1 先加载 父类 A02 1.2 再加载 B02//(2) 创建对象//2.1 从子类的构造器开始//new B02();//对象 new C02(); } } class A02 {
//父类 private static int n1 = getVal01(); static {
System.out.println("A02 的一个静态代码块..");//(2) } {
System.out.println("A02 的第一个普通代码块..");//(5) } public int n3 = getVal02();//普通属性的初始化 public static int getVal01() {
System.out.println("getVal01");//(1) return 10; } public int getVal02() {
System.out.println("getVal02");//(6) return 10; } public A02() {
//构造器//隐藏//super()//普通代码和普通属性的初始化...... System.out.println("A02 的构造器");//(7) } } class C02 {
private int n1 = 100; private static int n2 = 200; private void m1() {
} private static void m2() {
System.out.println("m2"); } static {
//静态代码块,只能调用静态成员//System.out.println(n1);错误 System.out.println(n2);//ok//m1();//错误 m2(); } {
//普通代码块,可以使用任意成员 System.out.println(n1); System.out.println(n2);//ok m1(); m2(); } } class B02 extends A02 {
// private static int n3 = getVal03(); static {
System.out.println("B02 的一个静态代码块..");//(4) } public int n5 = getVal04(); {
System.out.println("B02 的第一个普通代码块..");//(9) } public static int getVal03() {
System.out.println("getVal03");//(3) return 10; } public int getVal04() {
System.out.println("getVal04");//(8) return 10; }//一定要慢慢的去品.. public B02() {//构造器//隐藏了//super()//普通代码块和普通属性的初始化... System.out.println("B02 的构造器");//(10)// TODO Auto-generated constructor stub }

总结

(1)static代码块是类加载时执行,而且只会执行一次
(2)普通代码块是在创建对象时执行,创建一个对象,就会执行一次

5、final关键字

final可以修饰类、属性、方法、局部变量

(1)当不希望某个类被继承时,使用final来修饰该类
(2)当不希望父类的某个方法被子类覆盖(重写)时,可以用final关键字修饰
(3)当不希望类的某个属性的值被修改,可以使用final来修饰(常说的常量)
(4)当不希望某个局部变量被修改时,可以用final关键字修饰

/** * @author Francis * @create 2021-07-02 13:57 */public class Final01 {
public static void main(String[] args) {
E e = new E();//e.TAX_RATE = 0.09; }}//如果我们要求 A 类不能被其他类继承//可以使用 final 修饰 A 类final class A {
}//class B extends A {}class C {
//如果我们要求 hi 不能被子类重写//可以使用 final 修饰 hi 方法 public final void hi() {
}}class D extends C {
// @Override// public void hi() {
// System.out.println("重写了 C 类的 hi 方法..");// }}//当不希望类的的某个属性的值被修改,可以用 final 修饰class E {
public final double TAX_RATE = 0.08;//常量}//当不希望某个局部变量被修改,可以使用 final 修饰class F {
public void cry() {
//这时,NUM 也称为 局部常量 final double NUM = 0.01;//NUM = 0.9; System.out.println("NUM=" + NUM); }}

注意事项和细节

(1)final修饰的属性又叫做常量,一般用XX_XX_XX来作为常量名
(2)final修饰的属性在定义时,必须赋初值,并且以后不能修改,赋值操作可在一下位置之一即可。
①定义时:如public final double TAX_RATE=0.05;
②在构造器中
③在代码块中
(3)如果final修饰的属性是static的,则初始化的位置只能是
①定义时
②静态代码块中
(4)final类不能被继承,但能被实例化
(5)如果类不是final的,但是含有final的方法,则该方法不能被重写,但能被继承
(6)一般来说,一个类如果是final的,就没必要把方法再用final来修饰
(7)final不能修饰构造器方法
(8)final往往和static搭配使用,效率更高,不会导致类加载,底层编译器做了优化
在这里插入图片描述
在这里插入图片描述

(9)包装类(Integer 、Double、Float等)是final的,String也是final的

转载地址:http://wsxzi.baihongyu.com/

你可能感兴趣的文章
学习Swing 的网站[转]
查看>>
Google App engine 的第一个应用 midispot
查看>>
提问的智慧
查看>>
关于dom4j无法解析xmlns问题及生成非UTF-8字符集乱码问题的解决
查看>>
很好的一篇文章 如果让我重做一次研究生 王汎森
查看>>
保护U盘批处理文件
查看>>
hibernate 自动导入sql 文件import.sql 国际化编码的问题的解决方案
查看>>
第七颗头骨 & 忘魂花 凤凰
查看>>
李小龙哲学之言
查看>>
潜伏中体现的潜规则
查看>>
[Java] Appfuse 源代码分析
查看>>
[Java] Appfuse 最佳实践
查看>>
[心情] 如果有一天
查看>>
[随笔] 6月近况小记 & 一个站点优化问题
查看>>
[Perl] 关于 Bugzilla 的一些问题与研究
查看>>
[Linux] 常用 linux 系统命令及维护备忘
查看>>
[Linux] 关于 Ext4 HowTo
查看>>
[杂记] 新年物语&关于Mysql引擎性能测试
查看>>
[心得] 近期更新&关于Infobright
查看>>
[杂记] 流量统计 & 短信接口
查看>>