From 93fa60713252bdbe3f771add1f84ed676317d588 Mon Sep 17 00:00:00 2001 From: App <2314785400@qq.com> Date: Thu, 9 Apr 2026 16:36:17 +0800 Subject: [PATCH] w5,w6 --- project/.vscode/settings.json | 3 + project/OOP_封装_继承_多态.md | 917 ++++++++++++++++++ .../java/com/movieratings/model/Movie.java | 20 + .../com/movieratings/model/Movie.class | Bin 4441 -> 4875 bytes project/项目流程文档.md | 625 ++++++++++++ w5/README.md | 72 ++ w5/shape.png | Bin 0 -> 13005 bytes w5/shape/Circle.class | Bin 0 -> 386 bytes w5/shape/Circle.java | 6 + w5/shape/Main.class | Bin 0 -> 358 bytes w5/shape/Main.java | 8 + w5/shape/Rectangle.class | Bin 0 -> 395 bytes w5/shape/Rectangle.java | 6 + w5/shape/Shape.class | Bin 0 -> 199 bytes w5/shape/Shape.java | 3 + w5/vehicle.png | Bin 0 -> 11502 bytes w5/vehicle/Bike.class | Bin 0 -> 381 bytes w5/vehicle/Bike.java | 6 + w5/vehicle/Car.class | Bin 0 -> 378 bytes w5/vehicle/Car.java | 6 + w5/vehicle/Main.class | Bin 0 -> 387 bytes w5/vehicle/Main.java | 10 + w5/vehicle/Truck.class | Bin 0 -> 384 bytes w5/vehicle/Truck.java | 6 + w5/vehicle/Vehicle.class | Bin 0 -> 202 bytes w5/vehicle/Vehicle.java | 3 + w6/Animal.class | Bin 0 -> 206 bytes w6/Animal.java | 3 + w6/Animal.png | Bin 0 -> 13553 bytes w6/Cat.class | Bin 0 -> 375 bytes w6/Cat.java | 6 + w6/Dog.class | Bin 0 -> 476 bytes w6/Dog.java | 11 + w6/Main.class | Bin 0 -> 373 bytes w6/Main.java | 11 + w6/README.md | 75 ++ w6/Swimmable.class | Bin 0 -> 120 bytes w6/Swimmable.java | 3 + 38 files changed, 1800 insertions(+) create mode 100644 project/.vscode/settings.json create mode 100644 project/OOP_封装_继承_多态.md create mode 100644 project/项目流程文档.md create mode 100644 w5/README.md create mode 100644 w5/shape.png create mode 100644 w5/shape/Circle.class create mode 100644 w5/shape/Circle.java create mode 100644 w5/shape/Main.class create mode 100644 w5/shape/Main.java create mode 100644 w5/shape/Rectangle.class create mode 100644 w5/shape/Rectangle.java create mode 100644 w5/shape/Shape.class create mode 100644 w5/shape/Shape.java create mode 100644 w5/vehicle.png create mode 100644 w5/vehicle/Bike.class create mode 100644 w5/vehicle/Bike.java create mode 100644 w5/vehicle/Car.class create mode 100644 w5/vehicle/Car.java create mode 100644 w5/vehicle/Main.class create mode 100644 w5/vehicle/Main.java create mode 100644 w5/vehicle/Truck.class create mode 100644 w5/vehicle/Truck.java create mode 100644 w5/vehicle/Vehicle.class create mode 100644 w5/vehicle/Vehicle.java create mode 100644 w6/Animal.class create mode 100644 w6/Animal.java create mode 100644 w6/Animal.png create mode 100644 w6/Cat.class create mode 100644 w6/Cat.java create mode 100644 w6/Dog.class create mode 100644 w6/Dog.java create mode 100644 w6/Main.class create mode 100644 w6/Main.java create mode 100644 w6/README.md create mode 100644 w6/Swimmable.class create mode 100644 w6/Swimmable.java diff --git a/project/.vscode/settings.json b/project/.vscode/settings.json new file mode 100644 index 0000000..7b016a8 --- /dev/null +++ b/project/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.compile.nullAnalysis.mode": "automatic" +} \ No newline at end of file diff --git a/project/OOP_封装_继承_多态.md b/project/OOP_封装_继承_多态.md new file mode 100644 index 0000000..6f85684 --- /dev/null +++ b/project/OOP_封装_继承_多态.md @@ -0,0 +1,917 @@ +# 封装、继承、多态(Java示例) + +本文档基于当前项目中的 Java 源代码,整理了封装、继承、多态三个面向对象核心概念的说明和示例代码。 + +## 1. 说明 + +### 1.1 封装(Encapsulation) +封装是把类的数据(属性)和对数据的操作(方法)放在一起。通过把字段设为 `private`,再提供 `public` getter/setter 方法,让外部不能直接访问内部数据,从而保护数据、隐藏实现。 + +项目中典型示例: +- `src/main/java/com/movieratings/model/Movie.java` +- `src/main/java/com/movieratings/model/DirectorStats.java` + +### 1.2 继承(Inheritance) +继承让一个类获得另一个类或接口的特性。Java 中使用 `extends` 表示类继承类,使用 `implements` 表示类实现接口。接口也可以继承其他接口。 + +项目中典型示例: +- `src/main/java/com/movieratings/repository/MovieRepository.java` +- `src/main/java/com/movieratings/DataInitializer.java` +- `src/main/java/com/movieratings/model/Movie.java` +- `src/main/java/com/movieratings/model/DirectorStats.java` + +### 1.3 多态(Polymorphism) +多态是指同一个引用类型,运行时可以指向不同的对象,并执行不同的实现。通常表现为接口类型引用指向实现类对象,或者子类重写父类方法。 + +项目中典型示例: +- `DataInitializer` 实现了 `CommandLineRunner`,Spring 会以接口类型调用它 +- `MovieRepository` 继承自 `JpaRepository`,可以把它当作 `JpaRepository` 使用 +- `Movie` 重写了 `toString()` 方法,展示了动态绑定 + +## 2. 相关代码 + +### 2.1 `Movie.java` - 封装与多态示例 + +文件路径:`src/main/java/com/movieratings/model/Movie.java` + +```java +package com.movieratings.model; + +import javax.persistence.*; +import java.io.Serializable; + +/** + * 电影数据实体类 + */ +@Entity +@Table(name = "movies") +public class Movie implements Serializable { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String title; // 标题 + private double rating; // 评分 + private int releaseYear; // 年份 + private int rank; // 排名 + private String quote; // 简评/台词 + private String director; // 导演 + private int reviewCount; // 评价人数 + private String country; // 国家/地区 + private double boxOffice; // 票房 (模拟/演示) + private String type; // 作品类型 (电影、电视剧、纪录片等) + private String posterUrl; // 海报图片链接 + + public Movie() {} + + public Movie(String title, double rating, int releaseYear, int rank, String quote, String director, int reviewCount, String country, double boxOffice, String type, String posterUrl) { + this.title = title; + this.rating = rating; + this.releaseYear = releaseYear; + this.rank = rank; + this.quote = quote; + this.director = director; + this.reviewCount = reviewCount; + this.country = country; + this.boxOffice = boxOffice; + this.type = type; + this.posterUrl = posterUrl; + } + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public String getCountry() { return country; } + public void setCountry(String country) { this.country = country; } + + public double getBoxOffice() { return boxOffice; } + public void setBoxOffice(double boxOffice) { this.boxOffice = boxOffice; } + + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + + public double getRating() { return rating; } + public void setRating(double rating) { this.rating = rating; } + + public int getReleaseYear() { return releaseYear; } + public void setReleaseYear(int releaseYear) { this.releaseYear = releaseYear; } + + public int getRank() { return rank; } + public void setRank(int rank) { this.rank = rank; } + + public String getQuote() { return quote; } + public void setQuote(String quote) { this.quote = quote; } + + public String getDirector() { return director; } + public void setDirector(String director) { this.director = director; } + + public int getReviewCount() { return reviewCount; } + public void setReviewCount(int reviewCount) { this.reviewCount = reviewCount; } + + public String getType() { return type; } + public void setType(String type) { this.type = type; } + + public String getPosterUrl() { return posterUrl; } + public void setPosterUrl(String posterUrl) { this.posterUrl = posterUrl; } + + @Override + public String toString() { + return "Movie{" + + "id=" + id + + ", title='" + title + '\'' + + ", rating=" + rating + + ", releaseYear=" + releaseYear + + ", rank=" + rank + + ", quote='" + quote + '\'' + + ", director='" + director + '\'' + + ", reviewCount=" + reviewCount + + ", type='" + type + '\'' + + '}'; + } + + /** + * 重写 equals() — 两部电影 ID 相同则认为是同一部 + * equals 和 hashCode 必须配对重写 + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Movie other = (Movie) obj; + return id != null && id.equals(other.id); + } + + /** + * 重写 hashCode() — 与 equals() 保持一致,基于 id 计算 + */ + @Override + public int hashCode() { + return id != null ? id.hashCode() : 0; + } +} +``` + +#### 2.1.1 说明 +- 所有字段都使用 `private`,这是封装的核心。 +- 通过 `public getXxx()` 和 `public setXxx(...)` 提供访问和修改接口。 +- `toString()` 方法被重写,这是多态的一种体现:运行时调用的是 `Movie` 的实现。 +- **`equals()` 和 `hashCode()` 配对重写** — 这是 Java OOP 的重要规则: + - 如果两个对象 `equals()` 为 true,它们的 `hashCode()` 必须相等。 + - 重写 `equals()` 时必须同时重写 `hashCode()`,否则在 `HashMap`、`HashSet` 等集合中会出错。 + - `getClass() != obj.getClass()` 确保只比较同类型的对象。 + + +### 2.2 `DirectorStats.java` - 封装示例 + +文件路径:`src/main/java/com/movieratings/model/DirectorStats.java` + +```java +package com.movieratings.model; + +import java.io.Serializable; + +/** + * 导演作品统计 DTO + */ +public class DirectorStats implements Serializable { + private String director; // 导演姓名 + private long totalWorks; // 作品总数 + private String representativePoster; // 代表作品海报 + private double averageRating; // 平均评分 + private double totalBoxOffice; // 总票房 + + public DirectorStats(String director, long totalWorks, String representativePoster, double averageRating, double totalBoxOffice) { + this.director = director; + this.totalWorks = totalWorks; + this.representativePoster = representativePoster; + this.averageRating = averageRating; + this.totalBoxOffice = totalBoxOffice; + } + + public String getDirector() { return director; } + public void setDirector(String director) { this.director = director; } + + public long getTotalWorks() { return totalWorks; } + public void setTotalWorks(long totalWorks) { this.totalWorks = totalWorks; } + + public String getRepresentativePoster() { return representativePoster; } + public void setRepresentativePoster(String representativePoster) { this.representativePoster = representativePoster; } + + public double getAverageRating() { return averageRating; } + public void setAverageRating(double averageRating) { this.averageRating = averageRating; } + + public double getTotalBoxOffice() { return totalBoxOffice; } + public void setTotalBoxOffice(double totalBoxOffice) { this.totalBoxOffice = totalBoxOffice; } +} +``` + +#### 2.2.1 说明 +- 类字段同样设为 `private`。 +- 通过 getter/setter 访问属性,这是封装的标准写法。 + + +### 2.3 `MovieRepository.java` - 继承示例 + +文件路径:`src/main/java/com/movieratings/repository/MovieRepository.java` + +```java +package com.movieratings.repository; + +import com.movieratings.model.Movie; +import com.movieratings.model.DirectorStats; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface MovieRepository extends JpaRepository { + + /** + * 按导演统计作品数量排行榜,支持搜索、作品类型过滤和分页 + */ + @Query("SELECT new com.movieratings.model.DirectorStats(m.director, COUNT(m), MAX(m.posterUrl), AVG(m.rating), SUM(m.boxOffice)) " + + "FROM Movie m " + + "WHERE (:name IS NULL OR m.director LIKE %:name%) " + + "AND (:type IS NULL OR m.type = :type) " + + "GROUP BY m.director " + + "ORDER BY COUNT(m) DESC") + Page findDirectorRankings(@Param("name") String name, @Param("type") String type, Pageable pageable); + + /** + * 获取指定导演的作品列表 + */ + List findByDirector(String director); + + /** + * 获取所有不同的作品类型 + */ + @Query("SELECT DISTINCT m.type FROM Movie m WHERE m.type IS NOT NULL") + List findAllTypes(); +} +``` + +#### 2.3.1 说明 +- `MovieRepository` 通过 `extends JpaRepository` 继承了 Spring Data JPA 提供的通用数据访问方法。 +- 这就是继承的写法,子接口自动拥有父接口的行为。 + + +### 2.5 `DataAnalyzer.java` - 内部类封装与方法封装 + +文件路径:`src/main/java/com/movieratings/analysis/DataAnalyzer.java` + +```java +package com.movieratings.analysis; + +import com.movieratings.model.Movie; +import org.apache.commons.math3.stat.correlation.PearsonsCorrelation; +import org.apache.commons.math3.stat.inference.TTest; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 数据分析类 + */ +public class DataAnalyzer { + + /** + * 年份与评分相关性分析 (Pearson 相关系数) + */ + public CorrelationResult analyzeYearRatingCorrelation(List movies) { + double[] years = movies.stream().mapToDouble(Movie::getReleaseYear).toArray(); + double[] ratings = movies.stream().mapToDouble(Movie::getRating).toArray(); + + PearsonsCorrelation correlation = new PearsonsCorrelation(); + double coefficient = correlation.correlation(years, ratings); + + TTest tTest = new TTest(); + double pValue = tTest.tTest(years, ratings); + + return new CorrelationResult(coefficient, pValue); + } + + /** + * 导演作品统计结果类(内部静态类,体现封装) + */ + public static class DirectorStats { + private String name; // 导演姓名 + private long count; // 作品数量 + private double avgRating; // 平均评分 + private double totalBoxOffice; // 总票房 + + public DirectorStats(String name, long count, double avgRating, double totalBoxOffice) { + this.name = name; + this.count = count; + this.avgRating = avgRating; + this.totalBoxOffice = totalBoxOffice; + } + + public String getName() { return name; } + public long getCount() { return count; } + public double getAvgRating() { return avgRating; } + public double getTotalBoxOffice() { return totalBoxOffice; } + } + + /** + * 导演作品数量排行榜 (前 20 位) + */ + public List getTopDirectors(List movies, int topN) { + Map> directorMap = movies.stream() + .filter(m -> m.getDirector() != null) + .collect(Collectors.groupingBy(Movie::getDirector)); + + return directorMap.entrySet().stream() + .map(entry -> { + String name = entry.getKey(); + List directorMovies = entry.getValue(); + long count = directorMovies.size(); + double avgRating = directorMovies.stream() + .mapToDouble(Movie::getRating).average().orElse(0.0); + double totalBoxOffice = directorMovies.stream() + .mapToDouble(m -> m.getBoxOffice()).sum(); + return new DirectorStats(name, count, avgRating, totalBoxOffice); + }) + .sorted((a, b) -> Long.compare(b.getCount(), a.getCount())) + .limit(topN) + .collect(Collectors.toList()); + } + + /** + * 相关性结果封装类(内部静态类) + */ + public static class CorrelationResult { + private double coefficient; + private double pValue; + + public CorrelationResult(double coefficient, double pValue) { + this.coefficient = coefficient; + this.pValue = pValue; + } + + public double getCoefficient() { return coefficient; } + public double getPValue() { return pValue; } + + public String getSignificance() { + if (pValue < 0.01) return "极显著 (p < 0.01)"; + if (pValue < 0.05) return "显著 (p < 0.05)"; + return "不显著 (p >= 0.05)"; + } + } + + /** + * 统计评分基本信息 + */ + public DoubleSummaryStatistics analyzeRatings(List movies) { + return movies.stream() + .mapToDouble(Movie::getRating) + .summaryStatistics(); + } + + /** + * 按评分段统计 + */ + public Map countMoviesByRatingRange(List movies) { + return movies.stream() + .collect(Collectors.groupingBy(m -> { + double r = m.getRating(); + if (r >= 9.5) return "9.5-10.0"; + if (r >= 9.0) return "9.0-9.4"; + if (r >= 8.5) return "8.5-8.9"; + return "8.5以下"; + }, Collectors.counting())); + } + + /** + * 找出评价人数最多的前 N 部电影 + */ + public List findMostReviewed(List movies, int n) { + return movies.stream() + .sorted((m1, m2) -> Integer.compare(m2.getReviewCount(), m1.getReviewCount())) + .limit(n) + .collect(Collectors.toList()); + } +} +``` + +#### 2.5.1 说明 +- **封装**:`DirectorStats` 和 `CorrelationResult` 是 `DataAnalyzer` 的**内部静态类**,字段为 `private`,通过 `public` getter 暴露数据,是封装的典型应用。 +- **封装**:`getSignificance()` 方法把 p 值的判断逻辑封装在类内部,外部只需调用方法,不需要知道判断规则。 +- **封装**:各个分析方法(`analyzeRatings`、`countMoviesByRatingRange` 等)将复杂的数据处理逻辑封装为单一方法调用。 +- **多态**:`sorted((m1, m2) -> ...)` 使用了函数式接口 `Comparator`,这是多态在 Java 8+ 中的体现——接口引用指向 Lambda 表达式实现。 + +--- + +### 2.6 `MovieCrawler.java` - 常量封装与私有方法封装 + +文件路径:`src/main/java/com/movieratings/crawler/MovieCrawler.java` + +```java +package com.movieratings.crawler; + +import com.movieratings.model.Movie; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 电影数据爬虫类 - 抓取豆瓣 Top 250 + */ +@Component +public class MovieCrawler { + // 封装:常量使用 private static final,外部无法修改 + private static final String BASE_URL = "https://movie.douban.com/top250"; + private static final String USER_AGENT = "Mozilla/5.0 ..."; + + // 公开方法:提供单一清晰的调用入口 + public List crawl(int limit) { + List movies = new ArrayList<>(); + int start = 0; + + while (movies.size() < limit && start < 250) { + String url = BASE_URL + "?start=" + start + "&filter="; + try { + Document doc = Jsoup.connect(url).userAgent(USER_AGENT).get(); + Elements items = doc.select(".item"); + if (items.isEmpty()) break; + + for (Element item : items) { + if (movies.size() >= limit) break; + try { + Movie movie = parseMovie(item); // 调用私有方法 + movies.add(movie); + } catch (Exception e) { + System.err.println("解析失败: " + e.getMessage()); + } + } + start += 25; + Thread.sleep(1000); // 控制请求频率 + } catch (IOException | InterruptedException e) { + System.err.println("网络请求失败: " + e.getMessage()); + break; + } + } + return movies; + } + + // 封装:私有方法隐藏解析细节,外部只需调用 crawl() + private Movie parseMovie(Element item) { + Movie movie = new Movie(); + movie.setRank(Integer.parseInt(item.select(".pic em").text())); + movie.setTitle(item.select(".title").first().text()); + movie.setRating(Double.parseDouble(item.select(".rating_num").text())); + movie.setPosterUrl(item.select(".pic img").attr("src")); + movie.setType("电影"); + + String bdText = item.select(".bd p").first().text(); + String[] parts = bdText.split("\n"); + String infoLine = parts[0]; + + Pattern yearPattern = Pattern.compile("\\d{4}"); + Matcher matcher = yearPattern.matcher(infoLine); + if (matcher.find()) { + movie.setReleaseYear(Integer.parseInt(matcher.group())); + } + + if (infoLine.contains("导演: ")) { + int start = infoLine.indexOf("导演: ") + 4; + int end = infoLine.indexOf(" ", start); + if (end == -1) end = infoLine.length(); + movie.setDirector(infoLine.substring(start, end).trim()); + } + + String[] infoParts = infoLine.split(" / "); + if (infoParts.length >= 3) { + movie.setCountry(infoParts[infoParts.length - 2].trim()); + } + + Element starDiv = item.selectFirst(".star"); + if (starDiv != null) { + String starText = starDiv.text(); + Pattern reviewPattern = Pattern.compile("([\\d,]+)人评价"); + Matcher reviewMatcher = reviewPattern.matcher(starText); + if (reviewMatcher.find()) { + String countStr = reviewMatcher.group(1).replace(",", ""); + int count = Integer.parseInt(countStr); + movie.setReviewCount(count); + movie.setBoxOffice(count * 0.5 + (Math.random() * 100)); + } + } + + movie.setQuote(item.select(".inq").text()); + return movie; + } +} +``` + +#### 2.6.1 说明 +- **封装**:`BASE_URL` 和 `USER_AGENT` 使用 `private static final`,外部无法访问和修改,是常量封装的标准做法。 +- **封装**:`parseMovie()` 是 `private` 方法,把 HTML 解析细节隐藏起来。外部调用者只需知道 `crawl(limit)` 返回列表,不关心内部如何解析。 +- 这是**方法级别的封装**——将复杂的实现细节隐藏在私有方法中,对外暴露简洁的公共接口。 + +--- + +### 2.7 `MovieService.java` / `DirectorController.java` - 组合与依赖注入 + +文件路径:`src/main/java/com/movieratings/service/MovieService.java` + +```java +@Service +public class MovieService { + + @Autowired + private MovieRepository movieRepository; // 组合:持有另一个对象的引用 + + @Cacheable(value = "directorRankings", key = "{#name, #type, #page, #size}") + public Page getDirectorRankings(String name, String type, int page, int size) { + Pageable pageable = PageRequest.of(page, size); + return movieRepository.findDirectorRankings( + (name == null || name.isEmpty()) ? null : name, + (type == null || type.isEmpty()) ? null : type, + pageable + ); + } + + @Transactional + @CacheEvict(value = {"directorRankings", "movieTypes"}, allEntries = true) + public void refreshData(List movies) { + movieRepository.deleteAll(); + movieRepository.saveAll(movies); + } +} +``` + +#### 2.7.1 说明 +- **组合优于继承**:`MovieService` 没有继承 `MovieRepository`,而是通过 `@Autowired` **持有**它的引用。这是"组合"关系,是比继承更推荐的设计。 +- 初学者应理解:**继承表示"是一个"(is-a)关系,组合表示"有一个"(has-a)关系。** 优先使用组合。 + +--- + + +## 3. 概念对照表 + +| 概念 | 代码位置 | 说明 | +| --- | --- | --- | +| 封装 | `Movie.java`, `DirectorStats.java` | 字段 `private` + getter/setter | +| 封装 | `DataAnalyzer.java` 内部类 | 内部静态类的 `private` 字段 + getter | +| 封装 | `MovieCrawler.java` | `private static final` 常量 + `private` 方法 | +| 封装 | `MovieService.java` | 业务逻辑封装,隐藏 Repository 细节 | +| 继承 | `MovieRepository.java` | `extends JpaRepository` | +| 接口实现 | `DataInitializer.java` | `implements CommandLineRunner` | +| 组合 | `MovieService.java` | `@Autowired private MovieRepository` | +| 多态 | `Movie.toString()` / `DataInitializer` / `MovieRepository` | 运行时接口引用与子类方法重写 | +| 多态 | `DataAnalyzer.java` | Lambda 实现 `Comparator` 函数式接口 | + + +## 4. 项目代码中缺漏的 OOP 代码(重要) + +当前项目代码能说明基本的封装、继承、多态概念,但作为**教学项目**,以下重要代码是缺失的。 +建议初学者在理解本项目后,自行编写补充练习。 + +### 4.1 缺少 `equals()` 和 `hashCode()` 重写(已补充到源码) + +`Movie.java` 的 `toString()` 已使用 `@Override`。本项目已在源码中补充 `equals()` 和 `hashCode()` 的配对重写示例。这是 Java OOP 的核心规则: +- 如果两个对象 `equals()` 为 true,它们的 `hashCode()` 必须相等。 +- 重写 `equals()` 时必须同时重写 `hashCode()`,否则在 `HashMap`/`HashSet` 等集合中会出错。 + +项目中 `Movie.toString()` 已有 `@Override`,但以下为完整的方法重写对照示例: + +```java +/** + * 完整的方法重写示例,注意每个方法都有 @Override 注解 + */ +public class Movie { + // ... 字段省略 ... + + /** + * 重写 Object 类的 toString() 方法 + * @Override 告诉编译器:我在重写父类方法,如果拼写错误会报错 + */ + @Override + public String toString() { + return title + " (" + releaseYear + ") - 评分: " + rating; + } + + /** + * 重写 Object 类的 equals() 方法 + * 两部电影 ID 相同就认为是同一部 + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Movie other = (Movie) obj; + return id != null && id.equals(other.id); + } + + /** + * 重写 hashCode() — equals 和 hashCode 必须配对重写 + */ + @Override + public int hashCode() { + return id != null ? id.hashCode() : 0; + } +} +``` + +> **初学者提示**:重写方法时始终加上 `@Override`,这样如果方法签名写错,编译器会报错。 + +--- + +### 4.2 缺少 `extends` 父类的显式类继承示例 + +项目中唯一的 `extends` 出现在 `MovieRepository extends JpaRepository`,这是一个**接口继承接口**。 +项目中**没有** `class A extends class B` 的类继承示例。 + +**建议补充示例 — 类继承:** + +```java +/** + * 父类:媒体作品(电影、电视剧、纪录片的共同父类) + */ +public class MediaWork { + private String title; + private double rating; + private int releaseYear; + private String director; + + public MediaWork(String title, double rating, int releaseYear, String director) { + this.title = title; + this.rating = rating; + this.releaseYear = releaseYear; + this.director = director; + } + + public String getTitle() { return title; } + public double getRating() { return rating; } + public int getReleaseYear() { return releaseYear; } + public String getDirector() { return director; } + + @Override + public String toString() { + return title + " (" + releaseYear + ") 导演: " + director; + } +} + +/** + * 子类:电影 — 继承 MediaWork,添加电影特有属性 + */ +public class Movie extends MediaWork { + private String quote; // 电影特有:经典台词 + private String country; // 电影特有:国家 + private double boxOffice; // 电影特有:票房 + + public Movie(String title, double rating, int releaseYear, String director, + String quote, String country, double boxOffice) { + super(title, rating, releaseYear, director); // 调用父类构造方法 + this.quote = quote; + this.country = country; + this.boxOffice = boxOffice; + } + + public String getQuote() { return quote; } + public double getBoxOffice() { return boxOffice; } + + @Override + public String toString() { + return super.toString() + " | 票房: " + boxOffice; + } +} + +/** + * 子类:电视剧 — 继承 MediaWork,添加电视剧特有属性 + */ +public class TVSeries extends MediaWork { + private int seasons; // 电视剧特有:季数 + private int episodesPerSeason; // 电视剧特有:每季集数 + + public TVSeries(String title, double rating, int releaseYear, String director, + int seasons, int episodesPerSeason) { + super(title, rating, releaseYear, director); + this.seasons = seasons; + this.episodesPerSeason = episodesPerSeason; + } + + public int getSeasons() { return seasons; } + + @Override + public String toString() { + return super.toString() + " | " + seasons + "季"; + } +} +``` + +**使用示例(体现多态):** + +```java +// 多态:父类引用指向子类对象 +MediaWork work1 = new Movie("肖申克的救赎", 9.7, 1994, "弗兰克·德拉邦特", + "希望让人自由", "美国", 5000); +MediaWork work2 = new TVSeries("绝命毒师", 9.5, 2008, "文斯·吉里根", 5, 13); + +// 多态数组 +MediaWork[] works = {work1, work2}; +for (MediaWork work : works) { + // 运行时根据实际类型调用对应的 toString() + System.out.println(work.toString()); + // 还可以访问父类定义的方法 + System.out.println("评分: " + work.getRating()); +} +``` + +> **初学者提示**: +> - `super(...)` 调用父类构造方法,必须放在子类构造方法的**第一行**。 +> - `@Override` 重写的方法,运行时会根据**实际对象类型**调用对应版本,这就是多态。 +> - Java 中类只能**单继承**(一个类只能有一个直接父类),但可以实现多个接口。 + +--- + +### 4.3 缺少抽象类和抽象方法示例 + +项目中没有 `abstract` 关键字的使用。抽象类是理解继承和多态的重要桥梁。 + +**建议补充示例:** + +```java +/** + * 抽象类:定义媒体作品的共同行为和强制子类实现的规则 + * 抽象类不能被直接实例化,只能被继承 + */ +public abstract class MediaWork { + private String title; + private double rating; + + public MediaWork(String title, double rating) { + this.title = title; + this.rating = rating; + } + + public String getTitle() { return title; } + public double getRating() { return rating; } + + /** + * 抽象方法:没有方法体,强制子类提供自己的实现 + * 不同媒体类型的展示格式不同,由各自子类决定 + */ + public abstract String getDisplayFormat(); + + /** + * 普通方法:所有子类共享,不需要重写 + */ + public String getRatingStars() { + int stars = (int) Math.round(rating / 2.0); // 5星制 + return "★".repeat(stars) + "☆".repeat(5 - stars); + } +} + +/** + * 具体子类:必须实现所有抽象方法 + */ +public class Movie extends MediaWork { + private String country; + + public Movie(String title, double rating, String country) { + super(title, rating); + this.country = country; + } + + @Override + public String getDisplayFormat() { + return "电影: " + getTitle() + " [" + country + "] " + getRatingStars(); + } +} + +public class TVSeries extends MediaWork { + private int seasons; + + public TVSeries(String title, double rating, int seasons) { + super(title, rating); + this.seasons = seasons; + } + + @Override + public String getDisplayFormat() { + return "电视剧: " + getTitle() + " (" + seasons + "季) " + getRatingStars(); + } +} +``` + +> **初学者提示**: +> - 包含抽象方法的类**必须**声明为 `abstract`。 +> - 子类如果**不实现**所有抽象方法,也必须声明为 `abstract`。 +> - 抽象类和接口的区别:抽象类可以有构造方法和字段,接口(Java 8+)可以有默认方法但不能有实例字段。 + +--- + +### 4.4 缺少接口定义示例 + +项目中有 `implements`(实现接口)和 `extends`(接口继承接口),但**没有自己定义接口**。 + +**建议补充示例:** + +```java +/** + * 接口:定义媒体作品应该具备的行为 + * 接口中所有方法默认是 public abstract 的 + */ +public interface MediaPlayable { + /** 播放 */ + void play(); + + /** 暂停 */ + void pause(); + + /** 停止 */ + void stop(); + + /** + * 默认方法(Java 8+):提供默认实现,实现类可以选择性地覆盖 + */ + default void showInfo() { + System.out.println("正在播放媒体内容..."); + } +} + +/** + * 实现接口 + */ +public class MoviePlayer implements MediaPlayable { + private String title; + + public MoviePlayer(String title) { + this.title = title; + } + + @Override + public void play() { + System.out.println("开始播放电影: " + title); + } + + @Override + public void pause() { + System.out.println("暂停播放: " + title); + } + + @Override + public void stop() { + System.out.println("停止播放: " + title); + } +} + +/** + * 多态示例:接口类型引用不同实现 + */ +public class Demo { + public static void main(String[] args) { + MediaPlayable player = new MoviePlayer("肖申克的救赎"); + player.play(); // 调用 MoviePlayer 的实现 + player.pause(); + player.showInfo(); // 调用接口的默认方法 + } +} +``` + +> **初学者提示**: +> - 接口定义"**能做什么**"(能力),类定义"**是什么**"(身份)。 +> - 一个类可以实现**多个**接口(`implements A, B, C`),弥补了 Java 单继承的限制。 +> - Java 8 起,接口可以有 `default` 方法和 `static` 方法。 + +--- + +### 4.5 缺漏总结 + +| 缺失的 OOP 代码 | 状态 | 说明 | +| --- | --- | --- | +| `@Override` 注解 | 已有 | `Movie.toString/equals/hashCode` 均使用 `@Override` | +| `equals()` / `hashCode()` 重写 | 已补充到源码 | `Movie.java` 已添加配对重写 | +| 类继承 (`class A extends class B`) | 缺失 | 只有接口继承,没有父类派生子类(见补充示例代码) | +| `super()` 调用父类构造 | 缺失 | 类继承中调用父类构造方法(见补充示例代码) | +| 抽象类 (`abstract class`) | 缺失 | 抽象方法和具体方法的混合(见补充示例代码) | +| 自定义接口 (`interface`) | 缺失 | 只有自己定义接口才能完整展示接口概念(见补充示例代码) | +| 多态数组 / 多态集合 | 缺失 | 父类引用数组指向不同子类对象(见补充示例代码) | + + +## 5. 初学者提示 + +- **封装**让你控制类的数据访问权限,不要直接访问对象的字段。 +- **继承**让你复用已有行为,接口继承有助于解耦。优先使用接口继承而非类继承。 +- **多态**让代码更灵活,写接口类型变量并在运行时指向不同实现。 +- **组合优于继承**:能用 `has-a` 的地方就不要用 `is-a`。 +- **始终使用 `@Override`** 注解标注重写方法,避免拼写错误。 +- 在这个项目中,`Movie` 和 `DirectorStats` 是数据模型类,`MovieRepository` 是持久化接口,`DataInitializer` 是程序启动时执行的初始化逻辑。 + +--- + +以上内容已经包含项目中所有与封装、继承、多态相关的主要代码段,并补充了项目中缺失的重要 OOP 代码示例。 \ No newline at end of file diff --git a/project/src/main/java/com/movieratings/model/Movie.java b/project/src/main/java/com/movieratings/model/Movie.java index 74ae307..1f965d6 100644 --- a/project/src/main/java/com/movieratings/model/Movie.java +++ b/project/src/main/java/com/movieratings/model/Movie.java @@ -91,4 +91,24 @@ public class Movie implements Serializable { ", type='" + type + '\'' + '}'; } + + /** + * 重写 equals() — 两部电影 ID 相同则认为是同一部 + * equals 和 hashCode 必须配对重写 + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + Movie other = (Movie) obj; + return id != null && id.equals(other.id); + } + + /** + * 重写 hashCode() — 与 equals() 保持一致,基于 id 计算 + */ + @Override + public int hashCode() { + return id != null ? id.hashCode() : 0; + } } diff --git a/project/target/classes/com/movieratings/model/Movie.class b/project/target/classes/com/movieratings/model/Movie.class index b0953aec9574d740a74258342c26ab075910c3f9..80fcc64143496e1aad9e6de4aea563c4ede1de40 100644 GIT binary patch delta 572 zcmYjMOHUI~7(HL-$yiE+m`Dt0>LbuGA#PwnBqVHDfX3*`-7Su7%Ft=)l!t&-@Btz! znU#rgBXcFSqQ*j1E{t8zmx6_Oa`d(b1LZU#R0M7zh-X4oqj+Fsv`gI?PI_2I z?0~nK|BL3Lav_aHgaRYVmjwM?@91(x+X$>EE(Xhj-kY&nSe#dtTPhz0v@EJxaVEMG z=;a$}tm8)V&RVk{;faICN!Iq|X>!eeYwoysmi)4}O3q54{jjV50j z$g=mtWDnrrE>5F>Arx_*lXJ)0aRC>}=!1F#D-a3>vC3fzYaE||>15uPtWlJuQ2!*H}G=$ delta 128 zcmeBHyQ#!=>ff$?3=9nB3=JE(=CDqVU@K!QW+-K6D4BePO`EZ768k)sA`XVi$&1)) z8EYmhaA+~sP4?zk$0)t|7spi&8y1Fapl&9H90pDx%@1Vd0_i*kMuz-ih608{Acq6U WDF@;ThAJSB3&^TwsAZ^UkOTns_8ijy diff --git a/project/项目流程文档.md b/project/项目流程文档.md new file mode 100644 index 0000000..2417805 --- /dev/null +++ b/project/项目流程文档.md @@ -0,0 +1,625 @@ +# 电影数据抓取与分析项目 - 流程文档 + +> 本文档面向 Java 初学者,详细说明项目的整体架构、数据流向和各模块职责。 + +--- + +## 1. 项目概述 + +### 1.1 项目目标 +从豆瓣电影 Top 250 抓取影片数据,进行清洗、存储和多维度统计分析,最终以 Web 界面和图表形式展示结果。 + +### 1.2 技术栈 + +| 技术 | 版本 | 用途 | +| --- | --- | --- | +| Java | 11 | 主要开发语言 | +| Spring Boot | 2.7.12 | Web 框架、依赖注入 | +| Spring Data JPA | - | 数据持久化 | +| H2 Database | - | 内存数据库 | +| Jsoup | 1.15.3 | HTML 解析与网页爬取 | +| JFreeChart | 1.5.3 | 图表生成 | +| Apache Commons Math | 3.6.1 | 统计计算(相关性分析) | +| Jackson | - | JSON 序列化 | +| Thymeleaf | - | Web 模板引擎 | +| Caffeine | - | 缓存 | + +### 1.3 两种运行模式 + +本项目支持两种独立的运行模式: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 运行模式选择 │ +├─────────────────────────────────────────────────────────────┤ +│ 模式一:独立控制台模式 (Main.java) │ +│ - 命令:mvn exec:java -Dexec.mainClass="com.movieratings.Main"│ +│ - 输出:控制台表格 + JSON 文件 + PNG 图表 │ +│ - 适用:数据分析演示、离线运行 │ +├─────────────────────────────────────────────────────────────┤ +│ 模式二:Spring Boot Web 模式 (MovieRatingsApplication.java) │ +│ - 命令:mvn spring-boot:run │ +│ - 输出:Web 界面 (http://localhost:8080) │ +│ - 适用:交互式查询、在线展示 │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 2. 系统架构 + +### 2.1 整体架构图 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 项目整体架构 │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ 豆瓣电影 │────▶│ MovieCrawler │────▶│ Movie │ │ +│ │ Top 250 │ │ (爬虫层) │ │ (模型层) │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ │ +│ ┌────────────────────┼────────────────────┐│ +│ ▼ ▼ ▼│ +│ ┌──────────────────┐ ┌───────────────┐ ┌──────────┐│ +│ │ DataAnalyzer │ │ MovieRepository│ │JSON/CSV ││ +│ │ (分析层) │ │ (持久化层) │ │ (导出) ││ +│ └──────────────────┘ └───────────────┘ └──────────┘│ +│ │ │ │ +│ ▼ ▼ │ +│ ┌──────────────────┐ ┌───────────────┐ │ +│ │ ResultDisplay │ │ MovieService │ │ +│ │ (展示层) │ │ (业务层) │ │ +│ └──────────────────┘ └───────────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌──────────────────┐ ┌───────────────┐ │ +│ │ PNG 图表 + 控制台 │ │DirectorController│ │ +│ │ (独立模式) │ │ (Web 控制器) │ │ +│ └──────────────────┘ └───────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌───────────────┐ │ +│ │ Thymeleaf │ │ +│ │ (Web 页面) │ │ +│ └───────────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### 2.2 包结构 + +``` +com.movieratings +├── Main.java # 独立模式入口 +├── MovieRatingsApplication.java # Spring Boot 入口 +├── DataInitializer.java # 启动时数据初始化 +│ +├── model/ # 数据模型层 +│ ├── Movie.java # 电影实体类 +│ └── DirectorStats.java # 导演统计 DTO +│ +├── crawler/ # 爬虫层 +│ └── MovieCrawler.java # 网页爬取与解析 +│ +├── analysis/ # 分析层 +│ └── DataAnalyzer.java # 数据统计分析 +│ +├── display/ # 展示层 +│ └── ResultDisplay.java # 控制台输出与图表生成 +│ +├── repository/ # 持久化层 +│ └── MovieRepository.java # JPA 数据访问接口 +│ +├── service/ # 业务逻辑层 +│ └── MovieService.java # 业务服务 +│ +└── controller/ # Web 控制层 + └── DirectorController.java # HTTP 请求处理 +``` + +--- + +## 3. 详细数据流程 + +### 3.1 模式一:独立控制台流程 + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ 独立模式执行流程 (Main.java) │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. 启动 │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────┐ │ +│ │ MovieCrawler.crawl(50) │ │ +│ │ ──────────────────────── │ │ +│ │ • 连接豆瓣 Top 250 页面 │ │ +│ │ • 解析 HTML (Jsoup) │ │ +│ │ • 提取:排名、标题、评分、年份、导演等 │ │ +│ │ • 返回 List │ │ +│ └──────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────┐ │ +│ │ DataAnalyzer (多维度分析) │ │ +│ │ ──────────────────── │ │ +│ │ • analyzeRatings() → 评分统计 │ │ +│ │ • countMoviesByRatingRange() → 评分分布 │ │ +│ │ • findMostReviewed() → 热门电影 │ │ +│ │ • analyzeYearRatingCorrelation() → 相关性│ │ +│ │ • getTopDirectors() → 导演排行 │ │ +│ └──────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────┐ │ +│ │ ResultDisplay (结果展示) │ │ +│ │ ────────────────── │ │ +│ │ • printMoviesTable() → 控制台表格 │ │ +│ │ • printDirectorRanking() → 导演排行榜 │ │ +│ │ • generateRatingChart() → 评分分布图 │ │ +│ │ • generateScatterPlot() → 年份评分散点图 │ │ +│ └──────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────┐ │ +│ │ 数据导出 │ │ +│ │ ──────── │ │ +│ │ • saveAsJson() → movies_data.json │ │ +│ │ • exportToCSV() → movies_analysis.csv │ │ +│ └──────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ 程序结束 │ +│ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### 3.2 模式二:Spring Boot Web 流程 + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ Spring Boot Web 模式执行流程 │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. 应用启动 │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────┐ │ +│ │ MovieRatingsApplication.main() │ │ +│ │ ──────────────────────────── │ │ +│ │ • 启动 Spring 容器 │ │ +│ │ • 初始化 H2 内存数据库 │ │ +│ │ • 配置 Caffeine 缓存 │ │ +│ └──────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────┐ │ +│ │ DataInitializer.run() (CommandLineRunner)│ │ +│ │ ────────────────────────────── │ │ +│ │ • 调用 MovieCrawler.crawl(100) │ │ +│ │ • 设置部分作品类型(电影/电视剧/纪录片) │ │ +│ │ • 调用 MovieService.refreshData() │ │ +│ └──────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────┐ │ +│ │ MovieService.refreshData() │ │ +│ │ ───────────────────── │ │ +│ │ • movieRepository.deleteAll() │ │ +│ │ • movieRepository.saveAll(movies) │ │ +│ │ • 清除缓存 │ │ +│ └──────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ 应用就绪,等待 HTTP 请求 │ +│ │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ 2. 用户请求处理 │ +│ │ +│ 浏览器访问 http://localhost:8080/directors │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────┐ │ +│ │ DirectorController.showDirectorRankings()│ │ +│ │ ──────────────────────────────── │ │ +│ │ • 接收参数:name, type, page, size │ │ +│ │ • 调用 MovieService.getDirectorRankings()│ │ +│ └──────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────┐ │ +│ │ MovieService.getDirectorRankings() │ │ +│ │ ──────────────────────────── │ │ +│ │ • 检查缓存 (Caffeine) │ │ +│ │ • 缓存未命中 → 调用 Repository │ │ +│ │ • 返回 Page │ │ +│ └──────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────┐ │ +│ │ MovieRepository.findDirectorRankings() │ │ +│ │ ──────────────────────────────── │ │ +│ │ • 执行 JPQL 聚合查询 │ │ +│ │ • GROUP BY director │ │ +│ │ • 返回导演统计数据 │ │ +│ └──────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────┐ │ +│ │ Thymeleaf 模板渲染 │ │ +│ │ ──────────────── │ │ +│ │ • director_rankings.html │ │ +│ │ • 返回 HTML 页面给浏览器 │ │ +│ └──────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 4. 核心模块详解 + +### 4.1 爬虫模块 (MovieCrawler) + +**职责**:从豆瓣电影 Top 250 抓取数据 + +**流程**: +``` +┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ +│ 构造请求URL │───▶│ 发送HTTP请求│───▶│ 解析HTML │───▶│ 封装Movie │ +│ (分页参数) │ │ (Jsoup) │ │ (CSS选择器)│ │ 对象列表 │ +└────────────┘ └────────────┘ └────────────┘ └────────────┘ +``` + +**关键代码**: +```java +// 发送请求 +Document doc = Jsoup.connect(url).userAgent(USER_AGENT).get(); + +// 解析数据 +movie.setRank(Integer.parseInt(item.select(".pic em").text())); +movie.setTitle(item.select(".title").first().text()); +movie.setRating(Double.parseDouble(item.select(".rating_num").text())); +``` + +**数据提取字段**: +| 字段 | 提取方式 | +| --- | --- | +| 排名 | `.pic em` | +| 标题 | `.title` | +| 评分 | `.rating_num` | +| 海报 | `.pic img` 的 src 属性 | +| 年份 | 正则匹配 `\d{4}` | +| 导演 | 文本中提取 `导演: xxx` | +| 国家 | 按 `/` 分割取倒数第二项 | +| 评价人数 | 正则匹配 `([\d,]+)人评价` | + +--- + +### 4.2 数据模型 (Movie) + +**职责**:定义电影数据的结构,使用 JPA 注解映射到数据库 + +**类图**: +``` +┌─────────────────────────────────────────┐ +│ Movie │ +├─────────────────────────────────────────┤ +│ - id: Long (主键, 自增) │ +│ - title: String (标题) │ +│ - rating: double (评分) │ +│ - releaseYear: int (年份) │ +│ - rank: int (排名) │ +│ - quote: String (简评) │ +│ - director: String (导演) │ +│ - reviewCount: int (评价人数) │ +│ - country: String (国家) │ +│ - boxOffice: double (票房) │ +│ - type: String (类型) │ +│ - posterUrl: String (海报链接) │ +├─────────────────────────────────────────┤ +│ + getter/setter 方法 │ +│ + toString(): String │ +│ + equals(Object): boolean │ +│ + hashCode(): int │ +└─────────────────────────────────────────┘ +``` + +**JPA 注解说明**: +- `@Entity` — 标记为数据库实体 +- `@Table(name = "movies")` — 指定表名 +- `@Id` + `@GeneratedValue` — 主键自增策略 + +--- + +### 4.3 数据分析模块 (DataAnalyzer) + +**职责**:对电影数据进行多维度统计分析 + +**分析方法**: + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ DataAnalyzer 方法 │ +├──────────────────────────────────────────────────────────────────┤ +│ │ +│ analyzeRatings(List) │ +│ └──▶ 返回 DoubleSummaryStatistics (平均值、最大值、最小值、计数) │ +│ │ +│ countMoviesByRatingRange(List) │ +│ └──▶ 返回 Map (评分段 → 电影数量) │ +│ 评分段: 9.5-10.0, 9.0-9.4, 8.5-8.9, 8.5以下 │ +│ │ +│ findMostReviewed(List, int n) │ +│ └──▶ 返回评价人数最多的前 N 部电影 │ +│ │ +│ analyzeYearRatingCorrelation(List) │ +│ └──▶ 返回 CorrelationResult (Pearson 相关系数 + 显著性检验) │ +│ │ +│ getTopDirectors(List, int topN) │ +│ └──▶ 返回 List (按作品数排序的导演排行) │ +│ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +**内部类**: +- `DirectorStats` — 导演统计结果(姓名、作品数、平均分、总票房) +- `CorrelationResult` — 相关性分析结果(系数、p 值、显著性描述) + +--- + +### 4.4 数据持久化层 + +**MovieRepository 接口**: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ MovieRepository │ +│ extends JpaRepository │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 继承自 JpaRepository 的方法: │ +│ • save(Movie), saveAll(List) │ +│ • deleteAll(), deleteById(Long) │ +│ • findById(Long), findAll() │ +│ │ +│ 自定义方法: │ +│ • findDirectorRankings(name, type, pageable) │ +│ └── JPQL 聚合查询,返回导演排行榜 │ +│ • findByDirector(String director) │ +│ └── 按导演名查询作品列表 │ +│ • findAllTypes() │ +│ └── 查询所有不同的作品类型 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**JPQL 聚合查询示例**: +```java +@Query("SELECT new com.movieratings.model.DirectorStats(" + + "m.director, COUNT(m), MAX(m.posterUrl), AVG(m.rating), SUM(m.boxOffice)) " + + "FROM Movie m " + + "WHERE (:name IS NULL OR m.director LIKE %:name%) " + + "GROUP BY m.director " + + "ORDER BY COUNT(m) DESC") +Page findDirectorRankings(...); +``` + +--- + +### 4.5 业务服务层 (MovieService) + +**职责**:封装业务逻辑,管理缓存和事务 + +**方法说明**: + +| 方法 | 功能 | 缓存策略 | +| --- | --- | --- | +| `getDirectorRankings()` | 获取导演排行榜 | `@Cacheable` 缓存 10 分钟 | +| `getAllTypes()` | 获取所有作品类型 | `@Cacheable` 缓存 | +| `saveAll()` | 批量保存电影 | `@CacheEvict` 清除缓存 | +| `refreshData()` | 清空并重新加载数据 | `@CacheEvict` 清除缓存 | + +--- + +### 4.6 Web 控制层 (DirectorController) + +**职责**:处理 HTTP 请求,返回 Web 页面 + +**路由映射**: + +| URL | 方法 | 功能 | +| --- | --- | --- | +| `GET /` | `index()` | 重定向到导演排行 | +| `GET /directors` | `showDirectorRankings()` | 导演排行榜页面 | +| `GET /director/{name}` | `showDirectorMovies()` | 指定导演的作品列表 | + +**请求参数**: +``` +GET /directors?name=张艺谋&type=电影&page=0&size=20 +``` + +--- + +## 5. 数据流图 + +### 5.1 数据抓取流程 + +``` +豆瓣服务器 本地应用 + │ │ + │ 1. HTTP GET 请求 │ + │◀──────────────────────────│ + │ │ + │ 2. HTML 响应 │ + │──────────────────────────▶│ + │ │ + │ ┌────┴────┐ + │ │ Jsoup │ + │ │ 解析 │ + │ └────┬────┘ + │ │ + │ ┌────┴────┐ + │ │ Movie │ + │ │ 对象 │ + │ └────┬────┘ + │ │ + │ 存入 List +``` + +### 5.2 Web 请求处理流程 + +``` +浏览器 服务器 + │ │ + │ GET /directors │ + │──────────────────────────▶│ + │ ┌────┴────┐ + │ │Controller│ + │ └────┬────┘ + │ │ + │ ┌────┴────┐ + │ │ Service │ + │ │ (检查缓存)│ + │ └────┬────┘ + │ │ + │ ┌────┴────┐ + │ │Repository│ + │ │ (查询DB) │ + │ └────┬────┘ + │ │ + │ ┌────┴────┐ + │ │Thymeleaf│ + │ │ 渲染 │ + │ └────┬────┘ + │ │ + │ HTML 响应 │ + │◀──────────────────────────│ +``` + +--- + +## 6. 配置说明 + +### 6.1 数据库配置 (application.properties) + +```properties +# H2 内存数据库 +spring.datasource.url=jdbc:h2:mem:moviedb;DB_CLOSE_DELAY=-1 +spring.h2.console.enabled=true # 启用 H2 控制台 + +# JPA 配置 +spring.jpa.hibernate.ddl-auto=update # 自动创建表结构 +``` + +### 6.2 缓存配置 + +```properties +spring.cache.type=caffeine +spring.cache.cache-names=directorRankings,movieTypes +spring.cache.caffeine.spec=expireAfterWrite=10m,maximumSize=100 +``` + +- 缓存 10 分钟后过期 +- 最大缓存 100 条记录 + +--- + +## 7. 运行指南 + +### 7.1 环境要求 + +- JDK 11+ +- Maven 3.6+ + +### 7.2 运行命令 + +**独立控制台模式**: +```bash +mvn clean compile exec:java -Dexec.mainClass="com.movieratings.Main" +``` + +**Spring Boot Web 模式**: +```bash +mvn spring-boot:run +``` + +### 7.3 访问地址 + +| 功能 | 地址 | +| --- | --- | +| 导演排行榜 | http://localhost:8080/directors | +| H2 数据库控制台 | http://localhost:8080/h2-console | +| JDBC URL | `jdbc:h2:mem:moviedb` | + +--- + +## 8. 输出文件说明 + +### 8.1 独立模式输出 + +| 文件 | 说明 | +| --- | --- | +| `movies_data.json` | 完整的电影数据 JSON | +| `movies_analysis.csv` | 电影数据 CSV 表格 | +| `rating_distribution.png` | 评分分布柱状图 | +| `year_rating_scatter.png` | 年份-评分散点图 | + +### 8.2 控制台输出示例 + +``` +=== 电影数据抓取与分析项目开始 === +正在抓取: https://movie.douban.com/top250?start=0&filter= +... + +--- 电影抓取结果展示 (前 10 条展示) --- +-------------------------------------------------------------------------------------------------- +| 排名 | 标题 | 年份 | 评分 | 导演 | 评价人数 | +-------------------------------------------------------------------------------------------------- +| 1 | 肖申克的救赎 | 1994 | 9.7 | 弗兰克·德拉邦特 | 2900000 | +| 2 | 霸王别姬 | 1993 | 9.6 | 陈凯歌 | 1900000 | +... + +--- 基础统计分析报告 --- +总计分析电影数量: 50 +平均评分: 8.92 +最高评分: 9.70 +最低评分: 8.50 + +--- 导演作品排行榜 (前 20) --- +------------------------------------------------------------------ +| 导演 | 作品数 | 平均分 | 总模拟票房 | +------------------------------------------------------------------ +| 克里斯托弗·诺兰 | 7 | 8.9 | 1250000.00 | +| 斯蒂芬·斯皮尔伯格 | 6 | 8.7 | 980000.00 | +... + +=== 项目执行完毕 === +``` + +--- + +## 9. 扩展阅读 + +### 9.1 相关文档 + +- `OOP_封装_继承_多态.md` — 项目中的面向对象概念详解 +- `README.md` — 项目基本信息 +- `DEVELOPMENT.md` — 开发日志 + +### 9.2 学习要点 + +1. **爬虫技术**:Jsoup 的使用、HTTP 请求、HTML 解析 +2. **数据持久化**:JPA 实体映射、Repository 模式 +3. **业务分层**:Controller → Service → Repository 架构 +4. **缓存机制**:Caffeine 缓存的使用场景 +5. **数据分析**:Stream API、统计计算、相关性分析 +6. **可视化**:JFreeChart 图表生成 + +--- + +*文档版本:1.0* +*更新日期:2026-04-09* diff --git a/w5/README.md b/w5/README.md new file mode 100644 index 0000000..1635a07 --- /dev/null +++ b/w5/README.md @@ -0,0 +1,72 @@ +# Java程序设计 第5周作业 + +## 一、作业内容 + +本周作业主要练习Java中的**抽象类**和**继承**,通过两个实例理解面向对象程序设计中多态的应用。 + +## 二、项目结构 + +``` +w5/ +├── shape/ # 图形绘制示例 +│ ├── Shape.java # 抽象父类 +│ ├── Circle.java # 圆形子类 +│ ├── Rectangle.java # 矩形子类 +│ └── Main.java # 测试类 +├── vehicle/ # 交通工具示例 +│ ├── Vehicle.java # 抽象父类 +│ ├── Car.java # 汽车子类 +│ ├── Bike.java # 自行车子类 +│ ├── Truck.java # 卡车子类 +│ └── Main.java # 测试类 +└── README.md # 说明文档 +``` + +## 三、知识点总结 + +### 1. 抽象类 +- 使用`abstract`关键字修饰的类称为抽象类 +- 抽象类不能被实例化 +- 抽象类可以包含抽象方法和具体方法 +- 抽象方法只有声明,没有实现 + +### 2. 继承 +- 使用`extends`关键字实现继承 +- 子类继承父类的属性和方法 +- 子类必须实现父类的所有抽象方法(除非子类也是抽象类) + +### 3. 多态 +- 父类引用可以指向子类对象(向上转型) +- 运行时根据实际对象类型调用相应的方法 + +## 四、运行方法 + +### shape包: +```bash +cd w5 +javac shape/*.java +java shape.Main +``` + +### vehicle包: +```bash +cd w5 +javac vehicle/*.java +java vehicle.Main +``` + +## 五、运行结果 + +详见`输出结果.txt`文件。 + +## 六、心得体会 + +1. 抽象类为子类提供了一个公共的模板,定义了子类必须实现的方法。 + +2. 通过继承可以复用代码,减少重复。 + +3. 多态使得程序更加灵活,可以用统一的接口操作不同的对象。 + +--- +作者:[学生姓名] +日期:2026年4月 diff --git a/w5/shape.png b/w5/shape.png new file mode 100644 index 0000000000000000000000000000000000000000..c89cb4b14923a07783ccc3c2a0e2c138d5242a89 GIT binary patch literal 13005 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
hfA#;=`}mFr(b+D!CO>PEft_P7 z*7;t<$gL3rr6BLmEf2m7Y@^w#F^}m2m3e(cM`!vPi>J$G_F}{X?p>FN{$6n*rEbuJF z(W=Q4{$$d-UdO$9!XwMBwRcx0f0cFC>*}YarPR2NTJAf!PQDAqT0ljS!- zWeJLCT{wT9k-TX{7Qj$=v)Kbgs&yyB%^6m&{q zptzeFB^6RkAH-Ml&UV(nr2Z~}fx!lGDcbB81-#WVTES9JpIJ}3n3J=z%-?3${@BeBn8nM% z?W=N@(ze0BRb{mQ%3rEqx;Cs9(3BKG2h1i+U+GLvd+_N>b5J(J{57>J>V8Kv)vz@e zZq$3&E6@#6m3N$M(59YOoK%#vPzBO3My?HKPjlf=L-jeQc0^$(e~echi?rbaVMRPN z*L|rM*f|fu$_*R}z)v7UQXVdC&hEgsXHen|&Acw+ye*d+kcJS$(E~Z(J@h9Um*Yu% z51r&9Qg+OHOO4sr+u8i421=dTw^| zq*0pcY2DDL;X&gK=c260lHy8qk0Jj#4|cL$^Q;lXeS<|kMw-ouw?%DC3iBLd%*YG& zS|Q476joyq0Cfwqz4vK>OB(~#NE)w&#WJ6s&Rp%K52INX^n$bf`*u51mryN$c65~i zU}4teV71*}Y<$dcHvctc66ce`Z_=|I=kKt)_bRKnBhVr5p*m@8qjoh->Q7QGUy;v` zt?3~q81*}AE32vp=~rpZzrl`wV~!dL%yY*-$Am`GWtQ^4b>&I*CHT6U6t_7;LXU{% zO#e2tij3CdHi@LKmf6zzo3dF{R>gRARzLl=en!2UJbwJ$ptSyYzMLBUK*+Hy6> zk>NW9$Ip=iCWF@sx$o-}(~llhPKA{)L+&t|G}%$IcK*};+H;6P_q#Fp39o)#n24T2 z&MVT<^}~02>6*9#JoRttoTNt)Zxa7&Y+k4AYY;Jq;L7#Mn!mLr)FPoIxT*%Q)H#5jH=*p;)x3)0Uq+QINi^t}cB{8ZmQKm3Z{Fx+j;SM) zOUSonvn%A<`SG)K;mfUYIdZq(?$hZi^zumSKp(=ZFg08@;thIi-p=d%km_4n&ANp^ zxy~@YZf#Y$m3vbfOk}I?X}XNhE6#k8GEk)(z)IsHnOoWpWnY4I_aVlh5#Z(UWrocx z&+5l2-;9y+qak>QXxG|hBB4+d8*^g zBVX4vbMPyV7i__!F;j(AuEo_93S>Z#49yWWj{reyS;Ujdg!m*!n}A-~DcA-3t`IF& z!6q09*YfPXa^3H&=IZuS-^X?bR$lvG#oO+6^nA1s_J|U%cmFSrVvVA-rs$_c^LlS2 zv~@^blZk*5bOTC&{47qJr}V}HBvGJeN`vv?& zpGKU;HGB$|Mf&wH8K7fxx z?Aa1DT(P^iJ2ShQukVjf0GBxMV4&f^^kKm!SmB*mNrHW*QdOK28pF}dMH8+A&qoVB zp>r=DMUaRz4#MY$LM|DVl?9b*EZpKZ|30DAzN<2L^eITL5=BNhkXi;!WLQ*QHX7>>7_6F)d;xbO213&5*un;5)9^J^0yLO zn!Cj;Gu5Nc3Rcek<8k*nSxP+05SFnS$fU;AndFlpOy%c6%=7OJpIJx8QpbyOdUYtCR{|s O+f?v?b|T2~1f4&o=Q~jV literal 0 HcmV?d00001 diff --git a/w5/shape/Main.java b/w5/shape/Main.java new file mode 100644 index 0000000..4e29359 --- /dev/null +++ b/w5/shape/Main.java @@ -0,0 +1,8 @@ +public class Main { + public static void main(String[] args) { + Shape circle = new Circle(); + Shape rectangle = new Rectangle(); + circle.draw(); + rectangle.draw(); + } +} diff --git a/w5/shape/Rectangle.class b/w5/shape/Rectangle.class new file mode 100644 index 0000000000000000000000000000000000000000..63a2d6ecc036bef21ae4996a7cfbea68a4c1f0ea GIT binary patch literal 395 zcmZut%T5A85UhrMu5351M%J1Nb-^hVzK6SJm`;HY!JMgUrmB_mQVQujiJiqRhf=uaVy3N zcdRKtf#64ZSxn@mGQIkecx<-g03G(joC??sI2#%sW0H*Kcua9zRf56uKku>b%7 literal 0 HcmV?d00001 diff --git a/w5/shape/Rectangle.java b/w5/shape/Rectangle.java new file mode 100644 index 0000000..c5f6f06 --- /dev/null +++ b/w5/shape/Rectangle.java @@ -0,0 +1,6 @@ +public class Rectangle extends Shape { + @Override + public void draw() { + System.out.println("Drawing a rectangle"); + } +} diff --git a/w5/shape/Shape.class b/w5/shape/Shape.class new file mode 100644 index 0000000000000000000000000000000000000000..43358a0667989585010b5ddd2cc75a562576e450 GIT binary patch literal 199 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 YuMpkkH?;r8jk|!u?zv3a;@raa4;TMO-~a#s literal 0 HcmV?d00001 diff --git a/w5/vehicle/Bike.java b/w5/vehicle/Bike.java new file mode 100644 index 0000000..5bb1c5f --- /dev/null +++ b/w5/vehicle/Bike.java @@ -0,0 +1,6 @@ +public class Bike extends Vehicle { + @Override + public void run() { + System.out.println("Running a bike"); + } +} diff --git a/w5/vehicle/Car.class b/w5/vehicle/Car.class new file mode 100644 index 0000000000000000000000000000000000000000..6a31bb3be97e686e5070351796e0d6a48bc34019 GIT binary patch literal 378 zcmZut%TB{U3>+tE^B|?ArM!{K0jcFcKA?z81*Zxjf^y%MRan$+swF|yVF6_bf+8&QRU*8{}04{J4!GY_;i%~X{~hL6TPW05n9;r z(T>rVk#%97LhaFF@fV&ai71aDN_@zTw)((o zm&lSd{YXK=QP@CEVl#&=YnFZeZi1<%B1%Guf`I#ACR!nHckBqHdr=Zh6pA)4v)%Sh zNNCQ7bmdzn)SYBD&{5AH*g5WO)i2lHTI-8-b>~SG=qF>vo*i~$bvVT? z-(^n<+=>k29$OB`Nd?Sz#xE)Y0mKZT=zp@|DWz>hNC zfkZdX;y%wg_s;$L{`drNj{O)ODj})~d<2AWB5&0!lZ4ZdkM4AabPe;#>M&^tvtRb|Ai;gPNt5Rt*GNlyxpoTR<{n~1+^t>ZFrnIyB7!9n4 zXeMZ3gV6ei$m={fnM|{CZz;VTYPdWf^d})U3I5pW5vpg!4KH3FDlIQJRFO)0A3(m0{iZ0rG1ou3!8UnUkoE@+y_Wsd3=!FBqHe1(rF=6Kydbpqh Z(JR8{>Kp2RaCcy!$_MnBvdgiDy&v9mNsRyi literal 0 HcmV?d00001 diff --git a/w5/vehicle/Truck.java b/w5/vehicle/Truck.java new file mode 100644 index 0000000..8ab43f1 --- /dev/null +++ b/w5/vehicle/Truck.java @@ -0,0 +1,6 @@ +public class Truck extends Vehicle { + @Override + public void run() { + System.out.println("Running a truck"); + } +} diff --git a/w5/vehicle/Vehicle.class b/w5/vehicle/Vehicle.class new file mode 100644 index 0000000000000000000000000000000000000000..37d3e5077861013f76ef8079114cbf4cf40b408f GIT binary patch literal 202 zcmXXxpuH-vC$tZ7yRe>zJgIs}>OtI11E5bNs9 zG~5}h_w6my^+{ze@axtRqGQ$8x!xLQ#s8~?s}K`NZg%5=TsLEvw=pv@2lFTB!Ggaq Qx|p>f^jJGLX7tei0Z+LjBLDyZ literal 0 HcmV?d00001 diff --git a/w5/vehicle/Vehicle.java b/w5/vehicle/Vehicle.java new file mode 100644 index 0000000..ecef84f --- /dev/null +++ b/w5/vehicle/Vehicle.java @@ -0,0 +1,3 @@ +public abstract class Vehicle { + public abstract void run(); +} diff --git a/w6/Animal.class b/w6/Animal.class new file mode 100644 index 0000000000000000000000000000000000000000..b05489d14c245388ee868cbcef0faa28fc91506e GIT binary patch literal 206 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 literal 0 HcmV?d00001 diff --git a/w6/Cat.java b/w6/Cat.java new file mode 100644 index 0000000..ab22387 --- /dev/null +++ b/w6/Cat.java @@ -0,0 +1,6 @@ +public class Cat extends Animal { + @Override + public void makeSound() { + System.out.println("Meow!"); + } +} diff --git a/w6/Dog.class b/w6/Dog.class new file mode 100644 index 0000000000000000000000000000000000000000..867983a12cb0399623f7e78be6ad0d1ca5e68fc8 GIT binary patch literal 476 zcmZuu%TB^j5IrN5+tw<`!}p^sOu&VF0LH}lSP^4Vg6ksJdbRB}rD*&tU1;LM5AdUm zb0NkJn|YpdW-{~r^Z5nf98DJsCF00mkFcvBqua_(~i=et4yVNkY_SXx;B;x*0t8RJgtHifvSfZ>V(=H zI6*uba-6bWYbH1wm2)}jwg)y=3HAP+^hY}K)z}|Dt0duGQ(&D}In$BACcz0zJsif8 zP(0NmcIBQ*<>e$9%B(+YI7#>*13gJc3^GClm(%PlcEO~3%D zqC(_0OMJLIw?o-L7CwB~T&f1Bv5%L^xf*3lGi9mD(tdygmYlZ_ow_(AHk8^B46>;b zs72bS$7LF;{8`2esyOMt-srwY+h>i6T$|*oHx}^ef_$RxH8*=~cFBD>MV+?dV?pp< z6dROv2nAv3Yz^^AMBs=b%gjAAaZJdq5Bx2JoekWVHN0p8pD-AnudsWuLP)r`wP=wE XXrKZIA@Mrx+a$v_Eicd_&BDnaPEtDV literal 0 HcmV?d00001 diff --git a/w6/Main.java b/w6/Main.java new file mode 100644 index 0000000..593fe29 --- /dev/null +++ b/w6/Main.java @@ -0,0 +1,11 @@ +public class Main { + public static void main(String[] args) { + Dog dog = new Dog(); + Cat cat = new Cat(); + + dog.makeSound(); // Output: Woof! + cat.makeSound(); // Output: Meow! + + dog.swim(); // Output: The dog is swimming! + } +} diff --git a/w6/README.md b/w6/README.md new file mode 100644 index 0000000..a832a64 --- /dev/null +++ b/w6/README.md @@ -0,0 +1,75 @@ +# Java程序设计 第6周作业 + +## 一、作业内容 + +本周作业主要练习Java中的**接口(Interface)**,理解接口与抽象类的区别,以及类同时继承抽象类和实现接口的用法。 + +## 二、项目结构 + +``` +w6/ +├── Animal.java # 抽象父类 - 动物 +├── Swimmable.java # 接口 - 可游泳 +├── Dog.java # 狗类(继承Animal,实现Swimmable) +├── Cat.java # 猫类(继承Animal) +├── Main.java # 测试类 +└── README.md # 说明文档 +``` + +## 三、知识点总结 + +### 1. 抽象类 +- 使用`abstract`关键字修饰 +- 可以包含抽象方法和具体方法 +- 不能被实例化 +- 子类使用`extends`继承 + +### 2. 接口 +- 使用`interface`关键字定义 +- 接口中的方法默认为`public abstract` +- 类使用`implements`实现接口 +- 一个类可以实现多个接口 + +### 3. 接口与抽象类的区别 + +| 特性 | 抽象类 | 接口 | +|------|--------|------| +| 关键字 | abstract | interface | +| 继承/实现 | extends | implements | +| 多继承 | 单继承 | 可实现多个 | +| 方法 | 可有具体方法 | 默认抽象方法 | +| 变量 | 可有成员变量 | 只能是常量 | + +### 4. 本项目设计思路 +- `Animal`抽象类:定义所有动物的共性(发出声音) +- `Swimmable`接口:定义会游泳的能力 +- `Dog`类:继承Animal,同时实现Swimmable接口(狗会游泳) +- `Cat`类:只继承Animal(猫不会游泳) + +## 四、运行方法 + +```bash +cd w6 +javac *.java +java Main +``` + +## 五、运行结果 + +``` +Woof! +Meow! +The dog is swimming! +``` + +## 六、心得体会 + +1. 接口定义了一组行为规范,实现接口的类必须提供具体实现。 + +2. Java不支持多继承,但一个类可以实现多个接口,弥补了单继承的局限性。 + +3. 通过接口可以实现"行为"的抽象,如Swimmable表示"会游泳"这个能力,任何类都可以实现这个接口。 + +--- +作者:[学生姓名] +日期:2026年4月 diff --git a/w6/Swimmable.class b/w6/Swimmable.class new file mode 100644 index 0000000000000000000000000000000000000000..56507729f3da7ea2cb9d3c0e836ebda27478beff GIT binary patch literal 120 zcmX^0Z`VEs1_oCKPId++Mh4E{^32@a#H5^5b_Nzk27#=^vPAuy#JqHU|D>$c