javascript에서 해당 npm 패키지를 설치하고, 패키지에 내장되어있는 여러가지 도구와 기능들을 사용할 수 있듯이, java 역시 이와 동일하게 여러 도구가 존재하는 패키지를 사용할 수 있다.
그 중 대표적으로 java.lang 패키지가 있는데, 아래와 같은 도구들을 제공한다.
기본형을 객체로, 객체를 기본형으로 바꿔주는 java.lang 패키지 내장 클래스.
public class Wrapper{
public static void main(String[] args){
int i1 = 5;
Integer i2 = new Integer(5);
}
}
※ Integer 클래스는 java.lang 패키지가 제공하는 Wrapper class 중 하나이다.
위에서 i2는 기본형 정수값 5가 아닌, 참조할 수 있는 객체형태로 생성되었다.
java 5부터는 바로 형변환이 가능한 구문으로 작성할 수 있다.
Integer i2 = 5;
위 구문처럼, Integer class를 사용하면 정수형 값인 5는 자동으로 객체형태로 형변환되어 선언되는데, 이러한 자동 형변환을 오토박싱이라 한다.
이와 반대로,
int i3 = i2.intValue(); //첫번째 오토언박싱
int i3 = i2;
객체 형태로 선언되어있는 값을 기본형 정수값으로 바꿔주는 과정을 오토언박싱이라 일컫는다.
기본적으로 String class 자체는 값을 변화시킬 수 없지만, String buffer 클래스는 값을 변화시킬 수 있는 클래스이다.
String 클래스가 가지고 있는 여러 단점을 보완할 수 있는 메소드가 존재한다.
public class StringBuffer{
public void main(String[] args){
StringBuffer sb = new StringBuffer;
sb.append("Hello");
sb.append("World!");
}
}
문자열을 추가함으로써 sb 객체에 새로운 문자열을 만들어낸다.
Sring str = sb.toString();
위와 같이 toString() 메소드를 사용해서 내부 문자열을 확인해볼 수 있다.
이 과정은 String buffer 클래스가 내부적으로 문자열을 바꾸고, 바꾼 문자열 자체에 대한 동일한 참조객체(자기 자신, this 생성자)를 반환하기 때문에 가능하다.
이 과정을 메소드체이닝이라 하며, Java에서 많이 사용하는 구조임을 기억한다.
※ 메소드체이닝은 결과적으로 자신 객체를 반환하기 때문에, 반복적으로 메소드를 사용하는 것이 구조적으로 가능하다.
※ 객체상태에서 내부 문자열을 출력하고자 할 때는 toString() 메소드를 활용하도록 한다.
String str = new StringBuffer.append("Hello").append("World");
System.out.println(str.toString());
말 그대로 수학적 연산을 할 수 있는 메소드가 내장되어있는 클래스이다(cos, sin, tan,...).
Math 클래스 자체는 private 속성으로 new 연산자를 통해 객체를 생성할 수는 없지만, 내부적으로 메소드 속성이 static으로 선언되어 객체생성을 하지 않고도 q바로 Math 클래스를 통해 접근하여 사용할 수는 있다.
public class Math{
public void main(String[] args){
int v = Math.max(5, 3);
}
}
public class Math{
public void main(String[] args){
int v = Math.min(5, 3);
}
}
public class Math{
public void main(String[] args){
int v = Math.random();
}
}
public class Math{
public void main(String[] args){
int v = Math.sqrt(5);
}
}
public class String{
public void main(String[] args){
String str1 = "hello";
String str2 = "World!";
String str3 = st1 + str2;
}
}
위에서 str3 문자열 클래스가 생성되는 과정은, str3가 내부적으로 StringBuffer() 클래스를 호출하여 두 str1, str2 문자열을 append()한 후 최종적으로 toString()한 객체를 str3 참조변수가 참조하기까지의 과정과 동일하다.
String str = " ";
for(int i;i<100;i++){
str2 = str2 + "*";
}
따라서, 위 반복문을 통해 문자열을 구현한다고 할 때 반복순회를 할 때마다 StringBuffer를 호출하고 내부적으로 new 연산자를 통해 해당 객체를 다시 생성하는 과정을 반복한다(참고로 str2와 별표 문자열이 합쳐진 문자열은 또 다른 객체이다).
이에 따라 선형적으로 Stringbuffer 객체가 늘어나게되어 시스템적으로 무수히 많은 Stringbuffer 객체가 생성됨으로 인해 시간복잡도 및 공간복잡도가 늘어날 수 밖에 없다.
StringBuffer sb = new StringBuffer();
for(int i;i<100;i++){
sb.append("*");
}
따라서 최초 문자열 클래스를 StringBuffer를 통해 선언할 경우, 동일한 객체(this 생성자 반환)에 문자열이 수정되는 형태로 이루어지므로 공간복잡도와 시간복잡도를 최소화할 수 있다.
public class StringBufferPerformanceTest{
public static void main(String[] args){
// (1) String의 +연산을 이용해서 10,000개의 *를 이어붙입니다.
//시작시간을 기록합니다.(millisecond단위)
long startTime1 = System.currentTimeMillis();
String str="";
for(int i=0;i<10000;i++){
str=str+"*";
}
//종료시간을 기록합니다.(millisecond단위)
long endTime1 = System.currentTimeMillis();
// (2) StringBuffer를 이용해서 10,000개의 *를 이어붙입니다.
//시작시간을 기록합니다.(millisecond단위)
long startTime2 = System.currentTimeMillis();
StringBuffer sb = new StringBuffer();
for(int i=0;i<10000;i++){
sb.append("*");
}
//종료시간을 기록합니다.(millisecond단위)
long endTime2 = System.currentTimeMillis();
// 방법(1)과 방법(2)가 걸린 시간을 비교합니다.
long duration1 = endTime1-startTime1;
long duration2 = endTime2-startTime2;
System.out.println("String의 +연산을 이용한 경우 : "+ duration1);
System.out.println("StringBuffer의 append()을 이용한 경우 : "+ duration2);
}
}
java에서 제공하는 java.lang 패키지
https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html