一、static 关键字引入
static关键字声明的属性和方法是类自己的,所有类实例化的对象,都共享这些static属性和方法。
static可用于修饰:属性、方法、代码块、内部类
1.1 static修饰属性
static修饰后的属性称为静态属性,也叫静态变量,类变量。类的所有对象共享同一静态变量,当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过的。可以想象成大学宿舍,每个宿舍里面的房间都是对象,个人是个人的,宿舍公共区的东西比如澡堂,厨房就是共有的,static变量
1.2 static静态变量的说明
1、静态变量随着类加载而加载,因此静态变量的加载要早于对象的创建。
2、由于类只会加载一次,因此静态变量在内存中也会只有一份:存在方法区的静态域中。
说明:类是不会被销毁的,除非内存严重不足,因此类变量(静态变量)会被一直保存(即数据不会被重置)。
1.3 static静态变量的调用方法
静态变量由于是类变量,因此可以直接用类来调用,不需要用类的对象调用了(也可以用对象调用)
语法: 类名.静态变量 = 值; //可以直接通过类给类静态变量赋值(通过类来调用)
类对象名1.静态变量 = 值; //通过类对象来调用(注意需要public权限)
exp: Math.PI ,System.out(类的属性也可以是引用数据类型,out属性就是system类的一个引用数据类型的属性)
class System{
public static final PrintStream out; //属性名为out,属性值为out.toString()
}
因此可以用out对象调用 PrintStream类的println方法,就形成了System.out.println();
1.4 static静态变量的内存解析
1.5 静态方法
1、特点
(1)静态方法随着类的加载而加载,同样可以直接通过 类.方法名 来调用静态方法
(2)同样可以通过类的对象来调静态方法。
(3)静态方法,只能调用静态方法或属性(因为他们声明周期一致,重点是,非静态方法或属性都是对象的,根本不知道对象啥时候会销毁,而且那么多对象,你调用谁的)。非静态方法,既可以调用非静态属性或方法,也可以调用静态方法或属性。(就是说对象可以调用类的东西)
注意:静态方法内,不能使用this关键字、super关键字(根本没对象)。直接类名.属性,或类名.方法
1.6 static属性和方法的应用场景 (一般情况)
初始化对象的时候,会先初始化类。即先有类,再有对象。static的属性和方法都是类的属性和方法,会优先加载,但是只加载一次。
1、static属性应用场景
(1)如果这个属性可以被多个对象所共享,就可以声明成static。比如银行账户类,账号,密码,余额,透支额度,利率。显然利率可以声明为static属性
(2)类中的常量(final修饰的变量),一般也用static修饰,比如Math.PI。 既然是常量,自然这个类的所有对象都是用一个相同的值。那就static成类属性多好。要不每个对象都来生成一个相同值,麻烦。
2、static方法应用场景
(1)操作静态属性的方法,一般就设置成静态了,就是直接用类调用方法来设置静态属性,没必要造个对象去调方法。
(2)工具类中的方法,一般声明为静态。因为工具类没属性,还要造个对象去调方法,太麻烦了,直接用类调方法更方便。
扩展:main方法()
1、main方法使用说明
(1)main方法是程序入口,如果代码中写了多个main方法,需要选择其中一个main作为程序入口。其他main就变成一个普通静态方法。
public class MainTest{ //JVM通过这个类,来调用main方法,所以权限一定要是public
public static void main(String[ ] args) { } //由于是类直接调用,main方法需要声明成静态的。public确保main方法顺利调用
}
(2)main方法也是我们与控制台交互的方式。(通过main的形参 String[ ] args)
public class MainDemo{
public static void main(String[ ] args) {
for (int i=0;i<arg.length;i++) {
System.out.println(args[i]);}
}
}
特别说明:由于这就是程序入口,已经没有办法再找个方法来传实参调用这个main方法了,只有先编译此程序。编译完成后(生成.class),再运行时传入实参。
传入实参方法一:命令提示符
进入源代码所在的文件夹
javac MainDemo.java //编译MainDemo,生成MainDemo.class字节码文件
java MainDemo "Tao" "JJ" "Zou" //规范的写法加"",因为数据类型是String,但是这里允许不加
传入实参方法二: IDEA 里面
首先 右键 Run as (编译文件,生成字节码文件)
编译好以后,右键 Run Configurations。 找到类名MainDemo,然后在右边Arguments里面输入实参,双引号(不加也可以,规范点就加),空格隔开。
二、类的代码块 (Block)
代码块的作用:用来初始化类 和 对象。(static代码块初始化类,非static代码块初始化对象)
说明:代码块就是一种新的给 类 和 对象 的属性赋值的方式,一般自己写都不用代码块,都是用构造器赋值,但是有的源码会有代码块,因此需要学习下。
主要应用场景(静态代码块给类的属性赋值):类的构造器是用来初始化对象的,类本身的static属性,没有构造器来初始化,在给类的static属性赋默认值之前,同样可能需要做一些其他操作,比如来点判断语句之类的,这会就可以用静态代码块来给类的属性赋值。
注意:由于代码块在 类 或 对象 加载完就立刻加载,因此执行顺序在构造器之前。如果同时用来给属性赋值,显然最后显示构造器给属性赋的值。
特别注意:static的属性、方法和代码块都是类的东西,类实例化对象的时候会先初始化类,就会先执行类的静态代码块语句。因此如果该类有父类,而且父类中还有静态代码块的语句时,实例化该类的对象时,由于super会导致初始化父类,就会先执行父类的静态代码块语句。
总结:初始化一个类的对象时,要注意初始化属性和代码块的顺序, 由父及子,静态先行。
语法:
【static】{ 语句; } //有static的是静态代码块,没static的是非静态代码块
说明:
1、静态代码块随着类的加载而执行。(由于类只加载一次,所以静态代码块的语句只执行一次)
2、非静态代码块随着对象的创建而执行。(对象可以创建多个,所以非静态代码块的语句可以执行多次)
三、final关键字
final表示最终的,可以用来修饰的结构有:类、方法、变量
1、final 修饰类
表示最终的类(太监类),即不能有子类了。即final 类 不能被其他类所继承。
说明:很多java提供的类,比如String类,System类,都被声明为了final
语法: final class A{
} //classA没有子类了 , class 任意类 extends A 即报错
2、final 修饰方法
表示此方法是最终方法,不允许被子类重写了。
小扩展:native关键字
有的源码中会遇到native关键字,指要调用java底层的c++了,了解即可。
public final native class<?> getClass();
3、final修饰变量 将变量变成最终的变量,即常量(相当于c++的const)
注意养成好习惯:常量的标识符都用大写
(1)final 修饰成员变量(类属性)
由于final表示最终,不允许改变,因此final修饰的属性在类或对象初始化以后就不允许再改变。对象在构造器加载完成后被创建,因此必须在调用构造器之前(包含用构造器的时候,对final进行赋值)
使用时机:
- 在变量声明时立刻显式赋默认值(用的比较少,毕竟每个对象的属性多少有差异,用这种方式还不如static)
语法:final 数据类型 成员变量 = 值; //声明属性时,立刻显式赋值
- 声明final属性后,在代码块中赋值 (和上面的方式差不多,只是用代码块可以多写一些别的语句,比如if,或者抛异常)
语法:final 数据类型 成员变量;
{ 成员变量 = 值}; //单独对final变量赋值是错的,代码块中可以,因为类或对象的代码块只执行一次
- ☆ 构造器中赋值 (最常用,可确保每个对象都有自己的final值)
语法: final 数据类型 成员变量;
构造器(数据类型 形参){
成员变量 = 形参; }
(2)final修饰局部变量(普通变量)
就很简单了,就是把变量变成常量,后面不允许修改。特别注意局部变量作为函数形参的时候。
exp: public void show(final int NUM) { //相当于代码块中第一句 final int num = 实参;)
NUM = 20; } //报错,编译不通过,传过来的实参是常量,不允许修改
扩展: static final
用来修饰属性: 类的不可修改的属性,即全局常量 (类的属性只有一个)
用来修饰方法:类的不可重写的方法