해결된 질문
작성
·
357
0
public class _Quiz_09 {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student("유재석","파이썬"));
list.add(new Student("박명수","자바"));
list.add(new Student("김종국","자바"));
list.add(new Student("조세호","C"));
list.add(new Student("서장훈","파이썬"));
System.out.println("자바 자격증을 보유한 학생");
System.out.println("========================");
for (Student student : list) {
if (student.getCertification() == "자바"){
System.out.println(student.getName());
}
}
}
}
class Student{
private String name;
private String certification;
public Student(String name, String certification) {
this.name = name;
this.certification = certification;
}
public String getName() {
return name;
}
public String getCertification() {
return certification;
}
}
저는 Student 클래스를 생성할 때 getter를 만들어서 getter로 자바 자격증을 찾는 로직을 짯는데
equals()와 getter를 비교했을때 어느 방법이 성능면이나 이점이 있는지 알 수 있을까요 ?
답변 1
1
안녕하세요?
먼저 퀴즈를 훌륭하게 잘 풀어주셨습니다. 현재 상태로 수행을 하면 원하는 결과도 잘 출력이 되고 있지요. 그런데 한 가지 문제가 있습니다. 바로 == 연산자인데요.
퀴즈 해설에서 제공해드린 아래 코드와 비교해서 getter 를 쓰신 것은 아주 잘 하셨습니다. certification 인스턴스 변수를 직접 접근하는 것보다는 getter 또는 setter 로 접근하는 것이 권장되니까요.
if (student.certification.equals("자바")) {
...
}
하지만 다음과 같이 했을 때 경우에 따라 올바로 동작하지 않을 수도 있습니다.
if (student.getCertification() == "자바"){
...
}
자바에서 특히 문자열 비교를 할 때 == 연산자와 equals() 메소드를 주의해서 써야 하는데요. == 연산자는 해당 문자열이 위치하고 있는 메모리 주소가 같은지를 비교하는 것입니다. 반면에 equals() 메소드는 값(예: 자바)이 동일한지를 비교하는 거예요.
작성해주신 코드의 경우 "자바" 라는 문자열이 한 곳에 저장되어 있기 때문에 == 을 써도 true 라는 결과를 얻을 수 있게 됩니다. 제가 예시를 조금 간단하게 바꿔볼게요.
String s1 = "자바";
String s2 = "자바";
if (s1 == s2) { // true
...
}
if (s1.equals(s1)) { // true
...
}
위 경우 두 if 문 모두 true 가 나오게 됩니다. s1 과 s2 는 "자바" 라는 문자열이 존재하는 메모리 공간을 동일하게 가리키기 때문이에요. "자바" 는 값이 같기 때문에 굳이 다른 메모리 공간에 둘 필요가 없지요. 하지만 코드를 다음과 같이 바꾸면 어떻게 될까요?
String s1 = new String("자바");
String s2 = new String("자바");
if (s1 == s2) { // false
...
}
if (s1.equals(s1)) { // true
...
}
이번에는 == 연산자를 비교했을 때는 false 라는 결과가 나오게 됩니다. 우리가 명시적으로 new String() 을 통해 문자열을 만들게 되면 비록 문자열의 값이 같더라도 서로 다른 공간에 값이 저장되거든요.
일반적으로는
String s1 = new String("자바");
보다는
String s1 = "자바";
와 방식으로 문자열을 정의하기 때문에 == 를 써도 크게 문제가 되지 않는 것처럼 보일 수가 있습니다.
하지만 문자열은 다양하게 다뤄질 수 있어요.
가령 제가 예시를 다음과 같이 바꿔볼게요.
이번에는 프로그래밍 언어 이름 뒤에 "몇 급" 이라고 하는 급수도 추가가 되었습니다.
List<Student> list = new ArrayList<>();
list.add(new Student("유재석","파이썬 1급"));
list.add(new Student("박명수","자바 2급"));
list.add(new Student("김종국","자바 2급"));
list.add(new Student("조세호","C 2급"));
list.add(new Student("서장훈","파이썬 2급"));
그러면 "자바" 자격증을 보유한 학생을 찾기 위해서 "몇 급" 정보 부분을 제외하고 비교를 해야겠죠?
이때는 substring 을 이용해서 이렇게 할 수 있습니다.
먼저 질문자께서 작성하신 코드 기준으로 수정을 해보면 이렇게 되겠네요.
System.out.println("자바 자격증을 보유한 학생");
System.out.println("========================");
for (Student student : list) {
String cert = student.getCertification();
// 0 위치로부터 (문자열의 길이 - 3) 직전까지를 잘라내기
// 예: "자바 2급" -> "자바"
cert = cert.substring(0, cert.length() - 3);
if (cert == "자바"){
System.out.println(student.getName());
}
}
실행 결과는 어떻게 될까요?
(실행 결과)
자바 자격증을 보유한 학생
========================
분명 자바 자격증을 가진 학생은 2명이 있지만 결과가 올바로 출력되지 않았습니다.
== 연산자는 메모리 주소가 같은지를 비교한다고 했는데 우리가 비교하려는 "자바" 라는 문자열, 그리고 학생이 보유한 자격증 정보가 저장된 문자열인 "자바 2급" 을 "자바" 로 바꾸었을 때의 메모리 주소가 달라서 그런 것이죠.
코드를 이렇게 바꿔볼게요.
System.out.println("자바 자격증을 보유한 학생");
System.out.println("========================");
for (Student student : list) {
String cert = student.getCertification();
cert = cert.substring(0, cert.length() - 3);
if (cert.equals("자바")){ // 수정된 부분
System.out.println(student.getName());
}
}
이번에는 == 를 equals() 로 바꾸어보았더니
(실행 결과)
자바 자격증을 보유한 학생
========================
박명수
김종국
위와 같이 자바 자격증을 보유한 학생이 급수에 관계 없이 모두 올바로 출력된 것을 알 수 있습니다. 이번에는 equals() 를 통해 문자열의 값인 "자바" 를 비교했기 때문에 원하는 결과가 나오게 된 거에요.
문자열 비교는 굉장히 혼란스러울 수 있는 부분이기 때문에 설명을 다시 한번 천천히 곱씹어 보면서 이해하시면 좋겠습니다 😊
감사합니다.