You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何访问JShell中代码片段创建的对象及其引用关系?

Accessing JShell Objects & Visualizing Reference Relationships

Great question! Building a GUI to map out JShell's internal object graph is such a neat project—let's break down exactly how to pull this off.

1. Grabbing Named Variables (like allObj or tst)

JShell's API gives you direct access to variables created by user code via VarSnippet instances. Every time you call eval(), you get back a list of SnippetEvents that track what changed in the JShell session. Here's how to extract variable values:

Step-by-Step Code Example

JShell jShell = JShell.create();
Map<String, Object> jshellVariables = new HashMap<>();

// Process each line of user code
List<String> userCode = Arrays.asList(
    "ArrayList<TestObject> allObj = new ArrayList<TestObject>();",
    "TestObject tst = new TestObject();",
    "TestObject tst2 = new TestObject();",
    "allObj.add(tst);",
    "allObj.add(tst2);"
);

for (String line : userCode) {
    List<SnippetEvent> events = jShell.eval(line);
    for (SnippetEvent event : events) {
        // Only process valid, variable-related snippets
        if (event.status() == SnippetStatus.VALID && event.snippet() instanceof VarSnippet) {
            VarSnippet varSnippet = (VarSnippet) event.snippet();
            Object varValue = jShell.varValue(varSnippet);
            jshellVariables.put(varSnippet.name(), varValue);
            
            // Now you have the actual object (e.g., the ArrayList or TestObject instance)
            System.out.printf("Found variable: %s -> %s%n", varSnippet.name(), varValue);
        }
    }
}

Key Notes:

  • VarSnippet.name() gives you the variable's name (like allObj).
  • jShell.varValue(varSnippet) returns the live object instance created by the user's code.
  • For method calls (like allObj.add(tst)), the SnippetEvent will be an ExpressionSnippet instead. To get the updated state of allObj, just re-fetch its value from the VarSnippet (you can get all active variables via jShell.variables()).

2. Mapping Object Reference Relationships

JShell doesn't have a built-in API to directly get object reference graphs, but you can use Java reflection to dig into an object's fields and build this graph yourself.

Building the Reference Graph

Here's a helper method to scan an object's fields (including private ones) and track its references:

// Stores object identity hash -> list of referenced objects
Map<Integer, List<Object>> referenceGraph = new HashMap<>();

private void scanObjectReferences(Object obj) {
    int objHash = System.identityHashCode(obj);
    if (obj == null || referenceGraph.containsKey(objHash)) {
        return; // Avoid duplicates and infinite loops from circular references
    }

    List<Object> referencedObjects = new ArrayList<>();
    Class<?> currentClass = obj.getClass();

    // Scan all fields in the class and its superclasses
    while (currentClass != null) {
        for (Field field : currentClass.getDeclaredFields()) {
            field.setAccessible(true); // Bypass access modifiers for private fields
            try {
                Object fieldValue = field.get(obj);
                // Skip primitives, wrappers, and strings (adjust this list as needed)
                if (fieldValue != null && !isSimpleType(fieldValue.getClass())) {
                    referencedObjects.add(fieldValue);
                    scanObjectReferences(fieldValue); // Recursively scan referenced objects
                }
            } catch (IllegalAccessException e) {
                // Handle exceptions (log, skip, etc.)
                e.printStackTrace();
            }
        }
        currentClass = currentClass.getSuperclass();
    }

    referenceGraph.put(objHash, referencedObjects);
}

// Helper to filter out simple types we don't need to track
private boolean isSimpleType(Class<?> clazz) {
    return clazz.isPrimitive() 
        || clazz.equals(Integer.class) || clazz.equals(Long.class)
        || clazz.equals(Double.class) || clazz.equals(Boolean.class)
        || clazz.equals(String.class);
}

Using This for Your Example

Once you have allObj from the variable map, call scanObjectReferences(allObj)—this will:

  1. Scan the ArrayList's internal fields (like its element array).
  2. Find the TestObject instances (tst and tst2) stored in the list.
  3. Recursively scan those TestObjects for their own references.

3. Tips for Your GUI Visualization

  • Track Object Identity: Use System.identityHashCode(obj) as a unique identifier for objects—this avoids confusion when multiple variables point to the same instance.
  • Update on Every Eval: After each user code line is executed, refresh your variable list and re-scan references to keep the visualization up-to-date.
  • Handle Circular References: The scanObjectReferences method above skips already scanned objects to prevent infinite loops (common in things like linked lists or parent-child object structures).
  • Display Context: For each object, show its class type, variable name(s) that point to it, and the objects it references—this makes the graph meaningful to users.

内容的提问来源于stack exchange,提问作者Raphael S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:18:36