简体   繁体   English

Java 带注释的反射 Class 不起作用

[英]Java Reflection with Annotation Class not working

I'm pretty experienced with Java, however a novice to using Reflection and Annotation classes, which I'm trying to learn for fun.我对 Java 非常有经验,但是我是使用反射和注释类的新手,我想学习这些是为了好玩。 To get some practice, I made an Identifiable class which is designed to add several helpful methods to any class it inherits.为了进行一些练习,我制作了一个可Identifiable的 class,它旨在为它继承的任何 class 添加一些有用的方法。

Here is the full class:这是完整的 class:

abstract class Identifiable<T, K extends Comparable<K>> implements Comparable<Identifiable<T, K>> {

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Identifier { }

    private static Method getMethodAnnotatedWith(final Class<?> type) {
        return Arrays.stream(type.getDeclaredMethods())
                .filter(m -> m.isAnnotationPresent(Identifier.class))
                .findFirst()
                .orElse(null);
    }

    private K id;

    @SuppressWarnings("unchecked")
    public Identifiable(Class<T> clazz) {
        var m = getMethodAnnotatedWith(clazz);
        if (m == null) throw new IllegalArgumentException(
            clazz.toString() + " does not have a method annotated by @Identifier"
        );

        try {
            id = (K) m.invoke(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public int compareTo(@NotNull Identifiable<T, K> i) {
        return id.compareTo(i.id);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Identifiable<?, ?> that = (Identifiable<?, ?>) o;
        return id == that.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

And here is how I am trying to design it to work:这就是我试图设计它的方式:

class Foo extends Identifiable<Foo, Integer> {
    private final int i;

    Foo(int i) {
        super(Foo.class);
        this.i = i;
    }

    @Identifier
    int getI() {
        return i;
    }
}

However, id is always 0 for some reason, so I'm not sure if it's a problem with my Identifier annotation class or the way I'm using reflection.但是,由于某种原因, id始终为0 ,所以我不确定这是否是我的Identifier注释 class 或我使用反射的方式有问题。 I'm pretty sure it's the latter since while debugging, I found that it is able to access the method with the annotation.我很确定是后者,因为在调试时,我发现它能够访问带有注释的方法。 Any help would be appreciated, thanks!任何帮助将不胜感激,谢谢!

Don't call the annotated method during construction.构造过程中不要调用注解的方法。

If the identifier value is immutable ( final ), just pass the value to the super constructor.如果标识符值是不可变的( final ),只需将值传递给超级构造函数。

public Identifiable(K id) {
    this.id = id;
}
Foo(int i) {
    super(i);
    this.i = i;
}

If the identifier value is mutable, you need to change the logic to invoke the method when you need the value, not cache the value during construction.如果标识符值是可变的,则需要更改逻辑以在需要该值时调用该方法,而不是在构造过程中缓存该值。

abstract class Identifiable<T, K extends Comparable<K>> implements Comparable<Identifiable<T, K>> {

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Identifier {/**/}

    private Method idGetter;

    protected Identifiable(Class<T> type) {
        this.idGetter = Arrays.stream(type.getDeclaredMethods())
                .filter(m -> m.isAnnotationPresent(Identifier.class))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException(type.getName() + " does not have a method annotated by @Identifier"));
    }

    @SuppressWarnings("unchecked")
    private final K getIdentifiableKey() {
        try {
            return (K) this.idGetter.invoke(this);
        } catch (IllegalAccessException e) {
            throw new IllegalAccessError(e.getMessage());
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public int compareTo(Identifiable<T, K> that) {
        return this.getIdentifiableKey().compareTo(that.getIdentifiableKey());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        
        Identifiable<?, ?> that = (Identifiable<?, ?>) o;
        return this.getIdentifiableKey().equals(that.getIdentifiableKey()); // Call equals(), don't use ==
    }

    @Override
    public int hashCode() {
        return Objects.hash(this.getIdentifiableKey());
    }
}

Alternatively, use a functional interface and supply it with a method reference.或者,使用功能接口并为其提供方法引用。

abstract class Identifiable<T extends Identifiable<T, K>, K extends Comparable<K>> implements Comparable<Identifiable<T, K>> {

    private Function<T, K> idGetter;

    protected Identifiable(Function<T, K> idGetter) {
        this.idGetter = Objects.requireNonNull(idGetter);
    }

    @Override
    @SuppressWarnings("unchecked")
    public int compareTo(Identifiable<T, K> that) {
        return this.idGetter.apply((T) this).compareTo(that.idGetter.apply((T) that));
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        
        Identifiable<T, K> that = (Identifiable<T, K>) o;
        return this.idGetter.apply((T) this).equals(that.idGetter.apply((T) that));
    }

    @Override
    @SuppressWarnings("unchecked")
    public int hashCode() {
        return Objects.hash(this.idGetter.apply((T) this));
    }
}
class Foo extends Identifiable<Foo, Integer> {
    private final int i;

    Foo(int i) {
        super(Foo::getI);
        this.i = i;
    }

    int getI() {
        return i;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM