Java 带注释的反射 Class 不工作
Java Reflection with Annotation Class not working
我对 Java 非常有经验,但是使用反射和注释 classes 是个新手,我正在努力学习以获取乐趣。为了进行一些练习,我制作了一个 Identifiable
class,旨在为它继承的任何 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);
}
}
下面是我尝试设计它的方式:
class Foo extends Identifiable<Foo, Integer> {
private final int i;
Foo(int i) {
super(Foo.class);
this.i = i;
}
@Identifier
int getI() {
return i;
}
}
但是,由于某些原因,id
总是 0
,所以我不确定这是我的 Identifier
注释 class 还是我的方式有问题'使用反射。我很确定它是后者,因为在调试时,我发现它能够访问带有注释的方法。任何帮助将不胜感激,谢谢!
构造时不要调用注解方法
如果标识符值是不可变的(final
),只需将值传递给超级构造函数。
public Identifiable(K id) {
this.id = id;
}
Foo(int i) {
super(i);
this.i = i;
}
如果标识符值是可变的,则需要更改逻辑以在需要该值时调用该方法,而不是在构造过程中缓存该值。
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());
}
}
或者,使用功能接口并为其提供方法参考。
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;
}
}
我对 Java 非常有经验,但是使用反射和注释 classes 是个新手,我正在努力学习以获取乐趣。为了进行一些练习,我制作了一个 Identifiable
class,旨在为它继承的任何 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);
}
}
下面是我尝试设计它的方式:
class Foo extends Identifiable<Foo, Integer> {
private final int i;
Foo(int i) {
super(Foo.class);
this.i = i;
}
@Identifier
int getI() {
return i;
}
}
但是,由于某些原因,id
总是 0
,所以我不确定这是我的 Identifier
注释 class 还是我的方式有问题'使用反射。我很确定它是后者,因为在调试时,我发现它能够访问带有注释的方法。任何帮助将不胜感激,谢谢!
构造时不要调用注解方法
如果标识符值是不可变的(final
),只需将值传递给超级构造函数。
public Identifiable(K id) {
this.id = id;
}
Foo(int i) {
super(i);
this.i = i;
}
如果标识符值是可变的,则需要更改逻辑以在需要该值时调用该方法,而不是在构造过程中缓存该值。
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());
}
}
或者,使用功能接口并为其提供方法参考。
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;
}
}