如何在 Java 中从类实例读取属性<T>?



我有一个方法methodA(),它将类Class<T> inClass的实例作为参数。

methodA()中传递的任何给定inClass实例都将具有名为user:String的属性。

所以我想读取methodA()中的属性。但我得到了Cannot resolve method 'getUser' in 'T'

有可能以某种方式从泛型类中读取属性吗?

或者,我可以在methodA()中将我想要的类的名称作为字符串传递,并将其转换为";ClassName";。不知怎么的上课了?

private <T> Function<PredicateSpec, Route.AsyncBuilder> walletRoute(String server, String path, String method, Class<T> inClass) {
return r -> r.path(path)
.and().method(method)
.and().readBody(inClass, requestBody ->
walletDiscoveryService(requestBody.getUser()).equals(server))
.uri("http://" + server);
}

我称这种方法如下:

walletRoute("localhost:3000", "/api/account/**", "POST", BankAccount.class)

如何在Java中从class实例读取属性?

本身?对象属性?您不能。


想想一个物体。一个简单的Java对象。它容纳了所有的成员,也许还有一些额外的、继承的东西。假设我们有一个简单的类:

class Foo {
String name;
}

在创建了一个Foo类型的对象之后,我们可以访问它的内部,如下所示:

Foo f = new Foo();
f.name = "Groot";
System.out.println(f.name);

漂亮而简单。


现在让我们介绍一些Class<T>魔术:

Foo f = new Foo();
f.name = "Groot";
System.out.println(f.name);
Class<Foo> fClass = Foo.class;

太好了,我们有一个Class实例。我们能用它做什么?

在我们回答这个问题之前,请注意,fClass的创建是不可知的(不知道,不需要知道(实例f

这是什么意思?这意味着它决不会绑定到f。它与fclass绑定,但对f本身一无所知。您无法从fClass检索name,因为随后将检索哪个name

要完全理解这个问题,请考虑以下代码:

Foo f1 = new Foo();
f1.name = "Groot";
Foo f2 = new Foo();
f2.name = "Rocket";
Class<Foo> fClass = Foo.class;
//fClass.name ???

如果fClass可以引用来自某个类型为Foo的对象的name,它将引用哪个namef1还是f2?你不可能知道。


这就是为什么Class<T>会做一些不同的事情。它使您能够获得字段的通用表示(例如,Fooname(,但不会产生具体值(引用(,除非指定该字段必须反射的对象(这称为反射(。看看:

Foo f1 = new Foo();
f1.name = "Groot";
Foo f2 = new Foo();
f2.name = "Rocket";
Class<Foo> fClass = Foo.class;
try {
Field nameField = fClass.getDeclaredField("name");
System.out.println(nameField.get(f2));
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}

这是一个完整的片段。需要一些时间来消化。

当您尝试访问name字段时,魔术就会发生。请注意Field类型。在本例中,它是一个表示访问名为"name"的字段的对象。但请注意,我们可能拼错了字段的名称,这就是为什么我们必须像NoSuchFieldException一样出现catch错误。

然后我们想访问该字段,但我们想访问哪个对象的name?好吧,我们必须指定使用那个具体对象。我们需要f1f2,否则我们无法知道应该访问哪些(可能有很多(name

通过执行nameField.get(f2),我们说我们希望从对象f2访问nameField的相关字段(来自Fooname字段(。但请注意,该字段可能是不可访问的(例如,它可能是private(,这就是为什么我们必须使用catch这样的错误IllegalAccessException


老实说,你甚至可以通过做更多的魔术来访问private字段,但这有点超出了问题的范围。总之,您需要一个T类型的实际对象来访问其字段。Class<T>将使您能够做一点元魔术,但要有具体的东西,您需要具体的对象。

当然,如果您没有一个具体的对象,而只有一个Class<T>,那么您可以使用fClass.getDeclaredConstructor().newInstance()从中创建T

编辑:当然,您的API可能会用Class<T>做一些自己的魔术。我不熟悉您使用的API(PredicateSpecRoute.AsyncBuilder(,所以我不能代表他们说话。

您不能只使用Class<T>参数来实现这一点,除非您愿意使用混乱和脆弱的反射。

但是,您可以添加一个表示用户属性的get方法的参数:

private <T> Function<PredicateSpec, Route.AsyncBuilder> walletRoute(
String server,
String path,
String method,
Class<T> inClass,
Function<T, String> getUserMethod) {
return r -> r.path(path)
.and().method(method)
.and().readBody(inClass, requestBody ->
walletDiscoveryService(
getUserMethod.apply(requestBody)).equals(server))
.uri("http://" + server);
}

调用该方法看起来像这样:

walletRoute("localhost:3000", "/api/account/**", "POST",
BankAccount.class, BankAccount::getUser);

相关内容

最新更新