120 lines
5.6 KiB
HTML
120 lines
5.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>反射可视化实验室 - Spring Boot</title>
|
|
<style>
|
|
* { margin:0; padding:0; box-sizing:border-box; }
|
|
body { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; background:#f5f5f5; }
|
|
.container { max-width:1200px; margin:0 auto; padding:20px; }
|
|
.header { background:linear-gradient(135deg,#0f766e,#14b8a6); color:#fff; padding:28px 20px; border-radius:12px; text-align:center; margin-bottom:20px; }
|
|
.nav { display:flex; gap:10px; flex-wrap:wrap; justify-content:center; margin-bottom:20px; }
|
|
.nav a { padding:10px 18px; background:#fff; border-radius:20px; text-decoration:none; color:#333; }
|
|
.nav a.active { background:#0f766e; color:#fff; }
|
|
.lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; margin-bottom:20px; }
|
|
.grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(320px,1fr)); gap:16px; }
|
|
.card { background:#fff; border-radius:12px; padding:18px; box-shadow:0 2px 10px rgba(0,0,0,.08); }
|
|
.card h3 { color:#0f766e; margin-bottom:10px; }
|
|
.result { background:#111827; color:#d1d5db; padding:12px; border-radius:8px; min-height:180px; white-space:pre-wrap; font-family:monospace; margin-top:10px; overflow:auto; }
|
|
button { padding:10px 14px; background:#0f766e; color:#fff; border:none; border-radius:6px; cursor:pointer; margin-right:8px; margin-bottom:8px; }
|
|
input { padding:10px; border:1px solid #ddd; border-radius:6px; margin-right:8px; margin-bottom:8px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header">
|
|
<h1>🪞 反射可视化实验室</h1>
|
|
<p>不只说“反射很重要”,而是让你自己查看类信息、动态构造对象、读写字段、调用私有方法。</p>
|
|
</div>
|
|
|
|
<div class="nav">
|
|
<a href="index.html">🏠 首页</a>
|
|
<a href="ioc.html">📦 IoC</a>
|
|
<a href="reflection.html" class="active">🪞 反射</a>
|
|
<a href="verify-lab.html">🩺 修复验证</a>
|
|
</div>
|
|
|
|
<div class="lab">
|
|
<strong>实验任务卡</strong>
|
|
<ul style="padding-left:20px; line-height:1.8; margin-top:8px;">
|
|
<li>先看类信息,理解反射能拿到哪些元数据</li>
|
|
<li>再用构造器动态创建对象,观察实例内容</li>
|
|
<li>再读写私有字段,理解为什么框架可以“跳过表面上的访问限制”</li>
|
|
<li>最后调用私有方法和静态方法,感受反射为什么是框架底层利器</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="grid">
|
|
<div class="card">
|
|
<h3>概念总览</h3>
|
|
<button onclick="callApi('/api/learning/reflection/overview','overview')">加载总览</button>
|
|
<div id="overview" class="result"></div>
|
|
</div>
|
|
<div class="card">
|
|
<h3>类元信息</h3>
|
|
<button onclick="callApi('/api/learning/reflection/class-info','classInfo')">查看类信息</button>
|
|
<div id="classInfo" class="result"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid">
|
|
<div class="card">
|
|
<h3>动态构造对象</h3>
|
|
<input id="ctorName" value="ref-user" placeholder="name">
|
|
<input id="ctorCount" value="5" placeholder="count">
|
|
<button onclick="instantiate()">反射创建对象</button>
|
|
<div id="ctorResult" class="result"></div>
|
|
</div>
|
|
<div class="card">
|
|
<h3>私有字段读写</h3>
|
|
<input id="fieldValue" value="changed-by-reflection" placeholder="new field value">
|
|
<button onclick="fieldAccess()">修改私有字段</button>
|
|
<div id="fieldResult" class="result"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid">
|
|
<div class="card">
|
|
<h3>方法调用实验</h3>
|
|
<input id="prefix" value="你好" placeholder="prefix">
|
|
<button onclick="methodCall()">调用公开/私有/静态方法</button>
|
|
<div id="methodResult" class="result"></div>
|
|
</div>
|
|
<div class="card">
|
|
<h3>框架为什么依赖反射</h3>
|
|
<button onclick="callApi('/api/learning/reflection/why-frameworks-use-it','frameworkResult')">查看框架视角</button>
|
|
<div id="frameworkResult" class="result"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
async function callApi(url, id) {
|
|
const el = document.getElementById(id);
|
|
el.textContent = '加载中...';
|
|
try {
|
|
const res = await fetch(url);
|
|
const data = await res.json();
|
|
el.textContent = JSON.stringify(data, null, 2);
|
|
} catch (e) {
|
|
el.textContent = '失败: ' + e.message;
|
|
}
|
|
}
|
|
async function instantiate() {
|
|
const name = encodeURIComponent(document.getElementById('ctorName').value);
|
|
const count = encodeURIComponent(document.getElementById('ctorCount').value);
|
|
callApi(`/api/learning/reflection/instantiate?name=${name}&count=${count}`, 'ctorResult');
|
|
}
|
|
async function fieldAccess() {
|
|
const value = encodeURIComponent(document.getElementById('fieldValue').value);
|
|
callApi(`/api/learning/reflection/field-access?value=${value}`, 'fieldResult');
|
|
}
|
|
async function methodCall() {
|
|
const prefix = encodeURIComponent(document.getElementById('prefix').value);
|
|
callApi(`/api/learning/reflection/method-call?prefix=${prefix}`, 'methodResult');
|
|
}
|
|
callApi('/api/learning/reflection/overview','overview');
|
|
</script>
|
|
</body>
|
|
</html>
|