[프로그래머스] 자바 중급 복습(1)

Seungjae·2021년 6월 25일
0

JAVA 공부하기

목록 보기
2/4

[프로그래머스] 자바 중급 복습 PART 1~4


PART 1

Object

Object 클래스모든 클래스의 최상위 클래스이다. 클래스가 아무것도 상속받지 않을 경우 자동으로 Object 클래스를 상속 받기에 모든 클래스가 Object 클래스를 상위로 두고 있다고 볼 수 있다. 즉 Object클래스가 가지고 있는 클래스는 모든 클래스에서 사용할 수 있다.

equals, hashCode, toString

equals, hashCode, toString은 Object클래스의 메서드로, 다양한 객체들에서 가장 많이 사용되어진다. 이 3개의 클래스는 각 사용마다 적절하게 오버라이딩하여 사용해야한다.

이때 의문이 들 수 있다. 그래, equals, toString? OK. 당연히 내가 원하는 목적에 따라 바꿔 써야지. 근데 hashCode는 왜? 내가 객체의 해쉬코드를 쓸 일이 없는데? 이 hashCode를 오버라이드하지 않았을 때의 문제는 HashMap같은 Hash를 사용한 Collection을 사용할 때 발생한다. Hash를 사용한 Collection은 key를 결정할 때 바로 이 hashCode를 사용한다. 따라서 예를 들어 사람 객체가 있고 age, name이 필드로 있을 경우 age와 name이 같으면 같은 사람이라고 처리하고 싶다고 하자. 그리고 이 사람 객체를 key값으로 하여 HashMap에 각 사람의 재산을 넣고 싶다. 이 때 age와 name이 같은 동일한 사람객체여도 hashCode가 다르면 키의 hash값이 달라지는 것이기에 HashMap의 key에 대한 value값을 갱신하려 할 때, 문제가 생길 수 있다.

즉 equals와 hashCode, toString은 모두 override하여 사용해야만 한다.

PART 2

Wrapper Class

Wrapper Class기본형 타입을 객체로 변환시킬 때 사용한다. Boolean, Byte, Short, Integer, Long, Float, Double이 존재한다. java에서는 기본형과 그 기본형을 객체로 변환시키는 Wrapper Class 사이의 변환을 개발자가 신경 쓸 필요 없도록 오토 박싱오토 언박싱이라는 기능을 지원한다.

int i1 = 5;
Integer i2 = new Integer(5);
Integer i3 = 5; // 오토 박싱
int i4 = i3.intValue();
int i5 = i3; // 오토 언박싱

그렇다면 Wrapper Class는 왜 쓰는 것일까? 우선 객체로 만들 경우 null을 넣을 수 있으며, 해당 객체가 가지고 있는 메서드를 사용할 수 있다. 그리고 toString 메서드를 통해 쉽게 String으로 변환할 수 있다. 마지막으로 가상의 타입인 Generic를 사용하려면 객체 타입이여야하기에 Wrapper Class로만 Generic에 들어갈 수 있다.

StringBuffer

StringBuffer는 String과 다르게 가변 객체이다. append 메서드를 사용하여 쉽게 값을 추가할 수 있다. 그리고 toString메서드를 통해 String으로 만들 수도 있다.

StringBuffer에서 주목할 점은 StringBuffer의 대부분의 메서드는 자기 자신을 반환한다는 것이다.

StringBuffer stringBuffer1 = new StringBuffer();
StringBuffer stringBuffer2 = stringBuffer1.append("Hi Man!");
if(stringBuffer1 == stringBuffer2){
         System.out.println("stringBuffer1 == stringBuffer2"); 
} // 결과 -> stringBuffer1 == stringBuffer2

이처럼 본인의 메서드를 호출하여 자기 자신의 값을 바꿔나가는 것을 메소드 체이닝이라고 한다. StringBuffer는 메소드 체인 방식으로 사용할 수 있도록 만들어져있다. 이런 메소드 체이닝 방식을 사용하면 코드를 간결하게 만들 수 있다는 장점이 있다. 단점은 하나의 라인에 너무 많은 동작이 일어날 수 있어 디버깅하기 어려울 수 있다는 것이 있다.

String의 문제

String클래스는 간편하지만 큰 문제가 있다. 바로 불변이라는 것이다. 불변이기에 문자열을 더하는 작업 같은 것을 할 경우 StringBuffer를 내부적으로 사용하게 된다.

String str3 = new StringBuffer().append(str1).append(str2).toString();

이런식으로 문자열을 더하는 작업이 이루어지기에 반복문 안에서 String을 사용하여 문자열을 더하는 작업을 할 경우 new연산자를 호출하는 횟수가 쓸데없이 많아지게 된다. java에서 new연산자의 호출 횟수가 많다는 것은 그만큼 프로그램의 속도가 저하된다는 것을 의미합니다. 따라서 반복문 안에서 문자열을 더하는 작업 같은 것을 할 때는 StringBuffer를 사용하는 것이 효율적입니다.

StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10000; i++) {
      sb.append("*");
}

PART 3

Collection

자료구조란 말 그대로 자료를 저장할 수 있는 구조이다. 자바에서는 이러한 자료구조를 위한 클래스들을 제공하는데 그것들을 컬렉션 프레임워크라고 한다. 컬렉션 프레임워크에서 가장 기본이 되는 interface는 Collection 인터페이스이다. Collection은 중복도 허용하고, 자료가 저장된 순서도 기억할 수 없다. Collection은 대표적으로 add(), size(), iterator()라는 3개의 메서드를 가지고 있다.

여기서 iterator()는 저장된 자료들을 하나씩 꺼낼 수 있는 Iterator 인터페이스를 반환한다. Iterator는 크게 두가지 메서드를 가지고 있다. 우선 꺼낼 것이 있는지 확인하는 hasNext()가 있다. 그리고 하나씩 자료를 꺼내는 next()가 있다.

Set

Set은 Collection 인터페이스를 상속 받는다. Set은 중복을 허용하지 않는 자료구조이다. Set 인터페이스가 가지고 있는 add는 같은 자료가 있으면 false, 없으면 true를 리턴한다.

List

List도 Collection 인터페이스를 상속 받는다. List는 중복은 허용하며 자료가 들어온 순서를 기억한다. 따라서 n번째 자료를 꺼낼 수 있는 get()메서드를 가지고 있다.

Map

Map는 Collection과는 다른 검색의 개념이 더해진 인터페이스이다. Map은 Key와 Value를 가지고 있으며 put()메서드를 통해 key와 value를 함께 저장한다. 그리고 key값을 사용하여 get()메서드를 통해 값을 꺼낸다. Map에 저장된 모든 값은 중복된 key값을 가질 수 없으며 이미 key값이 존재하는데 또 put으로 그 key값에 대한 value를 지정할 경우, key의 value 값이 변경한 값으로 갱신된다. Key가 중복되지 않는다는 특징 때문에 Map은 자신이 가지고 있는 모든 키를 Set으로 반환하는 keySet()메서드를 가지고 있다.

Map의 모든 key,value 출력하기 (forEach사용)

map.forEach((key, value) -> System.out.println("key: " + key + ", value: " + value));

Generic

Generic은 다양한 타입의 객체를 받아서 사용해야할 경우 매우 유용하다. Generic을 사용하여 선언할때는 가상의 타입으로 선언하고, 사용시에는 구체적인 타입을 개발자 마음대로 설정할 수 있다. 물론 Generic을 사용안하고 Object로 받아서 사용할 수도 있다. 하지만 그 객체를 사용할 경우 다시 형변환을 진행해줘야하므로 Genenric보다 사용하기에 불편하다. Generic을 사용하는 대표적인 클래스는 컬렉션 프레임워크등이 있다.

public class Box<E> { // E에는 객체 타입이면 무엇이든 들어올 수 있다.
    private E obj;

    public void setObj(E obj) {
        this.obj = obj;
    }

    public E getObj() {
        return obj;
    }
}

PART 4

Date

Date는 날짜와 시간을 구하기 위한 클래스이다. Date 클래스는 아쉽게도 지역화를 고려하지 않고 설계되었다. 지역화란 나라마다 화폐 단위와 시간이 다른 것을 뜻한다.

SimpleDateFormat 클래스를 이용하여 원하는 형태로 출력을 할 수 있다. a는 오전/오후를 뜻하고 zzz는 TimeZone을 뜻한다.

System.currentTimeMillis()를 통해 현재 시간을 Long값으로도 얻을 수 있다.

Calendar

Date의 지역화를 고려하지 못했다는 단점을 해결하기 위해 등장한 클래스가 Calendar 클래스이다. Calendar 클래스는 추상 클래스이며, Calendar 클래스의 인스턴스를 생성하기 위해서는 getInstance() 메서드를 사용해야한다. 내부적으로는 GregorianCalendar 인스턴스를 리턴한다.(현재 표준 달력) 이렇게 설계한 이유는 혹시 나중에 표준이 바뀔 경우 쉽게 적용하기 위해서이다.

get 메서드를 사용하여 Calendar의 상수를 어떤 것을 넣느냐에 따라서 년,월,일, 시간 등을 구할 수 있다.

add 메서드로 특정한 기간 이전의, 혹은 지난 날짜를 구할 수 있다.

java.time

기존 Date, Time API의 문제점을 해결하고 더 직관적은 기능을 제공하기위해 등장하였다. java.time의 클래스들은 오브젝트를 생성할 때 factory 메서드를 사용한다. 자기 자신의 특정 요소를 가지고 오브젝트를 생성할 경우는 of 메서드를 사용하고, 다른 타입으로 변경하고자 할 경우 from 메서드를 사용하면 된다.

Ref


https://nesoy.github.io/articles/2018-06/Java-equals-hashcode

https://wakestand.tistory.com/184

profile
코드 품질의 중요성을 아는 개발자 👋🏻

0개의 댓글