◉ 代码块
代码块分为:静态代码块和实例代码块
位置:出于类体之中,方法体之外
特点:不需要调用,直接执行
作用:用于需要的一些提前准备
静态代码块
格式:static { … }
在类被加载的时候,该代码块就同时地被执行一次
实例代码块
格式:{ … }
在类被实例化时,该代码块就同时地被执行一次
特点:实例代码块优于构造器执行,可以简化构造器的代码,将前面部分相同的提取出来。
◉ == 和 equal 的区别
唯一区别:
在判断字符串时,“==” 要求两个字符串必须指向同一个对象,而 equals 只要求两个字符串序列相等。
除此之外,在 equals 没有被重写时,两者等同:
对于数值类型,只要前后的值相等就true;对于引用数据类型,必须是指向同一个对象才返回true
◉ 字符串的存放机制
新的字符串会在字符串常量池被创建出来,往后如果再有相同的字符串出现,便不再新创建而是直接使用
创建新字符串对象时,会先在常量池中寻找是否有该字符串,没有则新创建一个,然后还得在堆内存中创建一块空间存放对象,再将对象指向常量池中的字符串。所以,如果以new的方式创建字符串且是新的字符串,那么一共会开辟两块内存。
◉ 单例
条件:构造器私有,只能暴露一个对象
最简单的写法:public static final 类名 对象名 = new 构造器();
◉ final 关键字
使被修饰的成为最终类,有以下效果:
① 使类无法被继承
② 使方法无法被重写
③ 使变量一旦被赋值之后,就不能再次被赋值
也就是说成为常量了
—— 注意点:
当 final 修饰实例变量时,由于实例变量会默认赋初值 0 ,所以需要我们手动给予初值(否则造成值永远为 0 而无法修改)
—— 基于此:
Java 规定实例变量必须先赋初值,而不能在方法中才去赋值
—— 赋值地方:
① 在声明时直接赋值
② 在代码块中赋值
③ 在构造器中赋值
public class Test
{
// 第一种方法
final int a = 10; // 直接在初始化处赋值
// 第二种方法
final int b;
final static int c;
// 第三种方法
final int d;
{
b = 10; // 非静态实例变量实例代码块中赋值
}
static
{
c = 10; // 静态实例变量在静态代码块中赋值
}
public Test(int d)
{
this.d = d; //在构造器中赋值
}
}
— 理解:
这三种方法都有一个共同点,那就是在执行的同时赋值了,保证了 final 确确实实是拥有初始值的
如果是在方法中赋值,那只要不调用就没有赋值,对 final 的初始值没有保证,所以 Java 不允许这样 [ 冰澈如是说道 ]
— 发掘:
基于上面的理解,不难发现如果有多个构造器,那么必须保证所有构造器都实现了对 final 成员变量的赋值,否则就不能保证 final 有初值,就会报错!
— 优化:
如果想定义常量,除了用 final 修饰,最好还要加上 static
因为既然是常量了,就没必要每个实例都开辟一块内存去存放它多浪费啊,直接定义成静态,只占一份内存,就可以让所有实例去访问啦~
定义:public static final int MY_NAME = "IceClean"
当然,常量命名规范还是要注意的~
- 需要全部使用大写
- 有多个单词时,使用下划线分隔
- 而且常量一般是公开的,所以加 public
结论: final 修饰的实例变量一般和 static 联合使用变成常量
附加:
面试题:String 能被继承吗?
答案:不能,因为 String 被 final 修饰了!
④ 使引用一旦指向某个对象后,不能再重写指向
这个和 ③ 的本质相同,都是不能被二次赋值
但是修饰引用也有了新的注意地方:
- 该引用所指向的对象无法被垃圾回收器回收,直到程序结束。
- 对象内部的数据依旧可以被修改
public static final IceClean iceClean = new IceClean();