为什么我在Java中收到有关实用程序类的警告

giz*_*gok 37 java

我正在学习Java和OOPS,在eclipse中编写一个基本的Hello World时,我看到一个黄色三角形告诉我"实用程序类不应该有公共或默认构造函数".我无法理解为什么会发生这种情况,这是什么意思?我做得怎么样?

class HelloWorld {


public static void main(String[] args)
{
    // TODO Auto-generated method stub
            System.out.println("Hola Mundo!");

}


  }
Run Code Online (Sandbox Code Playgroud)

EDIT1:编辑代码以包含建议的更改.

final class HelloWorld {


private HelloWorld()
{
    throw new AssertionError("Instantiating utility class...");

}
public static void main(String[] args)
{
    // TODO Auto-generated method stub
            System.out.println("Hola Mundo!");

}


}
Run Code Online (Sandbox Code Playgroud)

仍在线上HelloWorld的警报.

EDIT2:

创建了一个新类,现在它可以工作了.谢谢Jon.为什么旧班仍然会发出警告?波希米亚人我还没有意识到你在帖子中提到的概念.一旦我有了更好的主意,我会回到他们身边.谢谢你解释一下.

Jon*_*eet 58

这意味着有人可以写:

HelloWorld helloWorld = new HelloWorld();
Run Code Online (Sandbox Code Playgroud)

如果您可能不希望它们 - 您没有提供任何实例成员,那么为什么要允许它们创建实例?将您的代码重写为:

final class HelloWorld {

    private HelloWorld() {
        // Prevent instantiation
        // Optional: throw an exception e.g. AssertionError
        // if this ever *is* called
    }

    public static void main(String[] args) {
        System.out.println("Hola Mundo!");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @ john16384:我强烈不同意.您应该尽可能简化API,以便尽可能使用不正确.如果操作没有意义,请禁止操作.当然,如果有这样的语言支持会更好,比如C#中的静态类. (5认同)
  • @Jon - 好的,你让我得到了JLS规范:) (2认同)
  • 我讨厌这个Checkstyle警告,它没有增加任何价值.如果对此实用程序类进行了即时操作,则实例化程序处于错误状态 - 标记为,不标记完全合理的Utility类并强制我添加丑陋的虚拟构造函数 (2认同)

Boh*_*ian 17

Jon说了什么,但是你也应该知道每个类都有一个构造函数,无论你是否声明了一个.如果您没有声明一个,则默认为您定义"默认构造函数".

换句话说,这两个类的行为是相同的:

public class ClassA {
}


public class ClassB {
    public ClassB() {
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意:拥有私有构造函数不会阻止实例化!

只是为了肛门,拥有一个私有构造函数并不会阻止某人实例化你的类,它只会让它变得更难:

有(至少)两种方法来解决它:

声明一个工厂方法(很明显,但如果它是你公司的代码,有人可以这样做):

public class ClassA {
    private ClassA() {}

    public static ClassA create() {
        return new ClassA(); // oops! this one got away
    }
}
Run Code Online (Sandbox Code Playgroud)


使用反射(鬼鬼祟祟,似乎有点错误,但它有效!):

public class ClassA {
    private ClassA() {}
}

// Elsewhere, in another class across town:
Constructor<?> constructor = ClassA.class.getDeclaredConstructor();
// constructor private? no problem... just make it not private!
constructor.setAccessible(true); // muhahahaha
Object obj = constructor.newInstance();
System.out.println(obj.getClass().getSimpleName());  // Prints ClassA!
Run Code Online (Sandbox Code Playgroud)

保证没有人创建实例的唯一方法是在(也可能使其成为私有)构造函数中抛出异常.


Uff*_*ffe 8

为了完整起见,到目前为止,没有一个响应者对您的原始课程的另一个问题发表评论

class HelloWorld {
Run Code Online (Sandbox Code Playgroud)

如你所说,你变成了

final class HelloWorld {
Run Code Online (Sandbox Code Playgroud)

finalJava类上的关键字禁止其他类扩展(继承)它.如果不使类成为final,则扩展类可以使用您可能没有预期的各种事物,因为扩展类可以访问protected继承类的成员.

优良作法是始终使您的类成为abstract或者final,意味着它们用于继承或用于继承.很多时候你会设计一个既可以实例化(不抽象)又可扩展(不是最终)的类,但是这个有意识的决定是一个很好的习惯.


Pet*_*rey 5

编写实用程序类的最简单方法是使用没有实例的枚举.您可以使用Java 5.0及更高版本.

public enum Utility {;
    public static void main(String... args) {
        System.out.println("Hola Mundo!");
    }
}
Run Code Online (Sandbox Code Playgroud)

您不必定义私有构造函数,也不能使用内部类或其他技巧(如反射)创建实例.(如果忽略Unsafe类;)

顺便说一句:有些人认为使用enumhack作为黑客,但对我来说它明确地说"我有一个没有实例的类",而不是阻止创建间接的实例.

  • 请注意隐藏在此枚举的开口大括号后面的分号?这需要表明空枚举.我认为这有点棘手. (2认同)