目录
系列文章目录
前言
一、static修饰成员变量
1.1简单描述:
1.2用static修饰的好处:
1.3属于类而不属于对象
1.4如何访问更加合理:
1.5按static的修饰来分类
小结:
二、static修饰成员方法
2.1简单描述:
2.2访问静态成员方法
2.2.1代码示例:
2.2.2输出结果:
2.3在静态成员方法中不能直接调用普通成员方法
2.3.1代码示例
静态成员方法不能直接调用普通成员方法的原因
如何在静态成员方法中调用普通成员方法
代码示例:
2.3.2输出结果
2.4在普通成员方法中可以直接调用静态成员方法
2.5同理不能在静态成员方法中用this.去引用普通成员变量
代码示例:
代码示例:
小结:
三、 static修饰代码块
3.1代码块的概念及分类
3.1.1代码块的概念
3.1.1代码块的分类
3.2 ②构造块(实例代码块)
3.2.1构造块的概念
3.2.2构造块的作用与用法
3.3 ③静态代码块
3.3.1静态代码块的概念,作用,书写位置
3.3.2静态代码块的用法
3.4总结
执行顺序:
四、继承中代码的执行顺序(加上代码块)
五、static成员变量初始化
六、final关键字
系列文章目录
第一章 Java 类和对象
第二章 Java 封装
第三章 Java 继承
第四章 Java 多态
附:static关键字及final关键字
附:this和super
前言
本篇博客主要讲解Java基础语法中的
面向对象系列之
static关键字及final关键字,
1.static关键字修饰成员变量、简述、好处及如何访问。
2.static关键字修饰成员方法、如何调用static修饰的成员方法。
3.static关键字修饰代码块、及代码块的概念、用法。
4.final关键字修饰基本数据类型、引用数据类型、成员变量、成员方法、类的意义。
大家好,本人是普通一本的在校大学生一枚,目前在学习java。之前也学了一段时间,但是没有发布博客。本人现在已经大二结束了,开学就大三了,时间过的真的很快。我会利用好这个暑假,来复习之前学过的内容,并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区进行讨论!!!
喜欢我文章的兄弟姐妹们可以点赞,收藏和评论我的文章。喜欢我的兄弟姐妹们以及也想复习一遍java知识的兄弟姐妹们可以关注我呦,我会持续更新滴,并且追求完整。
望支持!!!!!!一起加油呀!!!!
语言只是工具,不能决定你好不好找工作,决定你好不好找工作的是你的能力!!!!!
学历本科及以上就够用了!!!!!!!!!!!!!!!!!!!!!!!!!!!!
一、static修饰成员变量
1.1简单描述:
当static修饰成员变量时,这个成员变量将不再属于对象,而是属于类。依赖于类,而不再依赖于对象,需要用类名去引用来访问到这个变量。而不再用实例化出来的对象去引用来访问。此时这个变量在类被加载的时候就被创建出来。(虽然也可以通过对象去引用,这样合法,能编译通过但是不合理,不建议这样写代码)
1.2用static修饰的好处:
当我们想要被实例化的每个对象都有一个共同的变量,存放相同的值。我们就不需要去给每个对象的这个变量去赋值。而是通过类去赋值,这样每个实例化出来的对象都可以拥有这样值。简化了我们代码的书写。
例如:
我们定义一个学生类。我们的每一个学生都在14班。此时就可以用static去修饰这个成员变量了。只需要初始化一次,而每个被实例化出来的对象都可以去用类名.去访问到这个变量。
1.3属于类而不属于对象
我们知道对象是存储在JVM中的堆区的。当被static修饰后,这样变量是存放在方法区的。此时每一个被实例化出来的对象都共用这一份被static修饰的,存放在方法区的变量。也就是说这个成员变量将不再属于对象了。而是属于这个类。
1.4如何访问更加合理:
通过类名去引用。不需要实例化对象。也可以访问。如下代码示例分析:
class Stu{
//非静态成员变量/普通成员变量
public String name; //学生姓名
public String gender; //学生性别
public short age; //学生年龄
public double score; //学生分数
//静态成员变量
public static int classRoom; //学生班级
//成员方法
public void DoClass(){
System.out.println(name + "在上课");
} //
public void DoHomework(){
System.out.println(name + "在做家庭作业");
}
public void Exam(){
System.out.println(name + "在考试");
}
}
public class Test {
public static void main(String[] args) {
Stu.classRoom = 14;
System.out.println("学生班级:"+Stu.classRoom);
System.out.println("-----------------------");
Stu student1 = new Stu();//new一个对象后,
//我们发现用student1也可以去访问到这个变量,但是会出现警告
System.out.println("班级:"+student1.classRoom);
//这样做是可以编译通过,但是不合理。不建议这样去写代码
}
}
输出结果:
学生班级:14
-----------------------
班级:14
我们创建了一个学生类。我们假设我们要实例化的学生对象都在同一个班级14班。因此我们用static去修饰classRoom。由于用static修饰的成员变量不再属于对象。因此我们不需要再去实例化一个对象也可以访问到这个成员变量。
但是我们发现。new一个对象后,用student1去引用。虽然出现警告但也可以去访问到这个变量,
这样做是可以编译通过,但是不合理。因为这样变量是属于类的,不再属于对象,假设用对象去引用我们一般认为这样变量是属于这个对象的。显然classRoom不属于它。因此不建议这样去写代码
Stu.classroom这样去访问。才是最合理的
1.5按static的修饰来分类
①静态成员变量:也叫做类变量。由static修饰的成员变量我们称之为静态成员变量。是属于类的,不依赖于对象,用类名去引用访问,类被加载时,这个变量就被创建出来。
②非静态成员变量:也叫做普通成员变量。没有被static修饰的成员变量我们称之为非静态成员变量。是属于对象的,用对象去引用访问。对象被实例化出来。这个变量才被创建出来。
小结:
1. static修饰的成员变量 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中2. static修饰的成员变量既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问3. static修饰的成员变量是存储在方法区当中的4. 生命周期伴随类的一生 ( 即:随类的加载而创建,随类的卸载而销毁 )5.static修饰的成员变量称之为静态成员变量,也叫作类变量。没有被static修饰的成员变量称作非静态成员变量,也叫做普通成员变量。
二、static修饰成员方法
2.1简单描述:
了解了用static修饰的成员变量之后,一通百通。
static修饰其他代码时也是类似的道理。用static修饰的成员方法,我们称之为静态成员方法。也叫做类方法。此时这个成员方法也将属于类而不再属于对象。类似的道理,我们用类名.去引用这个成员方法。(用对象去引用也是合法但是不合理)
我们就不再去像成员变量那样详细去解释每一个点了,因为都是类似的,我们直接看
2.2访问静态成员方法
2.2.1代码示例:
class Stu{
//成员变量
//普通成员变量
public String name; //学生姓名
public String gender; //学生性别
public short age; //学生年龄
public double score; //学生分数
//静态成员变量
public static int classRoom; //学生班级
//成员方法
//普通成员方法
public void DoClass(){
System.out.println(name + "在上课");
} //
public void DoHomework(){
System.out.println(name + "在做家庭作业");
}
//静态成员方法
public static void Exam(){
System.out.println( "所有学生都在考试");
}
}
public class Test {
public static void main(String[] args) {
Stu.Exam();
System.out.println("-----------------------");
Stu student1 = new Stu();//new一个对象后,我们发现用student1也可以去访问到这个静态方法,但是会出现警告
student1.Exam();//这样做是可以编译通过,但是不合理。不建议这样去写代码
}
}
2.2.2输出结果:
所有学生都在考试
-----------------------
所有学生都在考试
类似的静态成员方法我们用类名Stu.去访问。虽然我们实例化出来的对象,也能访问到,但是不建议这样写。
小结:
当成员方法加了static之后,调用这样方法不再需要对象去调用。而是通过类名去引用。不再依赖于对象。而不加static的方法需要我们用对象的引用才能访问到。
2.3在静态成员方法中不能直接调用普通成员方法
如下面的代码示例!
我们知道如果是非静态成员方法,我们可以直接在其中一个成员方法中去调用另一个成员方法,只需要写出对应的方法名和传入相应的参数即可。但是在静态成员方法中就不能这样直接调用普通成员方法了
2.3.1代码示例
静态成员方法不能直接调用普通成员方法的原因
我们可以看到这样写会编译报错。因为普通成员方法是依赖对象的。而静态成员方法不依赖于对象。因此在类被加载时,静态成员变量就会被创建出来,而普通成员变量只有在类被实例化为对象时才被创建出来,因此这两者是矛盾的。当类被加载时,还没有对象被实例化时,又如何去调用那个还没有产生的普通成员方法呢!!!因此这样的写法是错误的。
如何在静态成员方法中调用普通成员方法
因为只有类被实例化后产生了对象才有了普通成员变量和方法,因此我们需要实例化一个对象,再用对象去调用,才能在静态成员方法中去调用普通成员方法。
代码示例:
class Stu{
//成员变量
//普通成员变量
public String name; //学生姓名
public String gender; //学生性别
public short age; //学生年龄
public double score; //学生分数
//静态成员变量
public static int classRoom; //学生班级
//成员方法
//普通成员方法
public void DoClass(){
System.out.println(name+"在上课");
} //
public void DoHomework(){
System.out.println(name + "在做家庭作业");
}
//静态成员方法
public static void Exam(){
Stu student1 = new Stu();
student1.name="李华";
student1.DoClass();
System.out.println( "所有学生都在考试");
}
}
public class Test {
public static void main(String[] args) {
Stu.Exam();
}
}
2.3.2输出结果
李华在上课
所有学生都在考试
我们需要在静态成员方法中new一个对象,再用这样对象去引用这个普通的成员方法,才能成功的在静态成员方法中调用普通成员方法。
小结:
在静态成员方法不能直接调用普通成员方法,如果需要调用就必须在静态成员方法中去new一个对象。再通过当前对象的引用去调用才可以。
2.4在普通成员方法中可以直接调用静态成员方法
这是因为在调用普通成员方法时,静态成员方法早已被创建好了,因此当然可以直接调用喽。
2.5同理不能在静态成员方法中用this.去引用普通成员变量
代码示例:
我们看到普通成员方法中就可以用this去调用其他成员变量,而在静态方法中不能通过this去调用其他成员变量。这样原因与不能调用普通成员方法同理,普通成员变量也是依赖于当前对象的。
如果非要去引用这个成员变量,只有通过类实例化出来的对象才能去引用这个成员变量。
代码示例:
小结:
1.static修饰的成员方法,称之为静态成员方法,也称作类方法, 不属于某个具体的对象。没有被static修饰的成员方法称之为普通成员方法2. static修饰成员方法的 可以通过对象调用,也可以通过类名. 静态方法名 (...) 方式调用,更推荐使用类名.来调用。3. 不能在静态方法中直接访问任何非静态成员方法,如果需要访问,必须在静态方法中实例化一个对象,通过这个对象去访问。4. 不能在静态方法中直接访问任何非静态成员变量,如果需要访问,必须在静态方法中实例化一个对象,通过这个对象去访问。5.可以在普通成员方法中调用普通成员方法和静态成员方法。
三、 static修饰代码块
3.1代码块的概念及分类
3.1.1代码块的概念
使用 {} 定义的一段代码称为代码块。
3.1.1代码块的分类
根据代码块定义的位置以及关键字,又可分为以下四种:
3.2 ②构造块(实例代码块)
3.2.1构造块的概念
构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量(普通成员变量)。
书写位置:实例代码块所处的位置在方法的外面,类的里面,与实例成员变量(普通成员变量)处于同一等级。
3.2.2构造块的作用与用法
作用:一般用来初始化普通成员变量
代码示例:
class Stu{
//成员变量
//普通成员变量
public String name; //学生姓名
public String gender; //学生性别
public short age; //学生年龄
public double score; //学生分数
//静态成员变量
public static int classRoom = 14; //学生班级
//实例代码块
{
this.name = "李华";
this.gender = "男性";
this.age = 18;
this.score = 100;
System.out.println("实例代码块1");
}
//成员方法
//普通成员方法
public void DoClass(){
Exam();//在普通成员方法中可以直接调用静态成员方法
DoHomework();
System.out.println(this.name+"在上课");
} //
public void DoHomework(){
System.out.println(this.name + "在做家庭作业");
}
public void toShow(){
System.out.println("学生姓名:" + this.name);
System.out.println("学生性别:" + this.gender);
System.out.println("学生年龄:" + this.age);
System.out.println("学生分数:" + this.score);
}
//静态成员方法
public static void Exam(){
System.out.println("学生在考试");
}
}
public class Test {
public static void main(String[] args) {
Stu student1 = new Stu();
student1.toShow();
student1.DoClass();
}
}
输出结果:
实例代码块1
学生姓名:李华
学生性别:男性
学生年龄:18
学生分数:100.0
学生在考试
李华在做家庭作业
李华在上课
在实例代码块中可以用this直接给实例成员变量进行赋值,来达到初始化的目的。
再者我们发现在实例代码块中我们输出了“实例代码块1”这段文字。理论上在main方法中。我们并没有调用这个实例代码块。那么这个实例代码块是何时被执行的呢?
我们将实例代码块放在类的最下面。再来输出试试
class Stu{
//成员变量
//普通成员变量
public String name; //学生姓名
public String gender; //学生性别
public short age; //学生年龄
public double score; //学生分数
//静态成员变量
public static int classRoom = 14; //学生班级
//成员方法
//普通成员方法
public void DoClass(){
Exam();//在普通成员方法中可以直接调用静态成员方法
DoHomework();
System.out.println(this.name+"在上课");
} //
public void DoHomework(){
System.out.println(this.name + "在做家庭作业");
}
public void toShow(){
System.out.println("学生姓名:" + this.name);
System.out.println("学生性别:" + this.gender);
System.out.println("学生年龄:" + this.age);
System.out.println("学生分数:" + this.score);
}
//静态成员方法
public static void Exam(){
System.out.println("学生在考试");
}
//实例代码块
{
this.name = "李华";
this.gender = "男性";
this.age = 18;
this.score = 100;
System.out.println("实例代码块1");
}
}
public class Test {
public static void main(String[] args) {
Stu student1 = new Stu();
student1.toShow();
student1.DoClass();
}
}
输出结果:
实例代码块1
学生姓名:李华
学生性别:男性
学生年龄:18
学生分数:100.0
学生在考试
李华在做家庭作业
李华在上课
我们发现实例代码块依然是最先被执行的。因此无关在类中实例代码块的位置,它都是最早被执行的。
3.3 ③静态代码块
3.3.1静态代码块的概念,作用,书写位置
概念:使用static定义的代码块称为静态代码块
作用:同理,静态代码块一般用于初始化静态成员变量。
书写位置:静态代码块所处的位置在方法的外面,类的里面,与静态成员变量处于同一等级。
3.3.2静态代码块的用法
在下面的代码中,不仅有静态代码块,还加了上面的实例代码块,不仅如此,我还添加了构造方法。如果又看不懂的也没有关系,你只需要看静态代码块部分就行了。
代码示例:
class Stu{
//成员变量
//普通成员变量
public String name; //学生姓名
public String gender; //学生性别
public int age; //学生年龄
public double score; //学生分数
//静态成员变量
public static int classRoom ; //学生班级
//实例代码块
{
this.name = "李华";
this.gender = "男性";
this.age = 18;
this.score = 100;
System.out.println("实例代码块1");
}
//静态代码块
static {
classRoom = 14; //静态代码块初始化
System.out.println("静态代码块1");
}
//构造方法
public Stu(String name, String gender, int age, double score) {
this.name = name;
this.gender = gender;
this.age = age;
this.score = score;
System.out.println("构造方法1");
}
//成员方法
//普通成员方法
public void DoClass(){
Exam();//在普通成员方法中可以直接调用静态成员方法
DoHomework();
System.out.println(this.name+"在上课");
} //
public void DoHomework(){
System.out.println(this.name + "在做家庭作业");
}
public void toShow(){
System.out.println("学生姓名:" + this.name);
System.out.println("学生性别:" + this.gender);
System.out.println("学生年龄:" + this.age);
System.out.println("学生分数:" + this.score);
System.out.println("学生班级" + Stu.classRoom);
}
//静态成员方法
public static void Exam(){
System.out.println("学生在考试");
}
}
public class Test {
public static void main(String[] args) {
System.out.println(Stu.classRoom);
Stu student1 = new Stu("LiHua","man",12,99.9);
student1.toShow();
System.out.println("-----------------------");
Stu student2 = new Stu("ZhangWei","man",11,100);
student2.toShow();
}
}
输出结果:
静态代码块1
14
实例代码块1
构造方法1
学生姓名:LiHua
学生性别:man
学生年龄:12
学生分数:99.9
学生班级14
-----------------------
实例代码块1
构造方法1
学生姓名:ZhangWei
学生性别:man
学生年龄:11
学生分数:100.0
学生班级14
如果只看静态代码块的部分,我们发现,它成功的给静态变量classRoom初始化,我们还成功的打印出了这个变量。当然了,我写了这么多代码,除了静态代码块的用法,还想去总结一些别的东西。
比如我们发现,
①分割线后面并没有打印静态代码块;
②并且实例代码块new了一个新对象后,再次被执行了;
③静态代码块位于实例化代码块后面但是却比实例化代码块先执行;
④实例化代码和构造方法都对普通成员变量进行了初始化,但是打印出来的是构造方法初始化的结果。
⑤没有实例化对象依然最先打印出了静态代码块
⑥实例化对象之后才打印出了实例化代码块
这是因为(不是没写完,是在3.4的总结里一一对应了上述问题哦!)
3.4总结
1.静态代码块不管生成多少个对象,它只会执行一次。
2.实例代码块每生成一个对象,就会被执行一次。
3.静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的,比实例化代码块,构造方法执行的早。
4.实例代码块比构造方法更早执行,因此最终的值是被构造方法初始化的
5.静态代码块不依赖于对象的产生。不管有没有对象,只要有类静态代码块都会被执行
6.实例化代码块依赖于对象的产生,只有对象产生了,实例化代码块才会被执行
执行顺序:
静态代码块 > 实例代码块(构造快) > 构造方法
备注:
如果有多个静态代码块,那么就按书写的顺序执行
如果有多个实例化代码块,那么就按书写的顺序执行
四、继承中代码的执行顺序(加上代码块)
我们已经知道
① 静态代码块先执行,并且只执行一次,在类加载阶段执行
② 当有对象创建时,才会执行实例代码块,实例代码块执行完成后,最后构造方法执行
那么加上继承的关系后,又是怎样的执行顺序呢?
父类的静态代码块 > 子类的静态代码块 > 父类的实例代码块 > 父类构造方法 > 子类的实例代码块 > 子类的构造方法
注意:
第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行,静态代码块只执行一次,它用于初始化静态成员变量。因为它是依赖于类的,因此只需要执行一次就能让每个对象都拥有它的值。
五、static成员变量初始化
5.1 就地初始化
5.2 静态代码块初始化
六、final关键字
2.1、final修饰变量
1.final修饰普通变量
final修饰普通变量,会使这个变量变为常量,不能再被更改。
2.final修饰引用变量
final修饰引用变量,会使这个引用变量中存的地址(哈希值),不能被更改。也就是不能让它指向新的空间。如:
final int[] array1 = {1,2,3,4,5}; 不能修改array1中存的这个空间的地址(哈希值),但是可以修改这个空间里存的数据。
2.2、final修饰方法
修饰方法:表示该方法不能被重写
2.3、final修饰类
修饰类:表示此类不能被继承
我们平时是用的 String 字符串类, 就是用 final 修饰的, 不能被继承.