一、前言
java进阶篇已经开始了,先从面向对象开始,由于时间原因今天就只更新了static部分,内容上特别详细,一些特别的注意事项也在反复的提醒大家。
温馨提示一下,往后的java篇会越来越难,希望大家能够坚持下去。大家一起努力!!!
二、基础概念
定义静态变量
静态变量使用 static
关键字声明。通常在类级别、方法外部定义,并且在整个类的生命周期内存在一份实例。静态变量可以是基本数据类型(如 int
、double
等)或引用类型(如对象的引用)。
访问静态变量
静态变量可以通过类名直接访问,也可以通过对象实例访问,但推荐使用类名访问,因为静态变量不是对象的一部分。
静态变量的初始化
静态变量可以在声明时初始化,也可以在静态初始化块中初始化。静态初始化块在类加载时执行,并且仅执行一次。
特点与注意事项
-
类级别共享:静态变量的值对所有类的实例来说是共享的,它们只有一份拷贝存在于内存中。
-
生命周期:静态变量随着类的加载而初始化,而不是随着对象的创建而初始化。它们存在于整个类的生命周期内,直到程序结束或类被卸载。
-
线程安全:静态变量在多线程环境下可能存在并发访问的问题,因此需要考虑线程安全性,可以使用
synchronized
关键字或其他并发控制机制来保护静态变量的访问。 -
命名规范:通常静态变量的命名习惯是使用大写字母和下划线分隔单词(例如
MAX_SIZE
),以区分于实例变量。 -
应用场景:静态变量通常用于表示类的常量(如
Math.PI
)、计数器(记录类实例创建次数)、单例模式中的实例等场景。
三、static静态变量
看上图可以发现,李四的输出信息中没有老师的姓名,那是因为李四并没有给teacher这个变量赋值。
总所周知,在一个教室中,老师是学生们共有的,所以有没有一种方法使得所有学生都能有这一属性呢,答案当然是有的。这就得使用我们的static静态变量了。
代码优化:
Student.teacher = "李老师";
Student student = new Student();
student.setName("张三");
student.setAge(18);
student.setGender("男");
student.study();
student.show();
Student student1 = new Student("李四", 19, "女");
student1.study();
student1.show();
运行结果:
思考一下teacher这一变量并没有赋值给学生,但是每个学生都有这一属性。
这就是静态变量的神奇之处,
好好的去理解一下这句话。
只要在类中存在了,他就会存在于整个生命周期中。
静态变量的值对所有类的实例来说是共享的。
四、static内存图
图片出自黑马程序员
注:静态变量是随着类的加载而加载的,优先于对象出现。
注:静态区的变量是共享的
五、静态方法和工具类
几种常见的工具类
javabeen类
Java Bean 类是Java开发中常见的一种模式,它有助于实现数据的封装和重用,同时也是构建面向对象程序设计中的基础组件之一。
使用 Java Bean 类的场景:
- 数据封装:用于封装应用程序中的数据,提供简洁的访问和修改方式。
- 数据传输:用于传输数据,例如在客户端和服务器之间,或者在不同层之间。
- 框架兼容性:许多框架(如Spring等)利用 Java Bean 的约定进行依赖注入和配置管理。
测试类
在Java中,测试类通常用于编写和运行单元测试,以验证程序的各个部分是否按预期工作。这些测试类是独立的Java类,用于测试应用程序中的其他类或方法的功能和行为。
编写测试类的基本步骤
导入必要的类和方法:
- 根据选择的测试框架,导入正确的测试注解和断言方法。通常,需要导入类似于
org.junit.jupiter.api.Test
和org.junit.jupiter.api.Assertions.*
这样的类。
编写测试方法:
- 使用测试框架提供的注解(如
@Test
)标记测试方法,以便测试运行器能够识别它们。- 在方法中编写测试逻辑,通常包括调用待测试的方法或类,并使用断言来验证预期的行为或结果是否正确。
运行测试:
- 在集成开发环境(IDE)中,通常可以通过右键单击测试类并选择“运行测试”来直接运行单元测试。
- 也可以通过构建工具(如 Maven 或 Gradle)的测试插件来运行测试,或者使用命令行界面运行测试。
工具类
Java 中的工具类是一种常见的编程实践,用于封装一些常用的静态方法或者提供一些静态字段,以便在整个应用程序中方便地进行调用和重用。工具类通常不包含状态,其方法一般是无副作用的,主要用于功能性的操作。
静态方法:
工具类中的方法通常是静态的,可以直接通过类名调用,无需实例化对象。
私有构造函数:
通常会将工具类的构造函数声明为私有,以防止被实例化。因为工具类主要是为了提供静态方法,而不是创建对象。
常用的静态方法:
工具类可以包含各种常用的静态方法,例如字符串处理、日期操作、数学计算等。
无状态:
工具类通常不包含成员变量,也不维护状态,这样可以确保其方法的纯粹性,避免副作用。
实用性:
工具类主要用于封装一些通用的操作,提高代码的复用性和可维护性。在大型项目中特别有用,可以减少代码重复。
定义数组工具类
代码实现:
/**
* 将整数数组转换为字符串表示形式。
* 该方法通过StringBuilder构建数组的字符串表示,以避免使用+操作符连接字符串时的性能问题。
* 它遍历数组,并将每个元素添加到StringBuilder中,除了最后一个元素之外,每个元素后面都跟上一个逗号。
* 最后,方法返回StringBuilder的字符串形式,该字符串以方括号包围数组元素。
*
* @param arr 整数数组,要转换为字符串表示的数组。
* @return 字符串表示的数组,格式为"[元素1, 元素2, ..., 元素n]"。
*/
public static String printArray(int[] arr){
// 初始化StringBuilder以构建数组的字符串表示。
StringBuilder sb = new StringBuilder();
// 开始构建字符串,先添加左方括号。
sb.append("[");
// 遍历数组中的每个元素。
for (int i = 0; i < arr.length; i++) {
// 如果当前元素是最后一个元素,就不添加逗号。
if (i == arr.length - 1){
sb.append(arr[i]);
}else {
// 对于其他元素,在其后面添加逗号。
sb.append(arr[i]).append(",");
}
}
// 完成构建字符串,添加右方括号。
sb.append("]");
// 返回构建好的字符串表示的数组。
return sb.toString();
}
/**
* 计算数组的平均值。
*
* @param arr2 一个double类型的数组,用于计算平均值。
* @return 返回数组所有元素的平均值。
*/
public static double getAverage(double[] arr2){
double sum = 0; // 初始化累加和为0
// 遍历数组,累加数组中的每个元素
for (int i = 0; i < arr2.length; i++) {
sum += arr2[i];
}
// 返回累加和除以数组长度得到的平均值
return sum / arr2.length;
}
结果展示:
定义学生工具类
代码实现:
/**
* StudentUtil类是一个工具类,用于学生信息的操作。
* 该类被设计为不可实例化,通过提供静态方法来服务。
*/
private StudentUtil(){}
/**
* 获取学生列表中最大的年龄。
*
* @param list 一个ArrayList类型的学生列表,不能为空。
* @return 返回学生列表中的最大年龄。
*
* 注意:该方法假设列表至少有一个学生,没有进行空列表的检查。
*/
public static int getMaxAge(ArrayList<Student>list){
/* 初始化最大年龄为列表第一个学生的年龄 */
int maxAge = list.getFirst().getAge();
/* 遍历学生列表,寻找最大年龄 */
for (Student student : list) {
/* 如果当前学生的年龄大于已知的最大年龄,则更新最大年龄 */
if (student.getAge() > maxAge) maxAge = student.getAge();
}
/* 返回找到的最大年龄 */
return maxAge;
}
结果展示:
六、static注意事项和使用场景
静态字段:
静态字段属于类而不是实例。这意味着所有实例共享同一个静态字段的值。应谨慎使用静态字段,因为它们的状态是全局的,并可能导致并发访问问题。
静态方法:
静态方法可以直接通过类名调用,无需实例化对象。通常用于实现工具类、工厂方法或者在没有实例化对象时执行某些操作的情况。静态方法不能访问非静态方法或者实例变量,因为它们没有隐式的
this
引用。
静态块:
静态块用
static { ... }
来声明,它在类加载时执行,并且仅执行一次。通常用于初始化静态字段或执行静态方法。
静态类:
如果类被声明为
static
,那么它通常是一个内部类,表明它不需要外部类的实例即可被实例化。静态内部类不能直接访问非静态的外部类成员。
注意事项:
- 线程安全性:静态字段和方法是类级别的,可能会影响多个实例或线程。确保在多线程环境下使用时考虑到线程安全性。
- 单例模式:静态方法和块常用于实现单例模式。确保单例的唯一性和线程安全性是使用静态的重要考虑因素。
- 依赖注入:静态方法或字段不适合用于依赖注入,因为它们导致代码紧耦合,并使得单元测试变得困难。
- 静态导入:
- 使用
import static
可以导入静态方法和字段,使得在使用时可以不通过类名而直接访问。这在某些情况下可以提高代码的可读性,但也要避免滥用,以免降低代码的可维护性。