Java单例+内部class误会
Java Singleton + inner class missunderstand
过去两个月我一直在编程 Java,但我在 python 和 C 方面是经验丰富的程序员。我知道我因此而犯错误。
我在 Android studio 中解决警告清理问题。
我使用带有内部 classes 的单例 class 将我所有的配置参数保存在一个地方,让所有其他 classes 访问它而无需传递配置。
这是我的单例的基本代码
public class syscfg {
public List<CommData> Commlist;
public static CommConfigIP4 MyCommConfig;// = new CommConfig();
private static syscfg instance = null;
private static boolean ConfigStat = false;
/** JAVA singleton control methods**/
protected syscfg(){
// pues eso
if(ConfigStat == false){
Log.i("SD_app_log", "SYSCFG: Module Initialization");
ConfigStat = true;
MyCommConfig = new CommConfigIP4();
init_config();
}else{
Log.i("SD_app_log", "SYSCFG: Module Loaded");
}
}
public static syscfg getInstance(){
if(instance == null){
instance = new syscfg();
}
return instance;
}
public class CommConfigIP4{
public int discoveryPort = 30303;
public byte[] MyMAC;
public String MyType = "";
public String MyIP;
public byte[] getIPbytearray(){
// byte[] IPout= new byte[4];
try{
byte[] IPout = (InetAddress.getByName(MyIP)).getAddress();
return IPout;
}catch (Exception e){
return null;
}
}
在我的通讯中 java file/class 我有:
public class Communications {
private syscfg CFid ;
...
public Communications(Context ctx){
...
CFid = syscfg.getInstance();
init_comms(); //init_comms calls whoami
}
private void whoami (){
...
CFid.MyCommConfig.MyType = netint.getName();
...
}
}
因此,当我第一次将 syscfg 中的所有元素(变量、classes 和方法)作为静态时 android studio 显示一条警告,指出通过实例引用访问静态成员。经过一些研究和文档,我发现建议不要使用静态变量和方法,我试图将它们全部消除。但是后来我在
中得到了一个 nullpointexception 错误
CFid.MyCommConfig.MyType = netint.getName();
使用调试器我发现 CFid.MyCommConfig = null
我使用单例来避免在 syscfg class 上使用静态并通过实例化访问而不使用 class 名称。
现在我的单例代码就像这里发布的静态 CommConfigIP4 代码一样,我再次收到建议我使用的警告:
syscfg.MyCommConfig.MyType = netint.getName();
而不是使用实例访问配置。
这里发生了什么?我缺少什么?
谢谢,
吉列尔莫
在你的 whoami() 方法中你引用了这个:
CFid.MyCommConfig.MyType = netint.getName();
... 但是,"MyCommConfig" 是 class "syscfg" 的静态 属性,而变量 "CFid" 指的是此实例class。换句话说,"syscfg" 的所有实例(以及 class 定义本身)都引用 "MyCommConfig" 变量的相同副本(这就是静态的意思)。
因此,通过说 "syscfg.MyCommConfig" 来引用 "MyCommConfig" 变量会更容易混淆,因为这清楚地表明您指的是静态变量而不是实例变量。
顺便说一句,您应该考虑遵循标准的 Java 代码约定来大写 class 名称和变量,因为这将使您的代码对其他 Java 程序员更具可读性。
您应该将嵌套 class 声明为静态的:
public static class CommConfigIP4
然后取消注释在外部 class.
顶部初始化静态变量的代码
要避免这些警告,您应该以这种方式实现单例。我更改了一些代码以使其易于理解:
public class Syscfg {
public Config getConfig() {
return c;
}
// Obtain the same instance always
public static Syscfg getInstance() {
return s == null ? new Syscfg() : s;
}
// Important for singleton
private Syscfg() {
c = new Config();
}
private static Syscfg s;
private Config c;
class Config {
public String[] getConfigs() {
return configs;
}
private String[] configs = {"10.10.10.10", "userName", "userPass"};
}
}
因此,如果您想知道另一个 class 中使用的配置,例如测试 class,那么您可以使用
public class Test {
public static void main(String[] args) {
System.out.println(Arrays.toString(Syscfg.getInstance().getConfig().getConfigs()));
}
}
结果是:[10.10.10.10, userName, userPass]
过去两个月我一直在编程 Java,但我在 python 和 C 方面是经验丰富的程序员。我知道我因此而犯错误。
我在 Android studio 中解决警告清理问题。
我使用带有内部 classes 的单例 class 将我所有的配置参数保存在一个地方,让所有其他 classes 访问它而无需传递配置。
这是我的单例的基本代码
public class syscfg {
public List<CommData> Commlist;
public static CommConfigIP4 MyCommConfig;// = new CommConfig();
private static syscfg instance = null;
private static boolean ConfigStat = false;
/** JAVA singleton control methods**/
protected syscfg(){
// pues eso
if(ConfigStat == false){
Log.i("SD_app_log", "SYSCFG: Module Initialization");
ConfigStat = true;
MyCommConfig = new CommConfigIP4();
init_config();
}else{
Log.i("SD_app_log", "SYSCFG: Module Loaded");
}
}
public static syscfg getInstance(){
if(instance == null){
instance = new syscfg();
}
return instance;
}
public class CommConfigIP4{
public int discoveryPort = 30303;
public byte[] MyMAC;
public String MyType = "";
public String MyIP;
public byte[] getIPbytearray(){
// byte[] IPout= new byte[4];
try{
byte[] IPout = (InetAddress.getByName(MyIP)).getAddress();
return IPout;
}catch (Exception e){
return null;
}
}
在我的通讯中 java file/class 我有:
public class Communications {
private syscfg CFid ;
...
public Communications(Context ctx){
...
CFid = syscfg.getInstance();
init_comms(); //init_comms calls whoami
}
private void whoami (){
...
CFid.MyCommConfig.MyType = netint.getName();
...
}
}
因此,当我第一次将 syscfg 中的所有元素(变量、classes 和方法)作为静态时 android studio 显示一条警告,指出通过实例引用访问静态成员。经过一些研究和文档,我发现建议不要使用静态变量和方法,我试图将它们全部消除。但是后来我在
中得到了一个 nullpointexception 错误CFid.MyCommConfig.MyType = netint.getName();
使用调试器我发现 CFid.MyCommConfig = null
我使用单例来避免在 syscfg class 上使用静态并通过实例化访问而不使用 class 名称。
现在我的单例代码就像这里发布的静态 CommConfigIP4 代码一样,我再次收到建议我使用的警告:
syscfg.MyCommConfig.MyType = netint.getName();
而不是使用实例访问配置。
这里发生了什么?我缺少什么?
谢谢, 吉列尔莫
在你的 whoami() 方法中你引用了这个:
CFid.MyCommConfig.MyType = netint.getName();
... 但是,"MyCommConfig" 是 class "syscfg" 的静态 属性,而变量 "CFid" 指的是此实例class。换句话说,"syscfg" 的所有实例(以及 class 定义本身)都引用 "MyCommConfig" 变量的相同副本(这就是静态的意思)。
因此,通过说 "syscfg.MyCommConfig" 来引用 "MyCommConfig" 变量会更容易混淆,因为这清楚地表明您指的是静态变量而不是实例变量。
顺便说一句,您应该考虑遵循标准的 Java 代码约定来大写 class 名称和变量,因为这将使您的代码对其他 Java 程序员更具可读性。
您应该将嵌套 class 声明为静态的:
public static class CommConfigIP4
然后取消注释在外部 class.
顶部初始化静态变量的代码要避免这些警告,您应该以这种方式实现单例。我更改了一些代码以使其易于理解:
public class Syscfg {
public Config getConfig() {
return c;
}
// Obtain the same instance always
public static Syscfg getInstance() {
return s == null ? new Syscfg() : s;
}
// Important for singleton
private Syscfg() {
c = new Config();
}
private static Syscfg s;
private Config c;
class Config {
public String[] getConfigs() {
return configs;
}
private String[] configs = {"10.10.10.10", "userName", "userPass"};
}
}
因此,如果您想知道另一个 class 中使用的配置,例如测试 class,那么您可以使用
public class Test {
public static void main(String[] args) {
System.out.println(Arrays.toString(Syscfg.getInstance().getConfig().getConfigs()));
}
}
结果是:[10.10.10.10, userName, userPass]