什么时候该用类方法(静态方法)?什么时候该用实例化方法?

2023-10-11 03:50

本文主要是介绍什么时候该用类方法(静态方法)?什么时候该用实例化方法?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一个新来的同事,写Java方法时,通篇都是static修饰,原因只是因为不需要new对象就可直接调用。一个类中抽象出来的方法,用static修饰无可厚非,但是一般而言,抽象出来的公共方法,大多都应该放在util工具类中,而不是直接写在该类中。static修饰的静态方法,虽然调用简单而且也快,但是实际编程中,不建议这么做。

这并非是因为静态方法占用内存更高,而是因为我们只有理解其原理,才能更好地应用到实际编程中。比如为什么有时候需要用单例模式,而不是静态方法?比如加载某些配置和属性,需要在整个生命周期存在,但仅仅只需要维护一份,但此时这些配置和属性又是通过面向对象的方式得到的,这个时候就要用单例模式,虽然用静态方法也能解决,但最好的方式还是采用单例模式。

所以,什么时候用静态方法呢?

1)工具类中的常用方法,不需要依赖具体实例,而且使用频率高。

2)不需要对象的“轻”方法,因为静态方法是无法直接使用任何非静态成员的,除非将实例作为参数传入。

那么,什么时候应该使用实例化方法呢?
方法依赖于类对象的时候,就应该使用实例化方法,因为在多线程场景下对静态方法中的静态变量进行更改操作易造成线程安全问题,这个时候,就一定要用实例化方法。

public class TestStatic {static class test {//静态成员变量static String a = "H";//修改该静态成员变量static void modify(String v) {a = v;}}public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(() -> {test.modify(Thread.currentThread().getName());System.out.println(Thread.currentThread().getName() + ":" + test.a);}).start();}}}

为什么会出现上述结果呢?

Java内存模型中,堆中存放对象示例、静态成员变量、数组元素等,这每个对象示例都有一把对应的锁监视器,而类的静态成员变量归类.class所有,所以上述的静态方法,相当于直接把共享变量a指向了v的引用,在多线程的情况下,如果一个线程修改了一个类的静态变量,再获取获该类的变量时,就有可能获取到的是被其他线程修改后的变量,所以说这种情况线程不安全。

那么如何解决这个问题呢?答案就是加锁。

public class TestStatic {static class test {// 静态成员变量static String a = "H";// 修改该静态成员变量static void modify(String v) {a = v;}}public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(() -> {synchronized (test.class) {test.modify(Thread.currentThread().getName());System.out.println(Thread.currentThread().getName() + ":" + test.a);}}).start();}}}输出:
Thread-4:Thread-4
Thread-7:Thread-7
Thread-6:Thread-6
Thread-5:Thread-5
Thread-1:Thread-1
Thread-2:Thread-2
Thread-0:Thread-0
Thread-3:Thread-3
Thread-9:Thread-9
Thread-8:Thread-8

另外一种方法,就是不要用静态方法,改成实例化方法,比如:

public class TestStatic {public static void main(String[] args) {test te = new test();for (int i = 0; i < 10; i++) {new Thread(() -> {te.modify(Thread.currentThread().getName());System.out.println(Thread.currentThread().getName() + ":" + te.a);}).start();}}}class test {// 静态成员变量String a = "H";public String getA() {return a;}public void setA(String a) {this.a = a;}public test(String a) {super();this.a = a;}public test() {}// 修改变量void modify(String v) {a = v;}
}

 

这篇关于什么时候该用类方法(静态方法)?什么时候该用实例化方法?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/185306

相关文章

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

504 Gateway Timeout网关超时的根源及完美解决方法

《504GatewayTimeout网关超时的根源及完美解决方法》在日常开发和运维过程中,504GatewayTimeout错误是常见的网络问题之一,尤其是在使用反向代理(如Nginx)或... 目录引言为什么会出现 504 错误?1. 探索 504 Gateway Timeout 错误的根源 1.1 后端

MySQL 表空却 ibd 文件过大的问题及解决方法

《MySQL表空却ibd文件过大的问题及解决方法》本文给大家介绍MySQL表空却ibd文件过大的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录一、问题背景:表空却 “吃满” 磁盘的怪事二、问题复现:一步步编程还原异常场景1. 准备测试源表与数据

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消

SpringBoot通过main方法启动web项目实践

《SpringBoot通过main方法启动web项目实践》SpringBoot通过SpringApplication.run()启动Web项目,自动推断应用类型,加载初始化器与监听器,配置Spring... 目录1. 启动入口:SpringApplication.run()2. SpringApplicat