前言:
当前各位老铁们对“javastatic一般用法”可能比较珍视,我们都想要了解一些“javastatic一般用法”的相关内容。那么小编在网上汇集了一些对于“javastatic一般用法””的相关文章,希望你们能喜欢,各位老铁们一起来学习一下吧!说到static,静态变量和静态方法大家随口就来,因为他们在实际开发中应用很广泛,但他们真正在使用的时候会存在很多问题,而且它的使用不只那两种:
1.静态变量。
2.静态方法。
3.静态代码块。
4.静态内部类。
5.静态导入。
接下来我们看一下这些用法。
1.静态变量
静态变量属于类,内存中只有一个实例,当类被加载,就会为该静态变量分配内存空间,跟 class 本身在一起存放在方法区中永远不会被回收,除非 JVM 退出。
【实例】实际开发中的日期格式化类SimpleDateFormat会经常用到,所以会创建一个工具类DateUtil不让代码重复,但它在高并发情况下是存在线程安全问题的,代码复现:
虽然有volatile使对象可见,但运行后有一定几率会报java.lang.NumberFormatException: multiple points或For input string: ""等错误,原因是多线程都去操作一个对象:
解决办法:1.使用私有的对象。2.加锁。3.ThreadLocal。4.使用第三方的日期处理函数。5.Java8推出了线程安全、简易、高可靠的时间包,里面有LocalDateTime年月日十分秒;LocalDate日期;LocalTime时间三个类可供使用。
下图是使用私有对象和ThreadLocal解决高并发状态的图解。
本文给出使用私有的对象和加锁两种实现代码,ThreadLocal方式读者可以尝试自己实现:
2.静态方法
静态方法和非静态方法一样,都跟class 本身在一起存放在内存中,永远不会被回收,除非 JVM 退出,他们使用的区别的一个方面是非static方法需要实例调用,static方法直接用类名调用。
【实例】一般工具类中的方法都写成static的,比如我们要实现一个订单导出功能,代码如下:
运行后orderService会是null,原因不是Spring没注入,而是static方法给它"清空"了。解决方案一:@PostConstruct,它修饰的方法会在服务器加载Servlet时执行一次,代码如下:
每个工具类都要去加上@PostConstruct注解,代码重复性高。那我们可不可以直接从Spring容器中获取Bean实例?
解决方案二:ApplicationContextAware
通过它Spring容器会自动把上下文环境对象注入到ApplicationContextAware接口的实现类中setApplicationContext方法里。
换句话说,我们在ApplicationContextAware的实现类中,就可以通过这个上下文环境对象得到Spring容器中的Bean。
首先,在web项目中的web.xml中配置加载Spring容器的Listener:
然后,实现ApplicationContextAware接口:
最后,在Spring配置文件中注册该工具类:
<bean id="springContextBean" class="com.test.SpringContextBean"></bean>
原来的导出工具类代码可以简化到如下:
3.静态代码块
所谓代码块是指使用“{}”括起来的一段代码。其中静态代码块只执行一次,构造代码块在每次创建对象是都会执行。根据位置不同,代码块可以分为四种:普通代码块、构造块、静态代码块、同步代码块。
【实例】因为JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配。所以实际工作中我们可以使用静态代码块初始化一些不变的属性:
但是静态代码块和静态变量初始化有什么关系?在上文的单例模式中,我们使用了静态代码块来创建对象,为何那那样写?我在网上看到了这样一段代码:
上面的结果是10还是20?如果存在多个代码块呢?
其实测试过后你会发现两个答案结果都是20。
因为 public static int _i = 10; 和如下代码是没有区别的:
public static int _i; static { _i = 10; }
他们在编译后的字节码完全一致(读者可以使用javap -c命令查看字节码文件),所以两个例子的结果就是最后一次赋值的数值。
4.静态内部类
在定义内部类的时候,可以在其前面加上一个权限修饰符static,此时这个内部类就变为了静态内部类。
【实例】LinkedList使用了如下静态内部类:
其实在数据结构中我们把next和prev称为前后节点的指针,HashMap内部也使用了静态内部类Entry的数组存放数据。为了加深理解,读者可以亲自运行以下的代码来体会一下静态内部类。
总结一下静态内部类:
1.加强代码可读性。如:StaticInternal.InnerStaticClass inner = new StaticInternal.InnerStaticClass();
2.多个外部类的对象可以共享同一个静态内部类的对象。
3.静态内部类无需依赖于外部类,它可以独立于外部对象而存在。因为静态类和方法只属于类本身,并不属于该类的对象,更不属于其他外部类的对象。
5.静态导入
静态导入是JKD1.5后新加的功能,一般不怎么常用,了解即可。有时候面试答出来这个会让别的觉得你热爱技术。
【实例】 静态导入写法如下:
是不是方便了许多?但别着急偷懒,因为使用它过多会导致代码可读性差。
或许你知道PI是Math类的方法,那bitCount是Math类还是Integer类的方法呢?所以要尽量避免使用static导入,实在要导入的话,去掉*号通配符,直接写成:
java.lang.Integer.bitCount(11);
我是个普通的程序猿,水平有限,文章难免有错误,欢迎牺牲自己宝贵时间的读者,就本文内容直抒己见,我的目的仅仅是希望对读者有所启发。
标签: #javastatic一般用法