【Java基础】静态类
来源:互联网 发布:吴京直男癌 知乎 编辑:程序博客网 时间:2024/06/06 05:32
前几天在交流IOC的时候,提到了静态类的写法,我的一个误区静态类 长这个样子:
public static class StaticClass{ //TODO}然鹅,“事与愿违”,静态类直接在class前加入"static"在Java中是一种错误的写法,在北京工作的时候由于写过工具类就天真的认为java的世界中也是酱紫,那就正好整理下在java语言中静态类如何玩吧。
一、分类
(1)外部静态类
public class StaticClass1{ //静态成员变量 //静态成员方法}
(2)内部静态类
class OuterClass{ //普通成员变量 //静态成员变量 static class InnerStaticClass{ //静态或非静态成员变量 //静态或非静态成员方法 }}
二、实例举例
(1)内部静态类(外部就不予展示,很常见)
package StaticClass;class Outer { private String name; private int age; public static class Builder { private String name; private int age; public Builder(int age) { this.age = age; } public Builder withName(String name) { this.name = name; return this; } public Builder withAge(int age) { this.age = age; return this; } public Outer build() { return new Outer(this); } } private Outer(Builder b) { this.age = b.age; this.name = b.name; }}public class StaticClass1 {public static void main(String[] args) {Outer outer = getOuter();System.out.println(outer.toString());}public static Outer getOuter(){ Outer outer = new Outer.Builder(25).withName("Vincent").build(); return outer;}}参考上述代码,如果一个类被声明为static,只有一种情况,就是静态内部类。(Attention:把上述这个例子搞清楚了,静态内部类就没有问题了。)
同时,比较静态内部类和普通内部类有几点不同:
(1)静态内部类跟静态方法一样,只能访问静态的成员变量和方法,不能访问非静态的方法和属性,但是普通内部类可以访问任意外部类的成员变量和方法。
(2)静态内部类可以声明普通成员变量和方法,而普通内部类不能声明static成员变量和方法。
三、静态类的特点
谈及静态类的特点,也是为什么要使用静态类的原因
(1)静态类的数据在全局是唯一的,一改都改。如果你想要处理的东西是整个程序中唯一的,弄成静态是个好方法。 非静态的东西你修改以后只是修改了他自己的数据,但是不会影响其他同类对象的数据。
参考下午我设计的一个demo:
public class StaticClass2 {public static void main(String[] args){//第一次调用StaticClass2中的值aSystem.out.println("StaticClass2中a的值为: " + TestStaticClass.a);//通过另外一个类来修改StaticClass2中a的值TestStaticClass1 testStaticClass1 = new TestStaticClass1();testStaticClass1.test();//第二次调用StaticClass2中的值aSystem.out.println("StaticClass2中a的值为: " + TestStaticClass.a);}}class TestStaticClass{static int a = 3;static int b;static{System.out.println("inti data2");b = a * 3;}}class TestStaticClass1{public void test(){TestStaticClass.a = 6;}}执行结果如图:
从这个输出结果看,StaticClass2中的静态成员变量a的值被其他类的对象修改之后,main方法再去拿一次,值已经变掉了。。。。
(2)引用方便,直接通过“类名.静态方法名”或者“类名.静态变量名”就可以使用并修改期属性值,不用通过get()和set()方法来做。
四、对比“对象实例化”与“静态类的静态块”
前些天在复习JVM的时候,学习了类的加载机制,其中在“初始化”的阶段,有主动和被动之区别,对于静态的成员变量、静态块就是主动的初始化。但是当时没有理解“静态块”和实例化new初始化之间的关系,在这里做个总结,看一个demo:
public class StaticClass3 {public static void main(String[] ars){ A ab = new B(); //记为A。执行到此处,结果是: ab = new B(); //记为B。执行到此处,结果是: B bb=new B();//记为C。执行到此处,结果是: }}class A {static {System.out.print("1");}public A() {System.out.print("2");}}class B extends A {static {System.out.print("a");}public B() {System.out.print("b");}}
可以执行一下main()方法,看看会有什么样的结果,在main()中是有三行代码的,
(1)“A ab = new B();”
(2)“ab = new B();”
(3)“B bb = new B();”
我操作的方法是先都注释掉,然后一行一行的放开注释,打印的结果是这样的:
"1a2b","1a2b2b","1a2b2b2b"
如上的操作结果,说明其实多次new实例化的过程中,satatic{}块中的代码,仅仅被执行了一次,然而new执行的构造方法的调用,是每次都运行的。同时可以分析得出,方法的调用顺序是:“父类静态代码块 > 子类静态代码块 > 父类构造函数 > 子类构造函数”。
总结:
(1)静态有限执行并且父类有限执行。
(2)静态代码是在JVM加载类的时候执行的,且仅仅执行一次;构造方法是每次new都会执行。
四、应用
(1)封装工具类
每一个应用程序中都有共性的功能,可以将这些功能进行抽取,封装,结合上面的特性,在调用的时候就不用每次new实例化,直接"类名.属性值"或者“类名.方法名”就ok了。
我在北京工作时候,我们组封装的一个工具类(虽然是C#,但是原理一样)
using System;using System.Collections.Generic;using System.Text;using VRLeCom.Commons;using VRLeCom.Server;using VRLeCom.Service;namespace VRLeCom.Handle{ public class CommandHanle { /// <summary> /// 解析命令 /// </summary> /// <param name="data"></param> /// <param name="actionid"></param> /// <returns></returns> public static string PhraseCMD(byte[] data, out ushort actionid) { byte versionID = data[0]; actionid = 0; switch (versionID) { case 1: { try { byte[] b = new byte[data.Length - 1]; Array.Copy(data, 1, b, 0, b.Length); //data.CopyTo(b, 1); var model = Encoding.UTF8.GetString(b).Deserialize<Dictionary<string, object>>(); if (model.ContainsKey("actid") && model.ContainsKey("param")) { actionid = ushort.Parse(model["actid"].ToString()); var c = model["param"] == null ? "" : model["param"].ToString(); return c; //typeof(T).InvokeMember(action, System.Reflection.BindingFlags.InvokeMethod, null, null, ) } } catch (Exception ex) { Log.Write(nameof(CommandHanle), $"指令分析失败:{ex.Message}", LogType.System, LogLevel.Crash); //Console.WriteLine("指令分析失败 :" + ex.Message); } break; } default: break; } return null; } /// <summary> /// 生成命令 /// </summary> /// <param name="versionID"></param> /// <param name="obj"></param> /// <param name="actionid"></param> /// <returns></returns> public static byte[] GeneratCMD(byte versionID, object obj, ushort actionid) { byte[] data = null; switch (versionID) { case 1: { try { string content = new { actid = actionid, param = obj }.Serialize(); byte[] c = Encoding.UTF8.GetBytes(content); data = new byte[c.Length + 1]; data[0] = versionID; Array.Copy(c, 0, data, 1, c.Length); } catch (Exception ex) { Console.WriteLine("指令生成失败 : " + ex.Message); return null; } break; } default: break; } return data; } /// <summary> /// 解析Android,IOS端命令 /// </summary> /// <param name="data"></param> /// <param name="actionid"></param> /// <returns></returns> public static string PhrasePOCMD(byte[] data, out ushort actionid) { byte versionID = data[0]; actionid = 0; switch (versionID) { case 1: { try { byte[] b = new byte[data.Length - 3]; byte[] action = new byte[2]; Array.Copy(data, 1, action, 0, 2); Array.Copy(data, 3, b, 0, b.Length); actionid = BitConverter.ToUInt16(action, 0); string ccc = Encoding.UTF8.GetString(b); return ccc; } catch (Exception ex) { Log.Write(nameof(CommandHanle), $"指令分析失败:{ex.Message}", LogType.System, LogLevel.Crash); //Console.WriteLine("指令分析失败 :" + ex.Message); } break; } default: break; } return null; } /// <summary> /// 生成Android,IOS命令 /// </summary> /// <param name="versionID"></param> /// <param name="obj"></param> /// <param name="actionid"></param> /// <returns></returns> public static byte[] GeneratPOCMD(byte versionID, object obj, ushort actionid) { byte[] data = null; switch (versionID) { case 1: { try { string content = obj.Serialize(); byte[] c = Encoding.UTF8.GetBytes(content); data = new byte[c.Length + 3]; data[0] = versionID; byte[] testByte = BitConverter.GetBytes(actionid); data[1] = testByte[0]; data[2] = testByte[1]; //data[1] = (byte)((0xff00 & actionid) >> 8); //data[2] = (byte)(0xff & actionid); Array.Copy(c, 0, data, 3, c.Length); } catch (Exception ex) { Console.WriteLine("指令生成失败 : " + ex.Message); return null; } break; } default: break; } return data; } /// <summary> /// 发送命令,有返回值 /// 此方法应尽量避免使用,因为是阻塞调用,是造成卡死状态可能原因之一 /// </summary> /// <param name="actionid"></param> /// <param name="obj"></param> /// <param name="proxy"></param> /// <returns></returns> public static byte[] ReqCMD_N(ushort actionid, object obj, ServerClient proxy) { byte[] response = null; byte[] cmd = null; try { cmd = GeneratCMD(Cmds.CMDVersionId, obj, actionid); response = ServerHelper.TryAction(() => { return proxy.SendOrder_N(cmd); }); } catch (Exception ex) { if (actionid != Cmds.BeatBrother) Log.Write("发送命令", $"发送命令:{actionid}异常:{ex.Message}", LogType.System, LogLevel.Error); } return response; } /// <summary> /// 发送命令,无返回值,非阻塞调用 /// 信息一旦到达目标端,则返回true,不保证目标端的命令可以成功执行,如果需要返回结果,则目标端后续要回调自己 /// </summary> /// <param name="actionid"></param> /// <param name="obj"></param> /// <param name="proxy"></param> /// <returns></returns> public static bool ReqCMD(ushort actionid, object obj, ServerClient proxy) { byte[] cmd = null; try { cmd = GeneratCMD(Cmds.CMDVersionId, obj, actionid); return ServerHelper.TryAction(() => { proxy.SendOrder(cmd); }); } catch (Exception ex) { if (actionid != Cmds.BeatBrother) Log.Write("发送命令", $"发送命令:{actionid}异常:{ex.Message}", LogType.System, LogLevel.Error); return false; } } /// <summary> /// 同步调用S端接口,有返回值 /// </summary> /// <param name="actionId"></param> /// <param name="obj"></param> /// <returns></returns> public static byte[] ReqCMD_N_S(ushort actionId, object obj) { if (Cmds.TransType == TransferType.WCFTCP) return ReqCMD_N(actionId, obj, ServerHelper.ControlerProxy); else return TCPReqCMD_N(actionId, obj, ServerHelper.TCPControlerProxy); } /// <summary> /// 异步调用S端接口 /// </summary> /// <param name="actionId"></param> /// <param name="obj"></param> /// <returns></returns> public static bool ReqCMD_S(ushort actionId, object obj) { if (Cmds.TransType == TransferType.WCFTCP) return ReqCMD(actionId, obj, ServerHelper.ControlerProxy); else return TCPReqCMD(actionId, obj, ServerHelper.TCPControlerProxy); } /// <summary> /// 同步调用兄弟程序接口 /// </summary> /// <param name="actionId"></param> /// <param name="obj"></param> /// <returns></returns> public static byte[] ReqCMD_N_Brother(ushort actionId, object obj) { if (Cmds.TransType == TransferType.WCFTCP) return ReqCMD_N(actionId, obj, ServerHelper.BrotherProxy); else return TCPReqCMD_N(actionId, obj, ServerHelper.TCPBrotherProxy); } /// <summary> /// /// </summary> /// <param name="actionId"></param> /// <param name="obj"></param> public static void ReqCMD_Brother(ushort actionId, object obj) { if (Cmds.TransType == TransferType.WCFTCP) ReqCMD(actionId, obj, ServerHelper.BrotherProxy); else TCPReqCMD_N(actionId, obj, ServerHelper.TCPBrotherProxy); } #region TCPClient public static byte[] TCPReqCMD_N(ushort actionid, object obj, TCPProxy proxy) { byte[] response = null; byte[] cmd = null; try { cmd = GeneratCMD(Cmds.CMDVersionId, obj, actionid); response = ServerHelper.TryAction(() => { return proxy.SentOrder(cmd, false); }); } catch (Exception ex) { if (actionid != Cmds.BeatBrother) Log.Write("发送命令", $"发送命令:{actionid}异常:{ex.Message}", LogType.System, LogLevel.Error); } return response; } public static bool TCPReqCMD(ushort actionid, object obj, TCPProxy proxy) { byte[] cmd = null; try { cmd = GeneratCMD(Cmds.CMDVersionId, obj, actionid); return ServerHelper.TryAction(() => { proxy.SentOrder(cmd, true); }); } catch { return false; } } #endregion }}如上所示,就是静态类最常用的一点了,对于我暂且理解到这个层次也就ok了。
最后有一点,如果为了保证工具类不被别人初始化,强制工具类不能建立对象,可以将其构造函数私有化,就Ok了,这就严谨多了。
That's all. (吃饭去了,饿死了)
- 【Java基础】静态类
- java基础--静态
- Java基础 静态导入
- 4 Java基础 静态
- java 基础静态工厂
- Java基础静态方法
- java 基础 - 静态 static
- java基础-静态方法
- java基础篇(五)——静态变量、静态方法、静态类
- Java基础静态变量、静态方法
- java基础-静态和非静态
- java基础入门-----静态导入
- Java 基础 静态工厂方法
- java基础入门-静态导入
- Java基础之静态static
- Java基础-静态属性,继承
- Java基础复习:Math类与静态导入
- 黑马程序员 java基础常识 类的中的静态
- ubuntu12.04升级gcc至4.8
- 茶叶好
- SpringMVC的各种参数绑定方式
- 控制密码输入框可见不可见
- Nginx编译安装
- 【Java基础】静态类
- nginx error.log
- WEB项目如何部署到服务器上线
- C语言程序设计(基础3)
- Vacations
- PHP的工作原理以及lamp四者之间的关系
- [bigdata-112] mongo3.x数据从一个公网导出然后再导入阿里mongo
- VS Code插件之Vue 2 Snippets(Vue2 片段补全工具)
- JavaWeb分页显示内容之分页查询的三种思路(数据库分页查询)