Compare commits
5 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
285529c614 | 1 month ago |
|
|
35b2cd781d | 1 month ago |
|
|
9375900290 | 1 month ago |
|
|
2550ac6244 | 1 month ago |
|
|
73f3dde210 | 1 month ago |
5 changed files with 194 additions and 0 deletions
@ -0,0 +1,67 @@ |
|||||
|
import java.time.LocalDate; |
||||
|
|
||||
|
public class Article { |
||||
|
private String title; |
||||
|
private String content; |
||||
|
private String url; |
||||
|
|
||||
|
// 作业要求新增 |
||||
|
private String author; |
||||
|
private LocalDate publishDate; |
||||
|
|
||||
|
public Article() { |
||||
|
} |
||||
|
|
||||
|
public Article(String title, String content, String url, String author, LocalDate publishDate) { |
||||
|
this.title = title; |
||||
|
this.content = content; |
||||
|
this.url = url; |
||||
|
this.author = author; |
||||
|
this.publishDate = publishDate; |
||||
|
} |
||||
|
|
||||
|
// getter & setter |
||||
|
public String getTitle() { |
||||
|
return title; |
||||
|
} |
||||
|
public void setTitle(String title) { |
||||
|
this.title = title; |
||||
|
} |
||||
|
|
||||
|
public String getContent() { |
||||
|
return content; |
||||
|
} |
||||
|
public void setContent(String content) { |
||||
|
this.content = content; |
||||
|
} |
||||
|
|
||||
|
public String getUrl() { |
||||
|
return url; |
||||
|
} |
||||
|
public void setUrl(String url) { |
||||
|
this.url = url; |
||||
|
} |
||||
|
|
||||
|
public String getAuthor() { |
||||
|
return author; |
||||
|
} |
||||
|
public void setAuthor(String author) { |
||||
|
this.author = author; |
||||
|
} |
||||
|
|
||||
|
public LocalDate getPublishDate() { |
||||
|
return publishDate; |
||||
|
} |
||||
|
public void setPublishDate(LocalDate publishDate) { |
||||
|
this.publishDate = publishDate; |
||||
|
} |
||||
|
|
||||
|
// 打印文章信息 |
||||
|
public void showInfo() { |
||||
|
System.out.println("标题:" + title); |
||||
|
System.out.println("作者:" + author); |
||||
|
System.out.println("发布日期:" + publishDate); |
||||
|
System.out.println("链接:" + url); |
||||
|
System.out.println("内容:" + content); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
import java.time.LocalDate; |
||||
|
import java.util.Scanner; |
||||
|
|
||||
|
public class MainTest { |
||||
|
public static void main(String[] args) { |
||||
|
Scanner sc = new Scanner(System.in); |
||||
|
HistoryCommand history = new HistoryCommand(); |
||||
|
|
||||
|
// 实验案例1:创建Article对象测试 |
||||
|
System.out.println("----- 实验案例1:创建并打印文章对象 -----"); |
||||
|
Article art = new Article( |
||||
|
"Java入门教程", |
||||
|
"面向对象、集合、作业讲解", |
||||
|
"https://test.com/java", |
||||
|
"张老师", |
||||
|
LocalDate.of(2025,5,7) |
||||
|
); |
||||
|
art.showInfo(); |
||||
|
System.out.println(); |
||||
|
|
||||
|
// 实验案例2:命令别名 + 历史记录 + URL校验 交互测试 |
||||
|
System.out.println("----- 实验案例2:命令行交互测试 -----"); |
||||
|
System.out.println("指令示例:c 网址、h、exit"); |
||||
|
while(true){ |
||||
|
System.out.print("请输入命令:"); |
||||
|
String input = sc.nextLine().trim(); |
||||
|
|
||||
|
// 记录原始命令到历史 |
||||
|
history.addCommand(input); |
||||
|
|
||||
|
// 解析别名 |
||||
|
String realCmd = CommandUtil.parseAlias(input); |
||||
|
System.out.println("解析后命令:" + realCmd); |
||||
|
|
||||
|
// 简单指令分发 |
||||
|
if(realCmd.startsWith("crawl")){ |
||||
|
String[] parts = realCmd.split(" ",2); |
||||
|
if(parts.length >= 2){ |
||||
|
String url = parts[1]; |
||||
|
if(CommandUtil.checkUrl(url)){ |
||||
|
System.out.println("URL合法,开始爬取:" + url); |
||||
|
}else{ |
||||
|
System.out.println("URL格式不合法!"); |
||||
|
} |
||||
|
} |
||||
|
}else if(realCmd.equals("history")){ |
||||
|
// 查看历史 |
||||
|
history.showHistory(); |
||||
|
}else if(realCmd.equals("exit")){ |
||||
|
System.out.println("退出程序"); |
||||
|
break; |
||||
|
} |
||||
|
System.out.println("------------------------"); |
||||
|
} |
||||
|
sc.close(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
import java.util.regex.Pattern; |
||||
|
|
||||
|
public class CommandUtil { |
||||
|
// 命令别名映射 |
||||
|
private static Map<String,String> aliasMap; |
||||
|
// URL正则校验 |
||||
|
private static final Pattern URL_REG = Pattern.compile("^https?://.+"); |
||||
|
|
||||
|
static { |
||||
|
aliasMap = new HashMap<>(); |
||||
|
// 作业要求:别名 c 代表 crawl |
||||
|
aliasMap.put("c", "crawl"); |
||||
|
// 可扩展其他别名 |
||||
|
aliasMap.put("h", "history"); |
||||
|
aliasMap.put("e", "exit"); |
||||
|
} |
||||
|
|
||||
|
// 解析别名,返回真实命令 |
||||
|
public static String parseAlias(String input) { |
||||
|
String[] arr = input.split(" ", 2); |
||||
|
String cmd = arr[0]; |
||||
|
// 如果有别名就替换 |
||||
|
if(aliasMap.containsKey(cmd)){ |
||||
|
cmd = aliasMap.get(cmd); |
||||
|
} |
||||
|
// 拼接参数 |
||||
|
if(arr.length > 1){ |
||||
|
return cmd + " " + arr[1]; |
||||
|
} |
||||
|
return cmd; |
||||
|
} |
||||
|
|
||||
|
// 校验URL是否合法 |
||||
|
public static boolean checkUrl(String url) { |
||||
|
if(url == null || url.isBlank()) return false; |
||||
|
return URL_REG.matcher(url).matches(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
public class HistoryCommand { |
||||
|
// 用List保存所有输入过的命令 |
||||
|
private List<String> cmdList; |
||||
|
|
||||
|
public HistoryCommand() { |
||||
|
cmdList = new ArrayList<>(); |
||||
|
} |
||||
|
|
||||
|
// 添加命令到历史 |
||||
|
public void addCommand(String cmd) { |
||||
|
cmdList.add(cmd); |
||||
|
} |
||||
|
|
||||
|
// 打印全部历史命令 |
||||
|
public void showHistory() { |
||||
|
System.out.println("===== 命令历史记录 ====="); |
||||
|
for (int i = 0; i < cmdList.size(); i++) { |
||||
|
System.out.println((i+1) + ". " + cmdList.get(i)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
当多个模块共享同一个 List<Article> 引用时,会存在多方面风险: |
||||
|
1. 线程安全问题:若多线程同时读写该列表,会出现并发修改异常、数据不一致,甚至数据损坏。 |
||||
|
2. 数据污染:一个模块对列表或内部 Article 对象的修改(如修改 title)会直接影响所有持有该引用的模块,导致数据意外变更。 |
||||
|
3. 封装性破坏:外部代码可直接修改列表结构(add/remove),违背了数据封装原则,难以追踪数据变更来源。 |
||||
|
4. 内存泄漏:若列表被静态或长生命周期对象持有,内部的 Article 对象无法被GC回收,造成内存泄漏。 |
||||
|
建议通过返回不可修改视图、拷贝副本或使用线程安全集合来规避风险。 |
||||
Loading…
Reference in new issue