查看: 96|回复: 0

【技术浅谈】Java 中的 static,其实还有不为人知的一面 ...

[复制链接]

2

主题

5

帖子

8

积分

新手上路

Rank: 1

积分
8
发表于 2023-6-18 16:49:47 | 显示全部楼层 |阅读模式
上期小编为大家介绍了PyTorch入门教学7。这里是上一期文章的链接:
本期,小编将浅谈一下Java 中的 static,其实还有不为人知的一面?
前言

即使是初学 Java 的程序员,也一定知道 static 修饰符的基本作用:声明静态变量和静态方法。然而,其实 static 还可以做到更多!有些语法看似生僻,但熟练掌握后便可轻松提高编程效率。今天就让我们一起整理一些特殊但又实用的 static 用法。
1. static final 修饰变量

这是 static 最常见的用法之一,相信大家也或多或少会在代码中见到或自己使用过。final 修饰的变量一经赋值,便无法改变,也就是所谓的 常量。而加上了 static,我们就可以绕开具体的对象通过类名直接获得该常量的值。因此,在实际的项目中经常能看到一些类里写了大量用 public static final 修饰的变量以供其它类调用。比起直接把值写在代码中,使用常量既提高了代码可读性,又使我们想要修改这些值的时候可以以一持万,事半功倍。
然而 static final 还有一个非常容易被误解的用法:用 private static final 来修饰 私有 变量。有些人会认为,既然是私有变量,那么就只有本类会访问,设定成 static 并没有意义。也就是说,private static final 和 private final 的作用是相同的:


大错特错!不使用 static 修饰的变量,仅仅是某个 对象 的“常量”。换句话说,类中的每一个对象都可能有不同的值。如何做到这一点?别忘了,final 修饰的变量除了能在声明时直接赋值之外,还可以 在构造器里赋值:


然而,又会有人觉得即使是想要表达整个类的常量,只要在声明时赋值,private final 似乎也已经足够了:


抛开降低代码可读性带来的麻烦不谈,这样定义类的常量还有个坏处:由于每个对象都会生成一个不同的 EPSILON,这将占据更多的内存空间。
结论:即使是 private 的常量,也一定要加上 static。
2. import static

严格来说,这里的 static 不算是修饰符,但这仍是一个非常实用的语法。看看下面的代码:




注意到问题了吗?每次用到类中的常量,都要重新写一遍类名。如果用到的常量在别的类中并没有重名的,就单纯只是显得十分啰嗦。而使用 import static 就能轻松解决这个问题:
这里我们用到了 * 号来导入类中的所有静态成员。你也可以用具体的名称导入单一的变量。另外,这种导入方法 不仅可以用于常量,一般的静态变量或方法其实都可以使用:


3. static 修饰内部类

除了修饰变量或方法,static 还能用于修饰内部类的定义。实际上,开发中 static 的内部类可能比非静态的还要常见。下面这个代码展示了两种内部类在使用上的区别:


可以看到,不带 static 的内部类在实例化时必须通过外部类的对象,而带 static 的内部类则可直接实例化。因此,static 修饰的内部类通常是一些和外部对象不直接产生关系的类。一般来说,static 的内部类主要有两个作用:
1.整理有关联的类以 提高代码可读性。比如驾驶员、轮胎、座位等和汽车相关的类,如果只有汽车用得到,那么没必要分别写在不同的代码文件中。
2.控制某些类的 访问权限。比如,可以在定义时设定内部类或其构造器的访问权限,使其只能被外部类访问或创建。此外,内部类可以直接访问到外部类的 private static 变量。
考虑到对于公开访问权限的内部类,上述的第 1 点作用可以被 package 取代,在实践中以被 private 修饰的内部类居多。
4. static 修饰代码块

最后一个用法是使用 static 直接修饰一段代码。要了解 static 代码块,首先得知道初始化块的写法:


在这个例子中,我们 直接在类中写了一个代码块。这段代码会在类被实例化时,在构造器运行之前被运行一次。
而 static(初始化)块同样是直接写在类里:


static 块中的代码会在类被第一次用到时被执行一次,并且 不管之后实例化了几个对象,都不会再次执行。总结一下,在我们实例化类时,各种初始化代码的实行顺序是这样的:


然而我们更关心的是,这种语法到底有什么用?比如上例中的变量,完全可以在声明时直接赋值为 10。我们在哪些场景下会使用到 static 块呢?
首先,static 代码块可以帮我们初始化一些一行代码无法解决的 复杂初始化。比如下面这个例子:


同时,static 代码块 不止能初始化变量。一些环境设定、文件读写之类的操作,只在变量声明中显然是无法完成的:


至于不带 static 的初始化块,其应用场景就比较少了,因为你完全可以把同样的代码写在构造器里。一种可能的用途是 初始化匿名内部类(因为匿名内部类没有构造器)。
总结

本期的内容到这里就结束啦,我们下期再见~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表