+
는 피연산자가 모두 정수일 땐 정수 덧셈 연산자, 문자열일 땐 연결 연산자로 동작한다.List<T>
Pass:3 Fail:2, A:1 B:1 C:1 D:0 F:2
Lecture
클래스가 존재하는 상황
Pass:3 Fail 2
public 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
를 상속한 GradeLecture
Lecture
의 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
부터이기 때문