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

时间:2009-11-18 22:05:16

标签: java constructor default

有没有办法要求一个类有一个默认(无参数)构造函数,一边使用反射检查,如下所示? (以下情况可行,但它很骇人,反思很慢)

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

3 个答案:

答案 0 :(得分:22)

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

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

@SupportedAnnotationTypes("*")   // needed to run on all classes being compiled
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class DefaultConstructor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> 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。然后,您可以使用该批注对基本类型进行批注,然后所有子类也将继承该批注。然后你的方法就是

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

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

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

    处理器将在

    上运行的类

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

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

      

    最后,"*"本身代表了。{   所有注释类型的集合,包括   空集。请注意处理器   除非是"*",否则不应声明false   实际上处理所有文件;   声称不必要的注释可能   导致某些人的表现放缓   的环境中。

    请注意如何返回{{1}}以确保处理器不会声明所有注释。

答案 1 :(得分:6)

没有。以上检查可以更容易地重写为:

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

答案 2 :(得分:1)

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

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

所以,如果你非常偏执(像我一样!)关于验证所有可能的架构规则,那么Macker确实很有用。

http://innig.net/macker/

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

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