如何在没有引用的情况下找到类的单例对象? 我们考虑下面的例子: import java.util.Map; 导入java.util.Optional; 课堂擦伤{ 公共静态类用户服务{ 私有最终地图用户=Map.of( “user1”,“Max”, “用户2”,“伊凡”, “用户3”、“Leo”); 公共可选findUserById(字符串用户ID){ 返回可选的.ofNullable(users.get(userId)); } } //我们将单例对象保存到此字段 //防止被垃圾收集 private volatile UserService UserService=null; 私有用户服务getUserService(){ ///我们需要实施它 ///显然,我们不能返回Scratch#userService字段 返回null; } 公共职位{ //我需要在这里获取'userService',而不是显式地传递它 //执行一些服务方法 UserService=getUserService(); if(userService!=null){ userService.findUserById(“userId”); } } 公共无效startApplication(){ userService=newuserservice(); doJobs(); } 公共静态void main(字符串[]args){ Scratch程序=新的Scratch(); program.startApplication(); } }
所以。我们有一个没有任何框架的简单java应用程序,比如spring。我需要在如何在没有引用的情况下找到类的单例对象? 我们考虑下面的例子: import java.util.Map; 导入java.util.Optional; 课堂擦伤{ 公共静态类用户服务{ 私有最终地图用户=Map.of( “user1”,“Max”, “用户2”,“伊凡”, “用户3”、“Leo”); 公共可选findUserById(字符串用户ID){ 返回可选的.ofNullable(users.get(userId)); } } //我们将单例对象保存到此字段 //防止被垃圾收集 private volatile UserService UserService=null; 私有用户服务getUserService(){ ///我们需要实施它 ///显然,我们不能返回Scratch#userService字段 返回null; } 公共职位{ //我需要在这里获取'userService',而不是显式地传递它 //执行一些服务方法 UserService=getUserService(); if(userService!=null){ userService.findUserById(“userId”); } } 公共无效startApplication(){ userService=newuserservice(); doJobs(); } 公共静态void main(字符串[]args){ Scratch程序=新的Scratch(); program.startApplication(); } },java,design-patterns,reflection,jvm,unsafe,Java,Design Patterns,Reflection,Jvm,Unsafe,所以。我们有一个没有任何框架的简单java应用程序,比如spring。我需要在doJobs()方法中查找UserService对象,而无需显式传递它。显然,这是求职面试的问题 有以下任务先决条件: UserService不是Springbean或类似的东西。它不是关于DI 无法将UserService对象显式传递给doJobs()方法 不能将UserService对象设置为某个静态/全局变量/接口/方法 您不能使用JavaAgent 您知道,在当前类加载器中只有一个UserService对象
doJobs()
方法中查找UserService
对象,而无需显式传递它。显然,这是求职面试的问题
有以下任务先决条件:
不是Springbean或类似的东西。它不是关于UserService
DI
- 无法将
对象显式传递给UserService
方法doJobs()
- 不能将
对象设置为某个静态/全局变量/接口/方法UserService
- 您不能使用JavaAgent
- 您知道,在当前类加载器中只有一个
对象UserService
- 如果愿意,您可以使用任何反射(包括库)
- 不能创建新对象,应使用现有对象
- 您不能出于任何目的使用
字段。它是为防止gc而引入的Scratch#userService
公共静态类用户服务{
public static class UserService {
private final Map<String, String> users = Map.of(
"user1", "Max",
"user2", "Ivan",
"user3", "Leo");
public Optional<String> findUserById(String userId) {
return Optional.ofNullable(users.get(userId));
}
}
// We save our singleton object to this filed
// to protect from being garbage collected
private volatile UserService userService = new UserService();
private UserService getUserService() {
/// TODO we need to implement it
/// Obviously, we cannot return Scratch#userService field
return userService;
}
public void doJobs() {
// I need to get `userService` here, without explicitly passing it
// to execute some service method
UserService userService = getUserService();
if (userService != null) {
System.out.println(userService.findUserById("user1"));
}
}
public void startApplication() {
userService = new UserService();
doJobs();
}
public static void main(String[] args) {
Scratch program = new Scratch();
program.startApplication();
}
私有最终地图用户=Map.of(
“user1”,“Max”,
“用户2”,“伊凡”,
“用户3”、“Leo”);
公共可选findUserById(字符串用户ID){
返回可选的.ofNullable(users.get(userId));
}
}
//我们将单例对象保存到此字段
//防止被垃圾收集
private volatile UserService UserService=new UserService();
私有用户服务getUserService(){
///我们需要实施它
///显然,我们不能返回Scratch#userService字段
返回用户服务;
}
公共职位{
//我需要在这里获取'userService',而不是显式地传递它
//执行一些服务方法
UserService=getUserService();
if(userService!=null){
System.out.println(userService.finduserbyd(“user1”);
}
}
公共无效startApplication(){
userService=newuserservice();
doJobs();
}
公共静态void main(字符串[]args){
Scratch程序=新的Scratch();
program.startApplication();
}
任务要求您在不直接引用字段的情况下实现此方法
private UserService getUserService() {
return ...;
}
作为实例方法,您可以通过this
关键字引用Scratch
的实例。使用反射,您可以获取对userService
字段的引用,然后使用该字段获取this
的该字段的值:
Field field = getClass().getField("userService");
UserService userService = (UserService)field.get(this);
完整的方法是:
private UserService getUserService() {
try {
return (UserService)getClass().getField("userService").get(this);
} catch (ReflectiveOperationException e ) {
throw new RuntimeException(e);
}
}
如果已知
UserService
的实例保存在静态字段中,您可以尝试
如果字段不是静态的,那么您必须创建一个声明类的实例(并将其馈送,而不是null
)
也许你遗漏了一些你没有意识到其重要性的问题细节。例如,以下示例适用于HotSpot/OpenJDK和派生的JRE:
import java.lang.ref.Reference;
导入java.lang.reflect.*;
导入java.util.*;
课堂擦伤{
公共静态类用户服务{
私有最终地图用户=Map.of(
“user1”、“Max”、“user2”、“Ivan”、“user3”、“Leo”);
公共可选findUserById(字符串用户ID){
返回可选的.ofNullable(users.get(userId));
}
@凌驾
受保护的void finalize()抛出可丢弃的{
System.out.println(“一切都出了问题”);
}
}
private volatile UserService UserService;//从不读取
私有用户服务getUserService(){
试一试{
Class c=Class.forName(“java.lang.ref.Finalizer”);
字段[]f={c.getDeclaredField(“未完成”),c.getDeclaredField(“下一个”)};
AccessibleObject.setAccessible(f,true);
引用r=(引用)f[0]。获取(null);
while(r!=null){
对象o=r.get();
if(o instanceof UserService)返回(UserService)o;
r=(引用)f[1].get(r);
}
}catch(ReflectiveOperationException ex){}
抛出新的IllegalStateException(“无论如何都不能保证有效”);
}
公共职位{
UserService=getUserService();
System.out.println(用户服务);
userService.findUserById(“userId”);
}
公开无效申请(
private UserService getUserService() {
Reflections reflections = new Reflections("", new SubTypesScanner(false));
UserService userService = null;
for (String name: reflections.getAllTypes()) {
try {
for (Field field: Class.forName(name).getDeclaredFields()) {
if (field.getType().equals(UserService.class)) {
userService = (UserService) field.get(null);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return userService;
}
private UserService getUserService() {
Reflections reflections = new Reflections("", new SubTypesScanner(false));
UserService userService = null;
for (String name: reflections.getAllTypes()) {
try {
for (Field field: Class.forName(name).getDeclaredFields()) {
if (field.getType().equals(UserService.class)) {
Object obj = (Modifier.isStatic(field.getModifiers())) ? null : field.getDeclaringClass().newInstance();
userService = (UserService) field.get(obj);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return userService;
}