我有一个方法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
。它与f
的class
绑定,但对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
,它将引用哪个name
?f1
还是f2
?你不可能知道。
这就是为什么Class<T>
会做一些不同的事情。它使您能够获得字段的通用表示(例如,Foo
的name
(,但不会产生具体值(引用(,除非指定该字段必须反射的对象(这称为反射(。看看:
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
?好吧,我们必须指定使用那个具体对象。我们需要f1
或f2
,否则我们无法知道应该访问哪些(可能有很多(name
。
通过执行nameField.get(f2)
,我们说我们希望从对象f2
访问nameField
的相关字段(来自Foo
的name
字段(。但请注意,该字段可能是不可访问的(例如,它可能是private
(,这就是为什么我们必须使用catch
这样的错误IllegalAccessException
。
老实说,你甚至可以通过做更多的魔术来访问private
字段,但这有点超出了问题的范围。总之,您需要一个T
类型的实际对象来访问其字段。Class<T>
将使您能够做一点元魔术,但要有具体的东西,您需要具体的对象。
当然,如果您没有一个具体的对象,而只有一个Class<T>
,那么您可以使用fClass.getDeclaredConstructor().newInstance()
从中创建T
。
编辑:当然,您的API可能会用Class<T>
做一些自己的魔术。我不熟悉您使用的API(PredicateSpec
和Route.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);