JAVA之路(二)

本文详细解析了字段的多态特性、不同类型的代码块及其执行顺序,并探讨了final修饰符的作用及应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

十二、字段不存在多态特征

通过对象调用字段,在编译时期就已经决定了调用那一块内存空间的数据。
即:字段不存在覆盖的概念,在多态时,不能有多态特征(在运行时期体现子类特征)。只有方法才有覆盖的概念。

十三、代码块

在类或者方法中,直接使用{}括起来的一段代码,表示一块代码区域,代码块里的变量属于局部变量,只在自己的区域里有效。
根据代码块定义的位置,我们把代码块分成三种形式:
1.局部代码块:直接定义在方法内部的代码块:
  一般的,我们不会直接使用局部代码块的,只不过我们会使用if,while,for,try等关键字结合;

2.初始化代码——构造代码块:直接定义在类中
  每次创建对象的时候都会执行初始化代码块(每次创建对象之前会调用构造器,在调用构造器之前,会先执行本类中的初始化代码块):

public class CodeBlockDemo 
{
	{
		System.out.println("初始化代码块");
	}
	
	CodeBlockDemo()
	{
		System.out.println("构造器...");
	}
	
	public static void main(String[] args) 
	{
		System.out.println("进入main方法");
		new CodeBlockDemo();
		new CodeBlockDemo();
		new CodeBlockDemo();
	}
}

运行结果如下:

进入main方法
初始化代码块
构造器...
初始化代码块
构造器...
初始化代码块
构造器...

大家会很好奇,为什么会这样呢,当我们将字节码文件反编译之后,会发现实际上的代码是这样的:

public class CodeBlockDemo 
{
	CodeBlockDemo()
	{
		System.out.println("初始化代码块");
		System.out.println("构造器...");
	}
	
	public static void main(String[] args) {
		System.out.println("进入main方法");
		new CodeBlockDemo();
		new CodeBlockDemo();
		new CodeBlockDemo();
	}
}

但是…但是…但是…我们一般不用初始化代码块,一般在构造器中初始化。如果初始化操作很多,构造器结构很乱,我们可以重新定义一个方法,再在构造器中调用这个方法。

3.静态代码块:使用static修饰的初始化代码块:
在主方法之前执行静态代码块,而且只执行一次。

	static
	{
		System.out.println("初始化代码块");
	}
	
	CodeBlockDemo()
	{
		System.out.println("构造器...");
	}
	
	public static void main(String[] args) 
	{
		System.out.println("进入main方法");
		new CodeBlockDemo();
		new CodeBlockDemo();
		new CodeBlockDemo();
	}

输出结果为:

初始化代码块
进入main方法
构造器...
构造器...
构造器...

main方法是程序的入口点,那为什么静态代码块优先于main方法执行呢?

因为:静态成员随着字节码的加载也加载进JVM,此时main方法还没有执行,因为方法需要JVM调用。也就是先把字节码加载进JVM,然后JVM再调用main方法。

一般的,我们用来做初始化操作,加载资源,加载配置文件等等。。。(不同于初始化代码块对于每一个对象的初始化操作)

十四、一道有趣的面试题

问以下代码的执行顺序:

public class App {

	private static App d = new App();
	private SubClass t = new SubClass();
	
	static{
		System.out.println(3);
	}
	
	public App(){
		System.out.println(4);
	}
	
	public static void main(String[] args) {
		System.out.println("Hello");
	}
}

class SuperClass{
	SuperClass(){
		System.out.println("构造SuperClass");
	}
}

class SubClass extends SuperClass{
	static{
		System.out.println(1);
	}
	
	SubClass(){
		System.out.println(2);
	}
}

运行结果为:

1):1               //APP类依赖于SubClass类,因此要先把SubClass类加载进JVM
2):构造SuperClass  //非static字段的初始化其实都是在构造器中优先执行的
3):2			   //static对象的初始化实际都是在静态代码块中执行的
4):4
5):3
6):Hello

十五、final修饰符

为什么需要使用final修饰符:
  因为继承关系最大的弊端是破坏封装,子类能访问父类的实现细节,而且可以通过方法覆盖的形式修改实现细节。

  多个修饰符之间是没有先后关系的:public static finalpubic final staticfinal static public 都是可以的。final可以修饰非抽象类,非抽象方法和变量。但是构造方法不能用final修饰,因为构造方法不能被继承。

当满足以下条件就可以把类设计成final类:
1.某个类不是专门为继承而设计;
2.出于安全考虑,类的实现细节不允许改动;
3.确信该类不会被拓展

什么时候的方法要用final修饰:
1.在父类中提供的统一的方法骨架,不准子类通过方法覆盖来修改,此时使用final修饰;(模板方法设计模式)
2.构造器中调用的方法(初始化方法),此时一般用final修饰。

注意:final修饰的方法,子类可以调用,但是不可以覆盖。

final修饰的变量:表示常量,只能赋值一次,不能再次赋值。
1.final变量必须显示置顶初始值,系统不会为final字段初始化;
2.final变量一旦赋值,就不能再次赋值、

常量名规范:常量名符合标识符,单词全部大写,单词间使用下划线分隔。
比如:final int MAX_VALUE = 2147483647;

补充概念:全局静态变量:public static final修饰的变量,直接用类名调用。


面试题:final修饰的引用类型变量到底表示引用的地址不能改变,还是引用地址里的数据不能改变?
final修饰基本类型变量:表示该变量的值不能改变,即不能用“=”重新赋值;
final修饰引用类型变量:表示该变量的引用地址不能改变,而不是引用地址里的内容不能变。

final是唯一可以修饰局部变量的修饰符,目的何在?(内部类将介绍,局部内部类只能访问final修饰的局部变量)

什么时候使用常量:当在程序中,多个地方使用到共同的数据,而且数据不会改变,此时我们专门定义全局的变量。
一般的,我们在开发中会专门定义一个常量类,专门用来存储常量数据。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值