在java中需要默认构造函数?

除了使用如下的reflection检查之外 ,有没有办法要求类具有默认(无参数)构造函数? (以下可行,但它很笨拙,反思很慢)

boolean valid = false; for(Constructor c : TParse.class.getConstructors()) { if(c.getParameterTypes().length == 0) { valid = true; break; } } if(!valid) throw new MissingDefaultConstructorException(...); 

您可以为此构建一个Annotation处理器。 注释处理器是在编译时运行的编译器插件。 它们的错误显示为编译器错误,甚至可能会停止构建。

这是一个示例代码(虽然我没有运行它):

 @SupportedAnnotationTypes("*") // needed to run on all classes being compiled @SupportedSourceVersion(SourceVersion.RELEASE_6) public class DefaultConstructor extends AbstractProcessor { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { for (TypeElement type : ElementFilter.typesIn(roundEnv.getRootElements())) { if (requiresDefaultConstructor(type)) checkForDefaultConstructor(type); } return false; } private void checkForDefaultConstructor(TypeElement type) { for (ExecutableElement cons : ElementFilter.constructorsIn(type.getEnclosedElements())) { if (cons.getParameters().isEmpty()) return; } // Couldn't find any default constructor here processingEnv.getMessager().printMessage( Diagnostic.Kind.ERROR, "type is missing a default constructor", type); } private boolean requiresDefaultConstructor(TypeElement type) { // sample: require any JPA Entity to have a default constructor return type.getAnnotation(Entity.class)) != null || type.getQualifiedName().toString().contains("POJO"); } } 

如果引入注释(例如RequiresDefaultAnnotation),注释处理器会变得更加容易。

声明要求具有默认限定符

::我还假设OP要求一种机制来防止开发人员意外错误,尤其是其他人写的。::

必须有一种机制来声明哪些类需要默认处理器。 希望您已经有了一个标准,无论是名称中的模式,限定符中的模式,可能的注释和/或基本类型。 在上面提供的示例中,您可以在方法requiresDefaultConstructor()指定条件。 以下是如何完成的示例:

  1. 基于名称模式。 TypeElement提供对完全限定名称和包名称的访问。

     return type.getQualifiedName().toString().contains("POJO"); 
  2. 基于类型声明中的注释。 例如,所有Java Bean实体类都应具有非默认构造函数

     return type.getAnnotation(Entity.class) != null; 
  3. 基于抽象类或接口。

     TypeElement basetype = processingEnv.getElements().getTypeElement("com.notnoop.mybase"); return processingEnv.getTypes().isSubtype(type.asType(), basetype.asType()); 
  4. [推荐方法]:如果您使用的是basetype接口,我建议将注释方法与基本类型接口混合使用。 您可以声明注释,例如MyPlain ,以及元注释: @Inherited 。 然后,您可以使用该批注对基本类型进行批注,然后所有子类也将inheritance批注。 那你的方法就是这样

     return type.getAnnotation(MyPlain.class) != null; 

    这是更好的,因为它更具可配置性,如果模式确实基于类型层次结构,并且您拥有根类。

如前所述,仅仅因为它被称为“注释处理”,它确实意味着你必须使用注释! 列表中您要遵循的方法取决于您的上下文。 基本上,重点是无论您希望在部署实施工具中配置什么逻辑,该逻辑都在requiresDefaultConstructor

处理器将运行的类

任何给定类的注释处理器调用取决于SupportedAnnotationTypes 。 如果SupportedAnnotationTypes元注释指定了具体注释,则处理器将仅在包含此类注释的那些类上运行。

如果SupportedAnnotationTypes"*" ,那么将在所有类上调用处理器,注释或不注释! 查看[Javadoc]( http://java.sun.com/javase/6/docs/api/javax/annotation/processing/Processor.html#getSupportedAnnotationTypes()) ,其中指出:

最后, "*"本身表示所有注释类型的集合,包括空集。 请注意,处理器不应声明"*"除非它实际处理所有文件; 声称不必要的注释可能会导致某些环境中的性能下降。

请注意返回false ,以确保处理器不会声明所有注释。

不可以。上面的检查可以更容易地重写为:

 try { MyClass.newInstance(); } catch (InstantiationException E) { // no constructor } catch (IllegalAccessException E) { // constructor exists but is not accessible ? 

您可以使用PMD和Macker来保证架构规则。 在partilar中,Macker会引发编译错误,在validation失败时破坏构建过程。

Macker扩展了PMD流行的一些关于源代码validation的概念。 一个很好的例子是当你想保证包中的所有类都实现某个接口时。

所以,如果你非常偏执(像我一样!)关于validation所有可能的架构规则,Macker真的很有用。

http://innig.net/macker/

注意:网站不是很好。 颜色会伤害你的眼睛……但是这些工具无论如何都非常有用。

理查德·戈麦斯http://www.jquantlib.org/