gpt4 book ai didi

java - 可以定义 Java 接口(interface),使得只有 Enums 可以扩展它吗?

转载 作者:行者123 更新时间:2023-12-04 10:55:17 25 4
gpt4 key购买 nike

我想这样做没有特别的原因 - 我只是想知道这是否可能。如果有帮助,这是一个可以使用的虚构情况:

想象一下 Enum 的类型它用作只读数据源,因此 Enum 的每个值包含不同的内容。 Enum实现 Readable .现在,假设我们想要一个读取 Enum 的所有值的方法。到单个缓冲区。这可以作为辅助类中的静态实用程序方法来实现(见下文)。

public class ReadableEnumUtils {
/** reads data from all enum values into the charbuffer */
public static <T extends Enum<T> & Readable> int readAll(Class<T> clazz, CharBuffer cb) throws IOException {
int total = 0;
for (T e : clazz.getEnumConstants()) {
int intermediate = e.read(cb);
if (intermediate < 0) {
throw new IllegalArgumentException("The enum value \'" + e.name() + "\' had no data to read.");
}
total += intermediate;
}
return total;
}
}

最好在接口(interface)中声明该方法,但这可能会造成混淆,因为非 Enum 类不应该实现这样的方法并不是很明显。理想情况下,接口(interface)可以定义为编译器确保它仅由 Enum 的子类实现。 .这是该界面可能看起来的示例:
interface ReadableEnum extends Readable {
int read(CharBuffer cb) throws IOException;

int readAll(CharBuffer cb) throws IOException;
}

我认为不可能让编译器确保 ReadableEnum仅由 Enum 的子类实现- 那是对的吗?

最佳答案

Java 默认不支持这样的东西,你问为什么不提供规范的链接,但没有什么特别的原因,只是没有人决定添加这样的特性,你可以自己提出来——但是你可能会知道他们不要认为这是需要的东西,也不会将其添加到语言中。

但是 java 提供了非常强大的选项来自己实现这一点:注释处理。
我创建了带有注释的简单 java 8 maven 项目:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface EnumInterface {}

并配备特殊处理器
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import java.util.*;

@SupportedAnnotationTypes("com.gotofinal.enuminterface.EnumInterface")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class EnumInterfaceProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Messager messager = processingEnv.getMessager();
Types typeUtils = processingEnv.getTypeUtils();

// first we scan for all interfaces marked with this annotation
List<TypeElement> enumOnlyInterfaces = new ArrayList<>();
for (Element rootElement : roundEnv.getRootElements()) { // getRootElements should return all types being compiled
if (! (rootElement instanceof TypeElement)) {
continue;
}
TypeMirror typeMirror = rootElement.asType();
// we check if this class have our annotation, we could also here check if this is an interface (by checking if it does not extend Object directly) and throw error otherwise
if (rootElement.getAnnotation(EnumInterface.class) != null) {
enumOnlyInterfaces.add((TypeElement) rootElement);
}
}

// and now we scan for any non enum types that implement this interface
for (Element rootElement : roundEnv.getRootElements()) {
if (! (rootElement instanceof TypeElement)) {
continue;
}
TypeElement type = findImplementedInterface(rootElement.asType(), enumOnlyInterfaces, typeUtils);
if (type == null) {
continue;
}
if (! (rootElement.asType() instanceof DeclaredType)) {
continue;
}

// it's fine if it is an enum
if (this.isEnum(rootElement.asType(), typeUtils)) {
continue;
}

// and we print error to compiler
messager.printMessage(Diagnostic.Kind.ERROR, "Interface " + type.getQualifiedName()
+ " can't be used on non enum class: " + ((TypeElement) rootElement).getQualifiedName());
}
return false;
}

public TypeElement findImplementedInterface(TypeMirror type, List<TypeElement> interfaces, Types types) {
for (TypeElement anInterface : interfaces) {
// types.isSubtype(typeA, typeA) would return true, so we need to add this equals check
if (!anInterface.asType().equals(type) && types.isSubtype(type, anInterface.asType())) {
return anInterface;
}
}
return null;
}

// maybe there is better way to do this... but I just scan recursively for a subtype with java.lang.Enum name, so it's not perfect but should be enough.
public boolean isEnum(TypeMirror type, Types types) {
for (TypeMirror directSupertype : types.directSupertypes(type)) {
TypeElement element = (TypeElement) ((DeclaredType) directSupertype).asElement();
if (element.getQualifiedName().contentEquals("java.lang.Enum")) {
return true;
}
if (isEnum(directSupertype, types)) {
return true;
}
}
return false;
}
}

并在 META-INF/services/javax.annotation.processing.Processor 中注册文件:
com.gotofinal.enuminterface.EnumInterfaceProcessor

这段代码可能会改进很多,我以前从未写过任何注释处理器。但是当我们将创建另一个 maven 项目并将其声明为依赖项并编写如下代码时:
@EnumInterface
interface TestInterface {}

enum TestEnum implements TestInterface {}

class TestClass implements TestInterface {}

我们将无法编译它并出现错误:

Interface com.gotofinal.enuminterface.TestInterface can't be used on non enum class: com.gotofinal.enuminterface.TestClass

关于java - 可以定义 Java 接口(interface),使得只有 Enums 可以扩展它吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58441864/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com