❗ 개인적으로 공부했던 내용을 복습하고 정리하기 위한 글입니다! 따라서 내용이 정확하지 않을 수 있습니다!
Application Programming Interface
API의 뜻이다. 애플리케이션을 프로그래밍 하기 위한 인터페이스, 우리는 여기서 인터페이스라는 단어에 집중해야 한다. 자바에서도 이러한 API를 제공하여 주는데, 자바 API는 자바 프로그래밍 시 자주 사용되는 클래스 및 인터페이스들의 모음이다. 우리가 흔히 사용하는 System
, String
, Math
, Scanner
등은 모두 자바에서 기본으로 제공해주는 JAVA API이다. 이 API는 우리가 java.lang.* 을 import하면 사용할 수 있다.(생략도 가능하다!) 이것은 우리가 JDK(Java Development Kit)를 설치하였기 때문에 사용할 수 있다.
JAVA API중 대표적인 클래스 중 하나로 Math클래스가 있다. 이 클래스를 사용하기 위해 평소처럼 객체를 생성해 보자.
Math m = new Math(); // 오류가 난다.
오류가 났다. 분명 평소 객체처럼 만들었는데 무언가 이상하다. 오류가 난 부분에 마우스를 가져가 보면 The constructor Math() is not visible
라고 한다. Math()클래스의 생성자가 보이지 않는다는데....
Math 클래스를 까보면 생성자가 private
로 되어있는 걸 볼 수 있다. 친절하게 인스턴스화 할 수 없다고 주석도 달려있다.
Math 클래스는 메소드 또한 전부 static
이기 때문에 객체 생성할 필요가 없다. 이를 싱글톤 패턴(프로그램 실행과 동시에 메모리 영역에 올려놓고 사용하는 것)이라고 한다.
또한 Math클래스 안에는 메소드들이 오버로딩 되어 있기 때문에 매개변수로 int
나 double
을 주어도 메소드가 제대로 호출되고 실행되는 걸 볼 수 있다. 아래 예시는 절대값 구하는 메소드Math.abs()
인데, 이 또한 Math 클래스 안에 오버로딩 되어 정의되어 있다.
우리가 자바 프로그래밍을 하면서 아마 가장 많이 사용하는 클래스는 String 클래스가 아닐까 생각한다. String 클래스는 불변 클래스이다. 또한 이 클래스로 만들어진 객체는 주소값을 저장하고 있는 참조 자료형이다.
String클래스로 객체를 생성하는 방법에는 두가지가 있다.
1. new 키워드로 생성자 호출
2. 대입연산자를 통해서 직접 값을 넣어서 생성
우리가 평소 객체를 만드는 것처럼 new
키워드로 생성자를 호출했다. 다행히 위의 Math 클래스처럼 오류가 뜨지 않았다. 출력도 잘 된다!
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1);
System.out.println(str2);
그렇다면 해당 주소들을 비교해보자. 객체는 heap영역에 생성되고, 객체 변수 이름은 stack영역에 생성되어 주소를 참조하는 것이니, 16진수의 주소값을 10진수의 주소값으로 출력해주는 hashCode()
메소드를 통하면 아마 주소값이 다르게 나올 것이다.
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());
그러나 결과는 달랐다.
69609650
69609650
어라... 분명 주소가 다르게 나와야 하는데... 그 이유는 String클래스의 hashCode()
메소드가 오버라이딩 되어 사용되기 때문이다. String클래스의 hashCode()
메소드는 주소값을 변환주는 것이 아닌 실제 담긴 문자열을 기반으로 해시코드값을 만들어서 반환해준다.
그럼 실제 주소값을 알려면 어떻게 해야할까? 그럴 떄 사용하는 것이 System.identityHashCode()
메소드이다. 이 메소드를 통하여 주소값을 출력해 보았다. 이 메소드는 실제 주소값의 해시코드를 출력해주는 메소드이다.
System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str2));
705927765
366712642
이렇게 되면 주소값이 다르게 출력되는 것을 알 수 있다. 그러나 이렇게 객체를 만들어 String클래스를 사용하는 건 금기시 된다. 그 이유는 위에 서술하였듯, String클래스는 불변 클래스인데, 불변 클래스는 말 그대로 변할 수 없는 클래스라는 뜻이다.
String str1 = "hello";
String str2 = "hello";
위와 같이 대입 연산자를 통하여 직접 값을 넣어(리터럴 값) 생성하면 된다. 그러면 str1과 str2의 주소값을 비교해 보자.
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());
99162322
99162322
주소가 똑같이 나왔다. 하지만 이 방법은 new
연산자에서 발생한 주소가 같았던 현상이라고 생각할 수 있어 System.identityHashCode()
메소드로 비교해 보자.
System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str2));
705927765
705927765
놀랍게도 주소가 같은 걸 확인할 수 있다! 그 이유는 String클래스를 대입연산자를 통해 직접 초기화 하여 생성하면, StringPool영역에 올라간다.
String Pool이란 Heap영역 안에 있는 메모리 영역인데, 위에서 말했듯 리터럴 값을 대입하면 String Pool 영역에 올라가게 된다. 그림으로 설명하면 다음과 같다.
String Pool에 "hello"라는 문자열의 공간이 할당되고, stack영역의 두 변수 str1, str2가 모두 String Pool에 있는 문자열의 주소를 참조하게 된다. 따라서 주소가 동일하게 나온다.
그렇다면 문자열 비교로 동등비교연산자(==
)를 통해 비교해 보면 어떻게 될까?
System.out.println("문자열이 같나용? : " + str1 == str2);
결과는 다음과 같다.
false
분명 주소값이 같아서 true
가 반환되어야 할텐데... 이상한 문자열이 나왔다. 이는 연산자 우선순위 때문이다. 문자열에서 +
연산자는 다형성이 적용되어 문자열 끝에 문자열을 붙이도록 되어있다. 그래서 "문자열이 같나용 ? " + str1이 먼저 실행되고, 이 합쳐진 문자열을 str2와 비교를 하기 때문에, false가 출력 되었다. 이를 방지하기 막기 위해 연산자의 우선순위를 정해주면 제대로 출력이 된다.
System.out.println("문자열이 같나용? : " + (str1 == str2));
문자열이 같나용? : true
제대로 출력됨을 확인할 수 있다!
마지막으로 소개할 건 Wrapper 클래스이다. 이 클래스는 기본자료형을 객체로 포장해주는 클래이다. Wrapper클래스는 기본 자료형을 객체로 취급해야 하는 경우, 메소드를 매개변수로 사용하여 기본 자료형이 아닌 객체타입만 요구할 때, 다형성을 적용시키고 싶을 때 사용한다고 한다.
String str1 = "10";
String str2 = "20.5";
System.out.println(str1 + str2);
1020.5
먼저 위와 같이 String으로 선언 된 문자열 객체에 숫자를 문자열로 대입하면, 당연히 문자열 끝에 다른 문자열이 붙어져서 출력된다. 그러나 이때 Wrapper클래스를 이용하면 숫자처럼 취급이 가능하다!
int i = Integer.parseInt(str1);
double d = Double.parseDouble(str2);
System.out.println(i + d);
20.5
Wrapper 클래스의 parse메소드를 통하여 숫자로 파싱해주었고, 파싱한 값들을 더하니 제대로 숫자끼리 더해져 출력이 되었다.
우리가 자바 프로그래밍을 하면서 정말 흔히 사용하는 클래스들을 한 번 정리해 보았다. 기존에 내가 알고 있던 내용들과 다른 내용들이 있었는데, 특히 String의 클래스에서 문자열 다음의 비교는 false가 나오던 게, 주소값이라고 생각하고 있었다. 이걸 다시 한 번 짚고 넘어갈 수 있어서 좋았고, String Pool이라는 메모리 영역에 생긴다는 사실을 알았다. 평소에는 생각 없이 사용했는데, 어떻게 돌아가는지 원리를 알 수 있어서 좋았다.
끝!😉