+는 피연산자가 모두 정수일 땐 정수 덧셈 연산자, 문자열일 땐 연결 연산자로 동작한다.List<T>Pass:3 Fail:2, A:1 B:1 C:1 D:0 F:2Lecture 클래스가 존재하는 상황
Pass:3 Fail 2public class Lecture {
private int pass; // 이수 여부 판단할 기준 점수
private String title; // 강의 제목
private List<Integer> scores = new ArrayList<>(); // 학생들의 성적
public Lecture(String title, int pass, List<Integer> scores) {
this.title = title;
this.pass = pass;
this.scores = scores;
}
public double average() {
return scores.stream().mapToInt(Integer::intValue).average().orElse(0);
}
public String evaluate() {
return String.format("Pass:%d Fail:%d", passCount(), failCount());
}
// ...
}
Lecture를 상속한 GradeLectureLecture의 evaluate를 오버라이딩하여 추가된 기능을 구현할 수 있다.public class GradeLecture extends Lecture {
private List<Grade> grades;
public GradeLecture(String name, int pass, List<Grade> grades, List<Integer> scores) {
super(name, pass, scores);
this.grades = grades;
}
@Override
public String evaluate() {
return super.evaluate() + ", " + gradesStatistics();
}
private String gradesStatistics() {
return grades.stream().map(grade -> format(grade)).collect(joining(" "));
}
private String format(Grade grade) {
return String.format("%s:%d", grade.getName(), gradeCount(grade));
}
private long gradeCount(Grade grade) {
return getScores().stream().filter(grade::include).count();
}
public double average(String gradeName) {
return grades.stream()
.filter(each -> each.isName(gradeName))
.findFirst()
.map(this::gradeAverage)
.orElse(0d);
}
private double gradeAverage(Grade grade) {
return getScores().stream()
.filter(grade::include)
.mapToInt(Integer::intValue)
.average()
.orElse(0);
}
}
Lecture 인스턴스 생성 후의 메모리 상태
Lecture 클래스는 하나만 할당되고 인스턴트들이 class라는 이름의 포인터로 이에 접근Lecture 클래스는 parent라는 이름의 포인터로 Object에 접근Professor의 compileStatistics 메서드로 통계 정보를 생성한다.
Lecture의 evaluate와 average 메서드를 호출public class Professor {
private String name;
private Lecture lecture;
public Professor(String name, Lecture lecture) {
this.name = name;
this.lecture = lecture;
}
public String compileStatistics() {
return String.format("[%s] %s - Avg: %.1f", name,
lecture.evaluate(), lecture.average());
}
}
Professor가 Lecture를 생성자로 받기에 GradeLecture를 전달 받아도 기능 수행에는 문제가 없다.Professor professor = new Professor("다익스트라",
new Lecture("알고리즘",
70,
List.of(81, 95, 75, 50, 45)));
String statistics = professor.compileStatistics();
// [다익스트라] Pass:3 Fail:2 - AVG: 69.2
Professor professor = new Professor("다익스트라",
new GradeLecture("알고리즘",
70,
List.of(new Grade("A", 100, 95), ...),
List.of(81, 95, 75, 50, 45)));
String statistics = professor.compileStatistics();
// [다익스트라] Pass:3 Fail:2, A:1 B:1 C:1 D:1 F:1 - AVG: 69.2
Lecture lecture = new GradeLecture(…)GradeLecture gradeLecture = (GradeLecture)lecture;public class Lecture {
public String stats() {
return String.format("ㅅTitle: %s, Evaluation Method: %s", title, getEvaluationMethod());
}
public String getEvaluationMethod() {
return "Pass or Fail";
}
}
stats() 메서드는 자신의 getEvaluationMethod()를 호출하고 있다.
getEvaluationMethod 메시지를 전송하는 것public class GradeLecture extends Lecture {
@Override
public String getEvaluationMethod() {
return "Grade";
}
}
GradeLecture가 getEvaluationMethod를 오버라이드하면 self 참조에 따라 GradeLecture로 생성한 인스턴스는 바로 위 메서드가 실행되게 된다.
GradeLecture부터이기 때문