final关键字(1)

}

// 不可变类定义要求:2.不对外提供实例变量set方法

public int getNum() {

return num;

}

public String getDesc() {

return desc;

}

public Person getPerson() {

// 不可变类定义要求:5.如果实例变量类型是可变类类型,则不能直接将该实例变量的原始值提供出去,而是创建一个备份值提供出去

return new Person(person.getName(),person.getAge());

}

@Override

public String toString() {

return “FinalTest2{” +

“num=” + num +

“, desc='” + desc + ‘’’ +

“, person=” + person +

‘}’;

}

}

// Person类是一个可变类

class Person{

String name;

int age;

public Person(String name, int age) {

this.name = name;

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

@Override

public String toString() {

return “Person{” +

“name='” + name + ‘’’ +

“, age=” + age +

‘}’;

}

}

class Main2{

public static void main(String[] args) {

FinalTest2 finalTest2 = new FinalTest2(10, “desc”, new Person(“qfc”, 10));

System.out.println(finalTest2);

finalTest2.getPerson().setAge(60);

finalTest2.getPerson().setName(“qfc father”);

System.out.println(finalTest2);

}

}

缓存不可变类实例


package finalTest;

import java.util.Arrays;

// 缓存不可变类实例

// 1.定义一个不可变类

public class CacheUnChangedTest {

private final String name;

private final int age;

// 4.创建一个容量合适的容器,来存储不可变类实例

private static CacheUnChangedTest[] cArr = new CacheUnChangedTest[3];

// 5.定义一个位置变量,来标记容器中实例存储的最新位置

private static int pos = 0;

// 2.私有化不可变类构造器

private CacheUnChangedTest(String name, int age) {

this.name = name;

this.age = age;

}

// 3.提供一个公有方法对外提供新创建或缓存过的实例

public static CacheUnChangedTest getInstance(String name,int age){

// 6.判断需要提供的实例是否已经创建过了?如果创建过了,则从容器中取出提供;如果未创建,则创建一个新的实例,加入到容器中,并提供出去

// 定义对外提供的实例变量 c

CacheUnChangedTest c = null;

System.out.println(“缓存池中的实例:”+Arrays.toString(cArr));

// 定义flag来标识外部需要的实例是否已经创建过,true表示已经创建过,false表示没有创建过

boolean flag = false;

// 遍历容器元素,判断外部需要的实例是否已经缓存过了?

for (CacheUnChangedTest cacheUnChangedTest : cArr) {

// 具体判断实例相同的标准可以自己定,只要在缓存池cArr中发现了相同的实例,则终止循环,直接提供缓存池中的实例给外部,而不需要创建新的实例

if (cacheUnChangedTest != null && cacheUnChangedTest.getName().equals(name) && cacheUnChangedTest.getAge() == age) {

flag = true;

c = cacheUnChangedTest;

break;

}

}

// 如果外部需要的实例还没有被创建过

if (!flag) {

// 则直接创建一个新的实例

c = new CacheUnChangedTest(name,age);

// 并且存入缓存池中

if (pos != cArr.length) {

// 如果缓存池还没有存满,则继续存

cArr[pos++] = c;

} else {

// 如果换存储已经存满了,则将位置变量变为0,从头开始重新覆盖存

pos = 0;

cArr[pos] = c;

}

}

return c;

}

public String getName() {

return name;

}

public int getAge() {

return age;

}

@Override

public String toString() {

return “CacheUnChangedTest{” +

“name='” + name + ‘’’ +

“, age=” + age +

‘}’;

}

}

class Main3{

public static void main(String[] args) {

CacheUnChangedTest c1 = CacheUnChangedTest.getInstance(“qfc”,18);//缓存池中的实例:[null, null, null]

CacheUnChangedTest c2 = CacheUnChangedTest.getInstance(“zyx”,19);//缓存池中的实例:[CacheUnChangedTest{name=‘qfc’, age=18}, null, null]

CacheUnChangedTest c3 = CacheUnChangedTest.getInstance(“孙悟空”,18);//缓存池中的实例:[CacheUnChangedTest{name=‘qfc’, age=18}, CacheUnChangedTest{name=‘zyx’, age=19}, null]

CacheUnChangedTest c4 = CacheUnChangedTest.getInstance(“qfc”,18);//缓存池中的实例:[CacheUnChangedTest{name=‘qfc’, age=18}, CacheUnChangedTest{name=‘zyx’, age=19}, CacheUnChangedTest{name=‘孙悟空’, age=18}]

System.out.println(c4 == c1);//true

CacheUnChangedTest c5 = CacheUnChangedTest.getInstance(“zyx”,19);//缓存池中的实例:[CacheUnChangedTest{name=‘qfc’, age=18}, CacheUnChangedTest{name=‘zyx’, age=19}, CacheUnChangedTest{name=‘孙悟空’, age=18}]

System.out.println(c5 == c2);//true

CacheUnChangedTest c6 = CacheUnChangedTest.getInstance(“zyx1”,18);//缓存池中的实例:[CacheUnChangedTest{name=‘qfc’, age=18}, CacheUnChangedTest{name=‘zyx’, age=19}, CacheUnChangedTest{name=‘孙悟空’, age=18}]

CacheUnChangedTest c7 = CacheUnChangedTest.getInstance(“qfc”,18);//缓存池中的实例:[CacheUnChangedTest{name=‘zyx1’, age=18}, CacheUnChangedTest{name=‘zyx’, age=19}, CacheUnChangedTest{name=‘孙悟空’, age=18}]

System.out.println(c7 == c1);//false

}

}

思考题

===

1.Java是否允许访问未初始化的final成员变量?或者请看下面代码的运行结果是什么?(final设计缺陷,好玩的题目)


public class Main5 {

final int a;

{

test();

a = 6;

System.out.println(a);

}

private void test() {

System.out.println(a);

}

public static void main(String[] args) {

Main5 main = new Main5();

}

}

这个题目是在李刚老师的疯狂java讲义上看到的。(第五版的181页)

我们一般理解final修饰的成员变量如下:

final修饰的成员变量,系统不会自动初始化,而需要程序员显式初始化。而在变量初始化之前,是不建议使用该变量的。

但是java还有一个规则:

Java允许在final成员变量显式初始化前,通过方法访问final成员变量。

那么在final成员变量显式初始化之前,final成员变量理论上没有值的。但是经过方法访问后,final成员变量的值就会变成0.

且还能被重新赋值。

按照李刚老师的结论,这是final设计的缺陷。违反了final的初衷:1.final修饰的成员变量只能显式初始化 2.final修饰的成员一旦初始化,就不能再次赋值。

所以:李刚老师建议:在final成员变量显式初始化之前,不要访问final成员变量。

2.final修饰基本类型变量和引用类型变量的区别?


我们知道:final修饰的变量一旦初始化后,就不能二次赋值了。

这个结论可以换种方式说:

举例:

final 变量类型 变量名 = 变量值;

初始化就是:增加一个指向,即(变量名)指向(变量值)

被final修饰意味着:指向就不能再改变了。

对于基本类型而言,它们的(变量值)就是字面量,字面量是无法改变的。所以“指向”无法改变,“变量值”无法改变,则基本类型变量被final修饰后就是一个固定常量。

对于引用类型而言,它们的(变量值)是对象,对象是有内容的(即对象的成员变量),final只能约束“指向”无法改变,无法约束“变量值”的内容不能改变。则引用类型被final修饰后,指向的对象的内容是有可能改变的。

如何保证对象的内容不被改变?那么就需要将对象的类型定义成不可变类。

3.什么是宏变量?


宏变量的定义:

1.变量被final修饰

2.变量在声明时被初始化

3.变量指向的值,在编译期就能确定

宏变量的作用:

编译器可以在编译期将使用宏变量的地方全部替换成变量值。

4.final修饰的方法是否可以重载?


final修饰的方法有如下特点:

1.不能被子类重写

2.不能再被abstract修饰

所以final修饰的方法只是限制了父子类之间方法重写。

方法重载指:在同一个类中,方法名相同,方法的形参不同(形参个数,形参类型,形参顺序不同)的方法。方法重载与访问权限修饰符,方法返回值类型无关。

final修饰的方法可以重载。重载的方法可以是非final的。

如下代码是针对final方法的重载:

public class FinalMethodReLoadTest {

final void test(String a,int b,Double d){

}

void test(Double daa,String abc,int bca){

}

final String test(int a){

return “”;

}

}

5.final类和不可变类的区别?


被final修饰的类的特点:

1.不能派生子类,即不能被其他类继承

2.不能被abstract修饰,即不能定义为抽象类

不可变类的概念是:

不可变类的对象的实例变量不会改变。

所以两者是不同的概念。很多人错误的理解final类就是不可变类,这是对不可变类的概念不清晰导致的。

6.不可变类的(实例变量)【类型】如果是(可变类类型),那么如何保证这个(可变类类型)的(实例变量)指向的对象内容不会变更?


两种方案:

1.把这个实例变量的类型的类定义改成不可变类模式。

2.通过一个备份值来保证(可变类类型)实例变量的指向对象不会被改变。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

结尾

正式学习前端大概 3 年多了,很早就想整理这个书单了,因为常常会有朋友问,前端该如何学习,学习前端该看哪些书,我就讲讲我学习的道路中看的一些书,虽然整理的书不多,但是每一本都是那种看一本就秒不绝口的感觉。

以下大部分是我看过的,或者说身边的人推荐的书籍,每一本我都有些相关的推荐语,如果你有看到更好的书欢迎推荐呀。

戳这里免费领取前端学习资料

Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中…(img-ZBNF4rsA-1713486009163)]

[外链图片转存中…(img-4pc7Czud-1713486009164)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-5BJHR2so-1713486009164)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

[外链图片转存中…(img-WRrZ5idS-1713486009165)]

结尾

正式学习前端大概 3 年多了,很早就想整理这个书单了,因为常常会有朋友问,前端该如何学习,学习前端该看哪些书,我就讲讲我学习的道路中看的一些书,虽然整理的书不多,但是每一本都是那种看一本就秒不绝口的感觉。

以下大部分是我看过的,或者说身边的人推荐的书籍,每一本我都有些相关的推荐语,如果你有看到更好的书欢迎推荐呀。

戳这里免费领取前端学习资料

前端学习书籍导图-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值