[{"data":1,"prerenderedAt":1357},["ShallowReactive",2],{"post:\u002Fposts\u002Fswdesign\u002Fsw-design-notes-20":3,"posts:ordered":1064},{"id":4,"title":5,"body":6,"category":1047,"cover":1048,"date":1049,"description":1050,"extension":1051,"featured":1052,"meta":1053,"navigation":526,"path":1054,"seo":1055,"series":1056,"seriesOrder":1057,"stem":1058,"tags":1059,"__hash__":1063},"posts\u002Fposts\u002FswDesign\u002Fsw-design-notes-20.md","软件分析与设计笔记 20：面向对象概念：对象、关系与多态",{"type":7,"value":8,"toc":1019},"minimark",[9,16,21,29,39,46,50,55,77,81,84,106,110,117,121,125,131,135,149,152,156,163,167,245,249,255,261,284,288,302,310,314,324,328,332,338,341,468,479,483,486,603,613,620,624,634,637,641,670,674,699,702,743,747,1015],[10,11,12],"blockquote",{},[13,14,15],"p",{},"这是我在学习软件分析与设计时整理的系列笔记。概念部分是我按自己的理解写的，示例与图示都是自己编、自己画的。理解有偏差的地方欢迎指出。",[17,18,20],"h2",{"id":19},"_0-面向对象不是用某个语言写代码","0 面向对象不是「用某个语言写代码」",[13,22,23,24,28],{},"一个常见的误解是：用 Java 或 C# 写程序，就是在做面向对象。但如果代码里只有一个「主流程类」加几十个静态方法，那只是",[25,26,27],"strong",{},"用面向对象的语法写过程式代码","。",[13,30,31,34,35,38],{},[25,32,33],{},"面向对象（object orientation）"," 是一种组织系统描述的方式：把系统看成一组",[25,36,37],{},"相对独立的、各自负责一件事的对象","，它们通过互相发消息来协作。",[13,40,41,42,45],{},"它带来的直接好处是：",[25,43,44],{},"改变了「改动会波及多远」这件事","。后面几篇（22–25）讲的分析与设计，都是在这个基础上展开的。",[17,47,49],{"id":48},"_1-对象与类","1 对象与类",[51,52,54],"h3",{"id":53},"_11-对象类与实例","1.1 对象、类与实例",[56,57,58,65,71],"ul",{},[59,60,61,64],"li",{},[25,62,63],{},"对象（object）"," —— 一个具体的、可区分的东西：「张三」「订单 A1091」；",[59,66,67,70],{},[25,68,69],{},"类（class）"," —— 对一组对象的共同描述：「客户」「订单」；",[59,72,73,76],{},[25,74,75],{},"实例（instance）"," —— 类是模板，对象是它的一个实例。",[51,78,80],{"id":79},"_12-状态与行为","1.2 状态与行为",[13,82,83],{},"一个对象有两部分：",[56,85,86,96],{},[59,87,88,91,92,95],{},[25,89,90],{},"状态（state）"," —— 它当前是什么样，由",[25,93,94],{},"属性（attribute）"," 记录；",[59,97,98,101,102,105],{},[25,99,100],{},"行为（behaviour）"," —— 它能做什么，由",[25,103,104],{},"操作（operation）"," 定义（在代码里就是方法）。",[51,107,109],{"id":108},"_13-行为跟着数据走","1.3 行为跟着数据走",[13,111,112,113,116],{},"关键在两者的绑定：",[25,114,115],{},"行为应该由持有状态的那个对象提供。","「计算订单总价」这个操作应该属于订单，而不是属于某个外部工具类 —— 因为总价依赖的数据（明细、单价）都在订单里。这条原则看起来朴素，但它正是笔记 25 里那个「依恋情结」坏味道的判断依据。",[17,118,120],{"id":119},"_2-抽象与封装","2 抽象与封装",[51,122,124],{"id":123},"_21-抽象","2.1 抽象",[13,126,127,130],{},[25,128,129],{},"抽象（abstraction）"," 是只看需要关心的部分，忽略其余。建模时不可能把所有细节都画进去 —— 一张订单在库存模块里关心的是数量，在财务模块里关心的是金额，两处看到的「订单」本来就不该完全一样。",[51,132,134],{"id":133},"_22-封装真正保护的是什么","2.2 封装真正保护的是什么",[13,136,137,140,141,144,145,148],{},[25,138,139],{},"封装（encapsulation）"," 是把状态和行为打包在一起，并",[25,142,143],{},"决定哪些对外可见","。这个概念常被简化成「用 private 修饰字段」，但它真正保护的是",[25,146,147],{},"信息隐藏（information hiding）","：外部只能通过你提供的方式改变状态，你因此可以保证状态始终合法。",[13,150,151],{},"举个具体的：如果金额字段可以被外部直接赋值，那任何一处代码都能写出「金额为负」的订单。加了设置方法之后，你可以在那里拦住非法值。",[17,153,155],{"id":154},"_3-五种关系","3 五种关系",[13,157,158],{},[159,160],"img",{"alt":161,"src":162},"面向对象里的五种关系：依赖是临时使用，关联是长期引用并可带重数，聚合是部分可独立存在的整体部分关系，组合是部分随整体消亡的强聚合，继承是子类复用并覆盖父类行为；每种关系都给出 UML 符号与例子","\u002Fimages\u002Fsw-design-notes-20-oo-relationships.svg",[51,164,166],{"id":165},"_31-五种关系一览","3.1 五种关系一览",[168,169,170,186],"table",{},[171,172,173],"thead",{},[174,175,176,180,183],"tr",{},[177,178,179],"th",{},"关系",[177,181,182],{},"中文",[177,184,185],{},"一句话判断",[187,188,189,201,212,223,234],"tbody",{},[174,190,191,195,198],{},[192,193,194],"td",{},"dependency",[192,196,197],{},"依赖",[192,199,200],{},"临时用一下就完了",[174,202,203,206,209],{},[192,204,205],{},"association",[192,207,208],{},"关联",[192,210,211],{},"长期持有对方的引用",[174,213,214,217,220],{},[192,215,216],{},"aggregation",[192,218,219],{},"聚合",[192,221,222],{},"has-a，部分可以独立存在",[174,224,225,228,231],{},[192,226,227],{},"composition",[192,229,230],{},"组合",[192,232,233],{},"强聚合，部分随整体消亡",[174,235,236,239,242],{},[192,237,238],{},"inheritance",[192,240,241],{},"继承",[192,243,244],{},"is-a，子类可以替换父类",[51,246,248],{"id":247},"_32-依赖与关联","3.2 依赖与关联",[13,250,251,254],{},[25,252,253],{},"依赖（dependency）"," 是最弱的耦合：某个方法临时用到另一个对象。它出现在参数、局部变量里。",[13,256,257,260],{},[25,258,259],{},"关联（association）"," 是长期引用，需要写清两件事：",[56,262,263,278],{},[59,264,265,268,269,273,274,277],{},[25,266,267],{},"重数（multiplicity）"," —— 一端对应几个，例如 ",[270,271,272],"code",{},"1"," 对 ",[270,275,276],{},"*","；",[59,279,280,283],{},[25,281,282],{},"角色名（role name）"," —— 这个引用在业务上叫什么，例如「客户」持有的是他下的「订单」。",[51,285,287],{"id":286},"_33-聚合与组合的分界线","3.3 聚合与组合的分界线",[13,289,290,293,294,297,298,301],{},[25,291,292],{},"聚合（aggregation）"," 和",[25,295,296],{},"组合（composition）"," 容易混。两者的分界线不是「是否包含」，而是",[25,299,300],{},"生命周期","：",[56,303,304,307],{},[59,305,306],{},"旅行团包含若干旅客 —— 旅行团取消了，旅客还在，这是聚合；",[59,308,309],{},"订单包含订单明细 —— 订单删了，明细没有单独存在的意义，这是组合。",[51,311,313],{"id":312},"_34-继承","3.4 继承",[13,315,316,319,320,323],{},[25,317,318],{},"继承（inheritance）"," 表达 is-a：子类（subclass）复用父类（superclass）的定义，并可以覆盖（override）其中一部分行为。它的前提是一条硬约束：",[25,321,322],{},"子类必须能替换父类而不破坏使用者的预期","。如果做不到，就不该用继承 —— 常见替代方案是组合。",[17,325,327],{"id":326},"_4-多态把条件判断换成对象","4 多态：把条件判断换成对象",[51,329,331],{"id":330},"_41-不用多态的写法","4.1 不用多态的写法",[13,333,334,337],{},[25,335,336],{},"多态（polymorphism）"," 是同一段调用代码，在不同对象上产生不同行为。",[13,339,340],{},"先看不用的写法。假设要按客户类型算折扣：",[342,343,348],"pre",{"className":344,"code":345,"language":346,"meta":347,"style":347},"language-java shiki shiki-themes github-light github-dark","double discount(Customer c) {\n    if (c.getType().equals(\"VIP\")) {\n        return 0.2;\n    } else if (c.getType().equals(\"CORPORATE\")) {\n        return 0.15;\n    }\n    return 0.0;\n}\n","java","",[270,349,350,367,395,408,435,445,451,462],{"__ignoreMap":347},[351,352,355,359,363],"span",{"class":353,"line":354},"line",1,[351,356,358],{"class":357},"szBVR","double",[351,360,362],{"class":361},"sScJk"," discount",[351,364,366],{"class":365},"sVt8B","(Customer c) {\n",[351,368,370,373,376,379,382,385,388,392],{"class":353,"line":369},2,[351,371,372],{"class":357},"    if",[351,374,375],{"class":365}," (c.",[351,377,378],{"class":361},"getType",[351,380,381],{"class":365},"().",[351,383,384],{"class":361},"equals",[351,386,387],{"class":365},"(",[351,389,391],{"class":390},"sZZnC","\"VIP\"",[351,393,394],{"class":365},")) {\n",[351,396,398,401,405],{"class":353,"line":397},3,[351,399,400],{"class":357},"        return",[351,402,404],{"class":403},"sj4cs"," 0.2",[351,406,407],{"class":365},";\n",[351,409,411,414,417,420,422,424,426,428,430,433],{"class":353,"line":410},4,[351,412,413],{"class":365},"    } ",[351,415,416],{"class":357},"else",[351,418,419],{"class":357}," if",[351,421,375],{"class":365},[351,423,378],{"class":361},[351,425,381],{"class":365},[351,427,384],{"class":361},[351,429,387],{"class":365},[351,431,432],{"class":390},"\"CORPORATE\"",[351,434,394],{"class":365},[351,436,438,440,443],{"class":353,"line":437},5,[351,439,400],{"class":357},[351,441,442],{"class":403}," 0.15",[351,444,407],{"class":365},[351,446,448],{"class":353,"line":447},6,[351,449,450],{"class":365},"    }\n",[351,452,454,457,460],{"class":353,"line":453},7,[351,455,456],{"class":357},"    return",[351,458,459],{"class":403}," 0.0",[351,461,407],{"class":365},[351,463,465],{"class":353,"line":464},8,[351,466,467],{"class":365},"}\n",[13,469,470,471,474,475,478],{},"问题不在写法，而在于",[25,472,473],{},"每加一种客户类型，都要回来改这个方法","。而且同样的 ",[270,476,477],{},"if"," 很可能散落在好几处。",[51,480,482],{"id":481},"_42-用多态改写之后","4.2 用多态改写之后",[13,484,485],{},"用多态之后：",[342,487,489],{"className":344,"code":488,"language":346,"meta":347,"style":347},"abstract class Customer {\n    abstract double discount();\n}\n\nclass VipCustomer extends Customer {\n    double discount() { return 0.2; }\n}\n\nclass CorporateCustomer extends Customer {\n    double discount() { return 0.15; }\n}\n",[270,490,491,505,518,522,528,543,561,565,569,583,598],{"__ignoreMap":347},[351,492,493,496,499,502],{"class":353,"line":354},[351,494,495],{"class":357},"abstract",[351,497,498],{"class":357}," class",[351,500,501],{"class":361}," Customer",[351,503,504],{"class":365}," {\n",[351,506,507,510,513,515],{"class":353,"line":369},[351,508,509],{"class":357},"    abstract",[351,511,512],{"class":357}," double",[351,514,362],{"class":361},[351,516,517],{"class":365},"();\n",[351,519,520],{"class":353,"line":397},[351,521,467],{"class":365},[351,523,524],{"class":353,"line":410},[351,525,527],{"emptyLinePlaceholder":526},true,"\n",[351,529,530,533,536,539,541],{"class":353,"line":437},[351,531,532],{"class":357},"class",[351,534,535],{"class":361}," VipCustomer",[351,537,538],{"class":357}," extends",[351,540,501],{"class":361},[351,542,504],{"class":365},[351,544,545,548,550,553,556,558],{"class":353,"line":447},[351,546,547],{"class":357},"    double",[351,549,362],{"class":361},[351,551,552],{"class":365},"() { ",[351,554,555],{"class":357},"return",[351,557,404],{"class":403},[351,559,560],{"class":365},"; }\n",[351,562,563],{"class":353,"line":453},[351,564,467],{"class":365},[351,566,567],{"class":353,"line":464},[351,568,527],{"emptyLinePlaceholder":526},[351,570,572,574,577,579,581],{"class":353,"line":571},9,[351,573,532],{"class":357},[351,575,576],{"class":361}," CorporateCustomer",[351,578,538],{"class":357},[351,580,501],{"class":361},[351,582,504],{"class":365},[351,584,586,588,590,592,594,596],{"class":353,"line":585},10,[351,587,547],{"class":357},[351,589,362],{"class":361},[351,591,552],{"class":365},[351,593,555],{"class":357},[351,595,442],{"class":403},[351,597,560],{"class":365},[351,599,601],{"class":353,"line":600},11,[351,602,467],{"class":365},[13,604,605,606,609,610,28],{},"调用方只写 ",[270,607,608],{},"c.discount()","。新增一种客户类型，只需要加一个类，",[25,611,612],{},"已有的代码一行都不用动",[13,614,615,616,619],{},"这就是「多态能减少条件判断」的含义：",[25,617,618],{},"把「判断类型然后分支」换成了「让对象自己回答」","。它也是后面笔记 24 讲设计原则时的核心工具。",[17,621,623],{"id":622},"_5-单继承与多继承","5 单继承与多继承",[13,625,626,629,630,633],{},[25,627,628],{},"单继承（single inheritance）"," 指一个子类只能有一个父类，",[25,631,632],{},"多继承（multiple inheritance）"," 可以有多个。",[13,635,636],{},"多继承看起来更灵活，但会带来一个真实的歧义：两个父类有同名方法时，该用谁的？所以很多语言（包括 Java、C#）在类这一层只允许单继承，把「多个能力的组合」交给另一种机制去表达 —— 接口。这一点会在笔记 24 展开。",[17,638,640],{"id":639},"_6-常见误解","6 常见误解",[56,642,643,649,655,661],{},[59,644,645,648],{},[25,646,647],{},"「把所有东西都建成类就是面向对象」。"," 类多不等于设计好。一个类如果既是数据结构又是工具集合，那它只是把过程式代码装进了类里；",[59,650,651,654],{},[25,652,653],{},"「继承用来复用代码」。"," 复用的手段很多，继承的语义是 is-a。为了省几行代码而继承，往往会在后面几周付出代价；",[59,656,657,660],{},[25,658,659],{},"「封装就是加 private」。"," 如果每个字段都配了无脑的读写方法，等于没封装；",[59,662,663,666,667],{},[25,664,665],{},"「组合优于继承是绝对规则」。"," 更准确的说法是：",[25,668,669],{},"当关系不是 is-a 时，别用继承。",[17,671,673],{"id":672},"_7-本节自测","7 本节自测",[675,676,677,680,683,686,693,696],"ol",{},[59,678,679],{},"类、对象、实例三者是什么关系？",[59,681,682],{},"「计算订单总价」这个方法为什么应该属于订单，而不是放在一个工具类里？",[59,684,685],{},"聚合和组合的分界线是什么？各举一个例子。",[59,687,688,689,692],{},"用多态改写一段 ",[270,690,691],{},"if (type.equals(...))"," 的代码，改完最大的收益是什么？",[59,694,695],{},"为什么很多语言在类的层面只允许单继承？",[59,697,698],{},"封装真正保护的是什么？如果金额字段可以被外部直接赋值会怎样？",[51,700,701],{"id":701},"参考答案",[675,703,704,710,717,724,730,736],{},[59,705,706,709],{},[25,707,708],{},"类是模板，对象是它的一个实例","；对象是「一个具体可区分的东西」。类是「对一组对象的共同描述」（§1.1）。",[59,711,712,713,716],{},"因为",[25,714,715],{},"行为应该由持有状态的对象提供"," —— 总价依赖的明细、单价都在订单里。放工具类里就是笔记 25 讲的「依恋情结」（§1.3）。",[59,718,719,720,723],{},"分界线是",[25,721,722],{},"整体消亡时部分还活不活得下去","。聚合：部分可独立存在（如旅客与订单，订单取消旅客还在）；组合：部分随整体消亡（如订单与订单明细）（§3）。",[59,725,726,729],{},[25,727,728],{},"新增一种类型只需新增一个类，已有的判断代码一行都不用改","，而且判断不再散落在多处（§4）。",[59,731,712,732,735],{},[25,733,734],{},"多继承会带来菱形继承的歧义","（同一个祖先被两条路径继承时，成员该用哪一份）。所以多数语言用「单继承 + 多接口」解决（§5）。",[59,737,738,739,742],{},"封装真正保护的是",[25,740,741],{},"信息隐藏"," —— 外部只能通过你提供的方式改变状态。如果金额可被直接赋值，任何代码都能写出「金额为负」的订单，而你没有任何地方可以拦住它（§2.2）。",[17,744,746],{"id":745},"_8-术语表","8 术语表",[168,748,749,761],{},[171,750,751],{},[174,752,753,756,758],{},[177,754,755],{},"术语",[177,757,182],{},[177,759,760],{},"一句话解释",[187,762,763,774,785,795,806,817,828,839,850,861,872,882,891,900,911,922,931,940,949,960,971,982,993,1004],{},[174,764,765,768,771],{},[192,766,767],{},"object orientation",[192,769,770],{},"面向对象",[192,772,773],{},"把系统组织成一组互相协作的对象的方法",[174,775,776,779,782],{},[192,777,778],{},"object",[192,780,781],{},"对象",[192,783,784],{},"具体的、可区分的实体",[174,786,787,789,792],{},[192,788,532],{},[192,790,791],{},"类",[192,793,794],{},"对一组对象的共同描述",[174,796,797,800,803],{},[192,798,799],{},"instance",[192,801,802],{},"实例",[192,804,805],{},"类的一个具体对象",[174,807,808,811,814],{},[192,809,810],{},"state",[192,812,813],{},"状态",[192,815,816],{},"对象当前的属性取值",[174,818,819,822,825],{},[192,820,821],{},"behaviour",[192,823,824],{},"行为",[192,826,827],{},"对象能执行的操作",[174,829,830,833,836],{},[192,831,832],{},"attribute",[192,834,835],{},"属性",[192,837,838],{},"记录对象状态的数据项",[174,840,841,844,847],{},[192,842,843],{},"operation",[192,845,846],{},"操作",[192,848,849],{},"对象提供的行为，通常对应一个方法",[174,851,852,855,858],{},[192,853,854],{},"abstraction",[192,856,857],{},"抽象",[192,859,860],{},"只保留当前关心部分的做法",[174,862,863,866,869],{},[192,864,865],{},"encapsulation",[192,867,868],{},"封装",[192,870,871],{},"把状态与行为打包并控制外部访问",[174,873,874,877,879],{},[192,875,876],{},"information hiding",[192,878,741],{},[192,880,881],{},"对外隐藏内部细节，只暴露必要接口",[174,883,884,886,888],{},[192,885,194],{},[192,887,197],{},[192,889,890],{},"临时使用另一个对象的关系",[174,892,893,895,897],{},[192,894,205],{},[192,896,208],{},[192,898,899],{},"长期持有对方引用的关系",[174,901,902,905,908],{},[192,903,904],{},"multiplicity",[192,906,907],{},"重数",[192,909,910],{},"一端可以对应多少个实例",[174,912,913,916,919],{},[192,914,915],{},"role name",[192,917,918],{},"角色名",[192,920,921],{},"关联中该引用在业务上的称呼",[174,923,924,926,928],{},[192,925,216],{},[192,927,219],{},[192,929,930],{},"部分可独立存在的整体—部分关系",[174,932,933,935,937],{},[192,934,227],{},[192,936,230],{},[192,938,939],{},"部分随整体消亡的强聚合",[174,941,942,944,946],{},[192,943,238],{},[192,945,241],{},[192,947,948],{},"子类复用并覆盖父类定义的关系",[174,950,951,954,957],{},[192,952,953],{},"superclass",[192,955,956],{},"父类",[192,958,959],{},"被继承的类",[174,961,962,965,968],{},[192,963,964],{},"subclass",[192,966,967],{},"子类",[192,969,970],{},"继承父类的类",[174,972,973,976,979],{},[192,974,975],{},"single inheritance",[192,977,978],{},"单继承",[192,980,981],{},"一个类只能有一个父类",[174,983,984,987,990],{},[192,985,986],{},"multiple inheritance",[192,988,989],{},"多继承",[192,991,992],{},"一个类可以有多个父类",[174,994,995,998,1001],{},[192,996,997],{},"polymorphism",[192,999,1000],{},"多态",[192,1002,1003],{},"同一调用在不同对象上产生不同行为",[174,1005,1006,1009,1012],{},[192,1007,1008],{},"override",[192,1010,1011],{},"覆盖",[192,1013,1014],{},"子类重新实现父类的方法",[1016,1017,1018],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":347,"searchDepth":397,"depth":397,"links":1020},[1021,1022,1027,1031,1037,1041,1042,1043,1046],{"id":19,"depth":369,"text":20},{"id":48,"depth":369,"text":49,"children":1023},[1024,1025,1026],{"id":53,"depth":397,"text":54},{"id":79,"depth":397,"text":80},{"id":108,"depth":397,"text":109},{"id":119,"depth":369,"text":120,"children":1028},[1029,1030],{"id":123,"depth":397,"text":124},{"id":133,"depth":397,"text":134},{"id":154,"depth":369,"text":155,"children":1032},[1033,1034,1035,1036],{"id":165,"depth":397,"text":166},{"id":247,"depth":397,"text":248},{"id":286,"depth":397,"text":287},{"id":312,"depth":397,"text":313},{"id":326,"depth":369,"text":327,"children":1038},[1039,1040],{"id":330,"depth":397,"text":331},{"id":481,"depth":397,"text":482},{"id":622,"depth":369,"text":623},{"id":639,"depth":369,"text":640},{"id":672,"depth":369,"text":673,"children":1044},[1045],{"id":701,"depth":397,"text":701},{"id":745,"depth":369,"text":746},"学习",null,"2026-11-11","面向对象不是「用某个语言写代码」：对象与类的区别、封装真正在保护什么、五种关系（依赖、关联、聚合、组合、继承）各自何时用，以及多态为什么能减少条件判断。","md",false,{},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-20",{"title":5,"description":1050},"软件分析与设计笔记",20,"posts\u002FswDesign\u002Fsw-design-notes-20",[770,1060,1061,1062],"软件设计","UML","学习笔记","6H4SXTJbZabhbqKDL1ls_5QD0wmxJlM20SfK0L4868Q",[1065,1071,1077,1083,1089,1095,1101,1107,1113,1114,1120,1126,1132,1138,1144,1150,1156,1162,1167,1172,1177,1182,1187,1192,1197,1202,1207,1212,1217,1223,1227,1231,1235,1239,1243,1247,1251,1255,1259,1263,1267,1273,1277,1283,1287,1291,1295,1299,1303,1307,1311,1316,1320,1324,1329,1334,1340,1344,1349,1353],{"path":1066,"title":1067,"description":1068,"date":1069,"series":1056,"seriesOrder":1070},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-28","软件分析与设计笔记 28：draw.io 作图手册：五张图的符号位置、落笔顺序与自检","不模拟软件界面，只讲清三件事：每个 UML 符号在 draw.io 里搜什么词、一张图该按什么顺序落笔、画完拿什么标准自查。覆盖用例图、活动图、顺序图、类图、界面草图五种图纸，末尾附「最容易画反的十二笔」总检表。","2026-11-19",28,{"path":1072,"title":1073,"description":1074,"date":1075,"series":1056,"seriesOrder":1076},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-27","软件分析与设计笔记 27：Paper 1 应试：从读案例到交卷的一次完整演算","拿一份完整的案例，从头到尾走一遍：怎么读案例列角色、怎么在四个小问之间分配时间、每一张图从哪一句话推出来、两张表怎么填、交卷前拿什么清单自查。附 C25 真题与样卷的题型分值对照。","2026-11-18",27,{"path":1078,"title":1079,"description":1080,"date":1081,"series":1056,"seriesOrder":1082},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-26","软件分析与设计笔记 26：总结：把整条链路串起来","系列收尾：从需求到代码的完整链路回顾、每一环的产出与验收方式、六条贯穿全系列的原则，以及一份可以直接拿去做项目自查的清单。","2026-11-17",26,{"path":1084,"title":1085,"description":1086,"date":1087,"series":1056,"seriesOrder":1088},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-25","软件分析与设计笔记 25：代码重构：坏味道与手法","重构不改变外部行为、只改善内部结构：四种常见坏味道与对应手法、为什么动手之前必须先有测试、什么时候该重构，以及重构和前面那些设计模型是什么关系。","2026-11-16",25,{"path":1090,"title":1091,"description":1092,"date":1093,"series":1056,"seriesOrder":1094},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-24","软件分析与设计笔记 24：设计原则：内聚、耦合与多态","好设计怎么衡量：内聚与耦合分别在说什么、一次从「差设计」到「多态重设计」的完整对照、抽象类与接口的选择依据，以及复用为什么会从优势变成风险。","2026-11-15",24,{"path":1096,"title":1097,"description":1098,"date":1099,"series":1056,"seriesOrder":1100},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-23","软件分析与设计笔记 23：设计建模：从对象模型到能实现的方案","分析模型能用但还不能直接开工：对象模型怎么映射到关系模型、继承映射的三种方案怎么选、数据访问层与 Data Broker 解决什么问题，以及三层架构与 MVC 的分工。","2026-11-14",23,{"path":1102,"title":1103,"description":1104,"date":1105,"series":1056,"seriesOrder":1106},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-22","软件分析与设计笔记 22：分析建模：边界、实体与控制对象","不经过分析直接写代码会踩什么坑、三种分析对象各管一段、怎么用顺序图完成一次用例实现，以及从顺序图导出类的属性、操作与关系的方法。","2026-11-13",22,{"path":1108,"title":1109,"description":1110,"date":1111,"series":1056,"seriesOrder":1112},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-21","软件分析与设计笔记 21：UML：类图与顺序图","为什么需要一种共同的画法：类符号三格怎么画、五种关系的符号与设计含义、每种关系落到 Java 是什么写法，顺序图的三要素怎么摆；以及这三种最容易找不到的符号在 draw.io 里各搜什么词。","2026-11-12",21,{"path":1054,"title":5,"description":1050,"date":1049,"series":1056,"seriesOrder":1057},{"path":1115,"title":1116,"description":1117,"date":1118,"series":1056,"seriesOrder":1119},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-19","软件分析与设计笔记 19：规范化与逻辑数据模型","一次改地址引发的数据不一致，讲清规范化的真正动机；UNF 到 3NF 每一步在解决什么问题，派生字段为什么不能存，优化为什么和规范化方向相反，以及逻辑数据模型在 3NF 之上补了什么。","2026-11-10",19,{"path":1121,"title":1122,"description":1123,"date":1124,"series":1056,"seriesOrder":1125},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-18","软件分析与设计笔记 18：数据库分析：实体、关系与数据字典","为什么不能拿到需求就动手建表：实体与关系怎么判定、基数为什么必须由业务方确认、数据命名要遵守什么规则，以及数据字典四列里最容易被空着的那一列。","2026-11-09",18,{"path":1127,"title":1128,"description":1129,"date":1130,"series":1056,"seriesOrder":1131},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-17","软件分析与设计笔记 17：用生成式 AI 做设计与开发：能用的场景与要防的坑","生成式 AI 在工作流里真正站得住的三个场景 —— 造示例数据、解释陌生代码、起草初稿；它为什么会复现社会偏见、为什么会编得像真的，以及哪些内容绝不能直接采用。","2026-11-08",17,{"path":1133,"title":1134,"description":1135,"date":1136,"series":1056,"seriesOrder":1137},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-16","软件分析与设计笔记 16：从 persona 到 URS：一份交付物的完整骨架","把前面十几篇串成一份能交出去的东西：用户需求规格说明书的九个部分、每一章来自哪个环节、由谁确认，以及面向决策者的提案该讲清哪三件事。","2026-11-07",16,{"path":1139,"title":1140,"description":1141,"date":1142,"series":1056,"seriesOrder":1143},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-15","软件分析与设计笔记 15：非功能需求：把「快、稳、安全」变成数字","为什么「系统要快」不是一条需求：非功能需求怎么量化，决定性能的用户量、交易量、数据量三张表怎么估，安全需求要写清什么，以及可靠性的「不可用」该怎么定义。","2026-11-06",15,{"path":1145,"title":1146,"description":1147,"date":1148,"series":1056,"seriesOrder":1149},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-14","软件分析与设计笔记 14：软件测试：层级、方法与等价类划分","「我们测过了」这句话问题在哪：为什么静态评审和动态测试缺一不可，五个测试层级各自验证什么，白盒与黑盒的差别，以及用等价类划分和边界值把无限输入变成有限用例的方法。","2026-11-05",14,{"path":1151,"title":1152,"description":1153,"date":1154,"series":1056,"seriesOrder":1155},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-13","软件分析与设计笔记 13：需求获取：五种调查方法与一场访谈","需求从哪里来：五种事实调查方法各自适合回答什么、代价是什么，访谈从准备到记录的全过程，问卷设计里最容易犯的错，以及访谈记录必须写下来的那几项信息。","2026-11-04",13,{"path":1157,"title":1158,"description":1159,"date":1160,"series":1056,"seriesOrder":1161},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-12","软件分析与设计笔记 12：前端设计：把流程变成屏幕","界面设计不是「画得好看」：从活动图走到屏幕的三步，CRUD 任务流怎么当检查表，界面必须回答的三个问题，信息架构与五种导航类型，视觉一致性与留白，以及移动端与 Web 端的差别。","2026-11-03",12,{"path":1163,"title":1164,"description":1165,"date":1166,"series":1056,"seriesOrder":600},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-11","软件分析与设计笔记 11：Agentic AI 与业务流程自动化","AI agent 到底是什么：五项能力与四个核心组件，什么场景该用定时任务、什么该用程序、什么才值得用 agent，两种实现路径的差别，必须提前防住的四类失败模式，以及设计方法从提示词到编排的演进。","2026-11-02",{"path":1168,"title":1169,"description":1170,"date":1171,"series":1056,"seriesOrder":585},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-10","软件分析与设计笔记 10：精炼用例模型：include、extend 与泛化","三种精炼用例关系的判断标准：include 什么时候用、它和 extend 的区别到底在哪、参与者泛化与用例泛化各解决什么问题，以及精炼到什么程度就该停手。","2026-11-01",{"path":1173,"title":1174,"description":1175,"date":1176,"series":1056,"seriesOrder":571},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-09","软件分析与设计笔记 09：功能需求（二）：从流程到业务实体","活动图画完之后，怎么从流程里筛出真正的业务实体：三条判断标准、哪些名词其实不该建实体、属性从哪里来，以及领域模型和后面的数据模型分别负责什么。","2026-10-31",{"path":1178,"title":1179,"description":1180,"date":1181,"series":1056,"seriesOrder":464},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-08","软件分析与设计笔记 08：功能需求（一）：用例模型与活动图","从用户故事到用例的翻译过程：什么才算「好」的参与者，系统边界怎么划，用例描述必须写清哪四件事，活动图怎么把分支、并行与泳道画清楚，以及这两个图在 draw.io 里各用哪个形状、最容易画错哪一笔。","2026-10-30",{"path":1183,"title":1184,"description":1185,"date":1186,"series":1056,"seriesOrder":453},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-07","软件分析与设计笔记 07：用户故事：把需求写成可验收的一句话","用户故事的三段结构，怎么从用户画像和数据地图里把它提取出来，一条故事多大算合适、时序为什么也是需求的一部分，以及验收标准怎么写才算真的可验收。","2026-10-29",{"path":1188,"title":1189,"description":1190,"date":1191,"series":1056,"seriesOrder":447},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-06","软件分析与设计笔记 06：范围界定（数据侧）：用数据校验你的判断","访谈结论和数字对不上时该怎么办：分析的四个层次分别在回答什么问题、为什么不能跳级、数据准备与搜集怎么做成一张应用地图，以及数据最容易在哪几个地方骗你。","2026-10-28",{"path":1193,"title":1194,"description":1195,"date":1196,"series":1056,"seriesOrder":437},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-05","软件分析与设计笔记 05：范围界定（用户侧）：用户画像与客户旅程图","为什么「所有用户」是一个陷阱，项目边界该怎么划，用户画像要写哪五个要素、最容易写成什么废纸，客户旅程图怎么把阶段、想法和情绪画在同一张纸上，以及怎么从这两样东西一步步推到可验证的需求。","2026-10-27",{"path":1198,"title":1199,"description":1200,"date":1201,"series":1056,"seriesOrder":410},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-04","软件分析与设计笔记 04：接手陌生案例的第一步：三问与一张表","拿到一个完全陌生的业务案例，怎么从零开始不跑偏：只问 Who、What、Why 三个问题，把「问题—事实—假设—理由」记成一张四列表，说清为什么假设必须写明理由，以及带着问题进访谈为什么比空手去有效得多。","2026-10-26",{"path":1203,"title":1204,"description":1205,"date":1206,"series":1056,"seriesOrder":397},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-03","软件分析与设计笔记 03：Agile 与 Scrum：迭代、角色与产出物","从「三周做完交付，客户说这不是我要的」讲起，说清瀑布式与迭代式的根本差别，Scrum 的三个角色和三种产出物，一个 sprint 里四次固定活动各自在解决什么问题，以及敏捷里最常见的几个误解。","2026-10-25",{"path":1208,"title":1209,"description":1210,"date":1211,"series":1056,"seriesOrder":369},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-02","软件分析与设计笔记 02：设计思维、用户驱动与数据驱动","从「客服要一个能一次看完所有排期的界面」这个翻车案例讲起，说清设计思维到底是什么、用户驱动与数据驱动各自能看见什么又看不见什么、为什么真正的落点是把两者合起来的 data-informed design，以及访谈中怎么问出有用的信息。","2026-10-24",{"path":1213,"title":1214,"description":1215,"date":1216,"series":1056,"seriesOrder":354},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-01","软件分析与设计笔记 01：课程地图与从需求到设计的主干","这一篇不写具体方法，先把整条链路铺开：软件分析与设计到底要解决什么问题，从需求到设计分成哪两段，中间有哪十几个环节，一份完整的交付物里应该有什么，以及后面 27 篇笔记怎么排、新人该按什么顺序读。","2026-10-23",{"path":1218,"title":1219,"description":1220,"date":1221,"series":1222,"seriesOrder":354},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-01","Spring 学习笔记 01：IoC、依赖注入与第一个 Spring Boot 应用","从「手写 new 出来的三层结构」的痛点讲起，说清 IoC 容器、Bean 与依赖注入是怎么回事，再用 Maven 与 Spring Initializr 跑起第一个能返回 JSON 的应用。","2026-10-15","Spring 学习笔记",{"path":1224,"title":1225,"description":1226,"date":1221,"series":1222,"seriesOrder":369},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-02","Spring 学习笔记 02：Spring Data JPA 基础——实体映射与 Repository","用 ORM 把类映射到表：@Entity、@Id、@GeneratedValue 怎么用，CrudRepository 三层接口怎么选，H2 与 MySQL 怎么配，以及 ddl-auto 到底该写哪个值。",{"path":1228,"title":1229,"description":1230,"date":1221,"series":1222,"seriesOrder":397},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-03","Spring 学习笔记 03：JPA 查询——派生方法、JPQL 与分页排序","Repository 自带的方法只够按主键查，这篇讲三种自己造查询的方式：方法名派生、@Query 写 JPQL、原生 SQL，以及 Pageable 分页排序和投影返回。",{"path":1232,"title":1233,"description":1234,"date":1221,"series":1222,"seriesOrder":410},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-04","Spring 学习笔记 04：JPA 关联映射与仓储测试","一对多、多对多怎么映射，谁负责维护外键，FetchType 与 CascadeType 该怎么选，顺带用 @DataJpaTest 与 AssertJ 把仓储层测起来。",{"path":1236,"title":1237,"description":1238,"date":1221,"series":1222,"seriesOrder":437},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-05","Spring 学习笔记 05：Spring MVC 与 Thymeleaf 入门","一次页面请求在 Spring MVC 里走了哪几步，@Controller 怎么把数据交给模板，@PathVariable 与 @RequestParam 怎么取参数，以及控制器为什么必须是无状态的。",{"path":1240,"title":1241,"description":1242,"date":1221,"series":1222,"seriesOrder":447},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-06","Spring 学习笔记 06：表单绑定与服务端校验","把表单字段绑到对象上，用 Bean Validation 注解做服务端校验，把错误信息显示回用户刚填的那一页，再补上自定义校验注解与全局异常处理。",{"path":1244,"title":1245,"description":1246,"date":1221,"series":1222,"seriesOrder":453},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-07","Spring 学习笔记 07：Thymeleaf 片段复用与国际化","用 th:fragment 与 th:insert\u002Fth:replace 把导航栏、页脚抽成片段，页面套用统一布局，再用 messages.properties 与 LocaleResolver 做中英文切换。",{"path":1248,"title":1249,"description":1250,"date":1221,"series":1222,"seriesOrder":464},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-08","Spring 学习笔记 08：HTTP Session 与会话状态管理","HTTP 无状态带来的问题，Cookie 与 Session 怎么分工，Spring 里读写会话的几种方式，以及会话固定、超时、多实例共享这些必须想清楚的事。",{"path":1252,"title":1253,"description":1254,"date":1221,"series":1222,"seriesOrder":571},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-09","Spring 学习笔记 09：拦截器 HandlerInterceptor","登录检查、权限判断、请求耗时统计这类横切逻辑该放哪：HandlerInterceptor 的三个回调各在什么时机执行，怎么注册与排除路径，以及它和过滤器的分工。",{"path":1256,"title":1257,"description":1258,"date":1221,"series":1222,"seriesOrder":585},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-10","Spring 学习笔记 10：Service 层与事务","一组数据库操作要么全成功要么全失败，靠 @Transactional 怎么做到；传播行为、隔离级别、回滚规则怎么选，以及自调用失效、乐观锁悲观锁这些实战里的坑。",{"path":1260,"title":1261,"description":1262,"date":1221,"series":1222,"seriesOrder":600},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-11","Spring 学习笔记 11：REST API 基础——把 Service 暴露成接口","同一套 Service 怎么同时服务页面和客户端：@RestController 的路由与方法语义、状态码怎么给、DTO 怎么定，以及 MockMvc 端到端和切片测试的两种写法与各自的坑。",{"path":1264,"title":1265,"description":1266,"date":1221,"series":1222,"seriesOrder":1161},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-12","Spring 学习笔记 12：REST 进阶——版本、更新、跨域与文档化","接口能跑通之后要处理的几件事：URL 与响应结构怎么定、版本怎么演进、更新怎么做到可安全重试、CORS 怎么配、HATEOAS 与 Spring Data REST 该不该用。",{"path":1268,"title":1269,"description":1270,"date":1271,"series":1272,"seriesOrder":410},"\u002Fposts\u002Fjava\u002Fjava-functionalprogramming-notes","Java 函数式编程笔记：Lambda、函数式接口与 Streams","学习 Java 函数式编程时的个人笔记：Lambda 表达式的五步简写与方法引用、常见函数式接口、Stream 流水线与惰性求值，以及创建流、中间操作、终止操作与收集器的用法。示例代码均为自写，运行结果来自本地实测。","2026-10-13","Java 学习笔记",{"path":1274,"title":1275,"description":1276,"date":1271,"series":1272,"seriesOrder":397},"\u002Fposts\u002Fjava\u002Fjava-generics-notes","Java 泛型笔记：泛型方法、有界类型与泛型类","学习 Java 泛型时的个人笔记：从重复的重载方法与多态尝试讲起，再到泛型方法与类型推断、有界泛型类型、Comparable 与 Number 边界，以及泛型类在集合中的用法。示例代码均为自写，运行结果来自本地实测。",{"path":1278,"title":1279,"description":1280,"date":1281,"series":1282,"seriesOrder":410},"\u002Fposts\u002Fmysql\u002Fmysql-learning-04","MySQL 学习笔记 04：数据操纵（增删改）","MySQL 学习笔记第四篇：INSERT 插入（含批量插入与 INSERT ... SELECT）、UPDATE 更新、DELETE 删除，以及各自的坑。","2026-10-10","SQL 学习笔记",{"path":1284,"title":1285,"description":1286,"date":1281,"series":1282,"seriesOrder":437},"\u002Fposts\u002Fmysql\u002Fmysql-learning-05","MySQL 学习笔记 05：DDL 概览","MySQL 学习笔记第五篇：数据定义语言概览——Schema、Table、View、Index、Constraints 这几类对象分别对应哪些 CREATE \u002F ALTER \u002F DROP 命令。",{"path":1288,"title":1289,"description":1290,"date":1281,"series":1282,"seriesOrder":447},"\u002Fposts\u002Fmysql\u002Fmysql-learning-06","MySQL 学习笔记 06：CREATE TABLE 与数据类型","MySQL 学习笔记第六篇：CREATE TABLE 的完整语法、常用数据类型的选型建议，以及外键的两种定义方式。",{"path":1292,"title":1293,"description":1294,"date":1281,"series":1282,"seriesOrder":453},"\u002Fposts\u002Fmysql\u002Fmysql-learning-07","MySQL 学习笔记 07：索引","MySQL 学习笔记第七篇：索引的作用与 B+ 树结构、单列与复合索引的创建、索引的代价与适用场景。",{"path":1296,"title":1297,"description":1298,"date":1281,"series":1282,"seriesOrder":464},"\u002Fposts\u002Fmysql\u002Fmysql-learning-08","MySQL 学习笔记 08：DROP 与 ALTER","MySQL 学习笔记第八篇：DROP 删除数据库对象、ALTER 修改表结构，以及常见的坑。",{"path":1300,"title":1301,"description":1302,"date":1281,"series":1282,"seriesOrder":571},"\u002Fposts\u002Fmysql\u002Fmysql-learning-09","MySQL 学习笔记 09：约束与数据完整性","MySQL 学习笔记第九篇：SQL 约束——NOT NULL、CHECK、PRIMARY KEY、FOREIGN KEY 等如何保证数据完整性，以及它们的对比。",{"path":1304,"title":1305,"description":1306,"date":1281,"series":1282,"seriesOrder":585},"\u002Fposts\u002Fmysql\u002Fmysql-learning-10","MySQL 学习笔记 10：视图","MySQL 学习笔记第十篇：视图（Views）的定义与特性、和表的对比、创建与使用，以及可更新视图的限制。",{"path":1308,"title":1309,"description":1310,"date":1281,"series":1282,"seriesOrder":600},"\u002Fposts\u002Fmysql\u002Fmysql-learning-11","MySQL 学习笔记 11：存储过程","MySQL 学习笔记第十一篇：存储过程（Stored Procedures）的概念、创建与调用、带参数的写法，以及优缺点。",{"path":1312,"title":1313,"description":1314,"date":1315,"series":1282,"seriesOrder":354},"\u002Fposts\u002Fmysql\u002Fmysql-learning-01","MySQL 学习笔记 01：MySQL 基础知识","MySQL 学习笔记第一篇：MySQL Server 与 Workbench 的安装，数据库与 DBMS 的基本概念，关系模型、ACID 事务、常见数据类型，以及后续的学习路线。","2026-10-09",{"path":1317,"title":1318,"description":1319,"date":1315,"series":1282,"seriesOrder":369},"\u002Fposts\u002Fmysql\u002Fmysql-learning-02","MySQL 学习笔记 02：SELECT 查询与过滤","MySQL 学习笔记第二篇：SELECT 的基本语法与逻辑执行顺序，WHERE 过滤（比较、LIKE、IN、BETWEEN、NULL）、各种 JOIN、UNION 与子查询。",{"path":1321,"title":1322,"description":1323,"date":1315,"series":1282,"seriesOrder":397},"\u002Fposts\u002Fmysql\u002Fmysql-learning-03","MySQL 学习笔记 03：聚合、分组与输出控制","MySQL 学习笔记第三篇：COUNT\u002FSUM\u002FAVG 等聚合函数、GROUP BY 分组、HAVING 过滤、ORDER BY 与 LIMIT，以及一条 SELECT 的完整逻辑执行顺序。",{"path":1325,"title":1326,"description":1327,"date":1328,"series":1272,"seriesOrder":369},"\u002Fposts\u002Fjava\u002Fjava-oop-notes","Java 面向对象笔记：类、继承、多态与异常","学习 Java 面向对象编程时的个人笔记：类与对象、封装与访问修饰符、继承与多态、集合、抽象类与接口、异常处理。示例代码均为自写，运行结果来自本地实测。","2026-10-06",{"path":1330,"title":1331,"description":1332,"date":1333,"series":1272,"seriesOrder":354},"\u002Fposts\u002Fjava\u002Fjava-basics-notes","Java 基础语法笔记：从环境安装到方法与数组","学习 Java 基础语法时的个人笔记：JDK 安装、输入输出、变量与运算符、条件与循环、字符串、数组与方法。示例代码均为自写，运行结果来自本地实测。","2026-10-05",{"path":1335,"title":1336,"description":1337,"date":1338,"series":1339,"seriesOrder":354},"\u002Fposts\u002Fgit\u002Fgit-install-and-basics","Git 安装与基本使用","从装好 Git 到跑通日常提交流程，把最常用的几条命令和它们背后的三个区域讲清楚。","2026-10-04","Git 入门",{"path":1341,"title":1342,"description":1343,"date":1338,"series":1339,"seriesOrder":369},"\u002Fposts\u002Fgit\u002Flocal-remote-repository","本地远程仓库的部署","用自己的机器当 Git 服务器：建一个裸仓库、走 SSH 连上去，把本地提交推上去。",{"path":1345,"title":1346,"description":1347,"date":1338,"series":1348,"seriesOrder":354},"\u002Fposts\u002Fguide\u002Fguide-file-layout","文件都放在哪","文章、图片、封面分别放在仓库的什么位置，哪些目录可以放手改、哪些碰了会出问题。","博客使用指南",{"path":1350,"title":1351,"description":1352,"date":1338,"series":1348,"seriesOrder":369},"\u002Fposts\u002Fguide\u002Fguide-frontmatter","frontmatter 每个字段是什么意思","文章开头那段被横线包住的字段，逐个说明作用、默认行为和写错的后果。",{"path":1354,"title":1355,"description":1356,"date":1338,"series":1348,"seriesOrder":397},"\u002Fposts\u002Fguide\u002Fguide-markdown","正文怎么写 —— Markdown 与排版效果","标题、链接、图片、代码、表格分别怎么写，以及本站对它们做了哪些自定义处理。",1793268185384]