bdfgdfg
자바 java.lang패키지 및 오토박싱&언박싱 본문
모든것을 외울필요는 당연히 없고, 유용해보이는것들 작성 혹은 중요한 개념이라고 생각되는것들만 작성.
Object클래스
모든 클래스의 최상위 부모.
clone() : 객체 자신의 복사본을 만든다.
-> 예전에는 clone()후 앞에 형변환을 직접 해주어야 했는데, 공변 반환 타입을 통해 clone()을 오버라이딩 했을 때 반환타입을 실제로 반환되는 타입으로 반환 가능하다.
-> 또한 clone()은 일반적으로 얕은복사. 그렇기에 복제할 대상의 인스턴스가 멤버로 클래스 멤버변수를 가지고 있다면 깊은 복사 처리가 될 수 있도록 처리해주어야 한다.
wait() : 다른 쓰레드가 notify를 호출할때까지 현재 쓰레드는 무한 대기 및 매개변수로 넣은 시간동안 대기.
hashcode()
-> 해싱 기법에 사용되는 해시함수를 구현한 것
-> 호출 시 해시코드(해시값)를 반환한다.
-> 해싱기법을 사용하는 HashMap,HashSet과 같은 클래스에 저장되는 객체(사용자 정의 클래스)인 경우 hashCode를 오버라이딩해 꼭 직접 구현해주어야 한다.
String 클래스
public class Hello {
public static void main(String[] args)
{
// TODO Auto-generated method stub
String s1 = "Hello Java";
String s2 = "Hello Java";
String s3 = new String("Hello Java");
if(s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if(s1 == s3)
System.out.println("s1 == s3");
else
System.out.println("s1 != s3");
}
}
자바의 문자열 리터럴들은 따로 리터럴들의 목록이 존재한다. 해당 리터럴들은 JVM내에 있는 상수 저장소(Constant pool)에 저장이 되며
위 그림과 같이 리터럴 문자열이 내용이 같다면 참조하는 변수의 주소값은 동일하지만, new로 할당한 String은 독립적으로 주소를 가지기에 주소값이 다르다.
String Buffer / StringBuilder
String클래스는 인스턴스 생성 시 지정된 문자열의 변경이 불가능하다. (불변의 특성을 가짐)
public static void main(String[] args)
{
String s1 = "Hello";
s1 = s1 + "Java";
System.out.println(s1);
}
문자열을 덧셈(+)연산자, append를 통해서 결합이 가능한데, 이 경우 연산 시 마다 매번 새로운 문자열을 가진 String인스턴스가 생성되어( 새로운 메모리(버퍼) 생성 -> 기존 내용 복사 ) 성능에 좋지않다.
즉 stringbuffer/stringBuilder는 위와같은 문제를 해결하기 위해 사용한다.
StringBuffer와 StringBuilder의 동작은 동일하지만, StringBuffer의 경우 레이스 컨디션의 문제를 막기위한 동기화를 진행하므로 싱글쓰레드 환경. 혹은 레이스 컨디션이 발생하지 않는 구조가 확실한 경우에는 StringBuilder를 사용하는게 좋다.
public static void main(String[] args)
{
StringBuilder sb = new StringBuilder();
System.out.println( sb.capacity() );
sb.append( " Hello JAVA ");
System.out.println( sb.capacity());
sb.append("adsgsakdga;lsdgj;aslgj;asdlgjaosdjgopsdjgpsjgaspdgjasdpgoasdpogjaspodgjpasdog");
System.out.println( sb.capacity());
}
16
16
89
StringBuilder의 기본적인 capacity는 16. 물론 StringBuilder 내부 버퍼의 크기보다 더 긴 문자열을 append하는 경우 내부 새로운 버퍼를 할당하고 복사하는건 다르지는 않다.
다만 생 String만 이용해서 문자열을 결합하는것보다 위 클래스를 이용해 미리 어느정도 버퍼 크기를 할당해놓고 사용한다면 더 좋은 성능을 가질 수 있다.
또한, 가장 중요한건 버퍼의 크기를 넘어서지 않는다면 새로 버퍼를 할당하지않고도 내부 String값의 변경(추가)이 가능하다는 것.
주의해야할점은 String클래스 자체는 equals메소드를 오버라이딩하여 실제 문자열 내용을 비교하지만 StringBuffer/StringBuilder의 경우 오버라이딩하지 않았기에 == 연산자(주소값 비교)로 비교하는것과 같은 결과를 반환한다.
public static void main(String[] args)
{
StringBuilder sb = new StringBuilder("Hello");
StringBuilder sb2 = new StringBuilder("Hello");
System.out.println(sb == sb2 ); // false 출력
System.out.println(sb.equals(sb2)); // false 출력
}
반면에 toString은 오버라이딩 되어있기에 해당 인스턴스들을 toString을 호출해 equals로 비교하면 원하는 결과를 얻을 수 있다.
기본형 타입의 래퍼(Wrapper)클래스
자바언어는 기본형 타입을 객체로 다루지않는다.
C#의 경우에는 기본형 타입도 객체로 다루기에(자바와 같이 최상위 부모 클래스는 Object) 밑과 같이
많은 내부 메소드를 가지고 있는 반면 java의 경우에는 순수 기본형 타입으로만 사용하기에
매개변수로 객체(Object)를 요구하거나, 비교등이 필요한경우에는 객체로 변환하여 작업을 수행해야한다.
대표적인 기본형 타입의 래퍼클래스
boolean -> Boolean
char -> Character
byte -> Byte
short -> Short
int -> Integer
long -> Long
float -> Float
double -> Double
public static boolean equalInt( Object left, Object right ) throws Exception
{
if( !( left instanceof Integer ) || !( right instanceof Integer ) )
throw new Exception("정수형 객체가 아닙니다.");
int leftValue = ((Integer)left).intValue();
int rightValue = ((Integer)right).intValue();
return leftValue == rightValue;
}
public static void main(String[] args)
{
try
{
int a = (int)Math.random() * 10;
int b = (int)Math.random() * 10;
System.out.println(equalInt( a, b ));
}
catch(Exception e)
{
e.printStackTrace();
}
}
위 예제를 통해서 throw되는 상황을 보이고 싶었는데.. 지역변수 a,b로 선언된 값이 매개변수 left와 right에 들어갈 때 자동으로 Integer객체로 형변환 되어서 들어가는듯하다. (throw되지않고 정상적으로 잘 실행됨)
이건 궁금해서 좀 더 찾아봤는데 오토박싱과 관련이 있었음.
박싱 & 언박싱
박싱 : 기본형 객체를 Wrapper로 바꿔주는 것을 박싱. 즉 기본형 -> 참조타입
언박싱 : Wrapper -> 기본형으로 바꿔주는것을 언박싱.
여기서 오토박싱이라는 묵시적인 박싱이 위 예제에서도 자동으로 Integer로 박싱이 되었기에 Object가 10이라는 기본형 타입의 값을 넘겼을 때 오류가 발생하지 않은 것.
반대로 언박싱
public static void main(String[] args)
{
try
{
Integer a = new Integer(3);
Integer b = new Integer(5);
Integer c = a + b;
System.out.println(c.intValue());
}
catch(Exception e)
{
e.printStackTrace();
}
}
Integer는 참조형 타입이기에 참조형끼리의 덧셈연산은 불가능.
다만 자동으로 언박싱이 되기에 결과는 밑과 같이 정상적으로 나오게 된다.
8
C++에서 연산자 오버로딩이 떠올랐는데 자바에선 연산자 오버로딩은 사용불가능하다고 함.
'웹프로그래밍 > Java' 카테고리의 다른 글
자바의 컬렉션(Collection) (0) | 2023.07.27 |
---|---|
Calendar와 Date 그리고 java.time (0) | 2023.07.27 |
자바의 예외처리(exception handling) (0) | 2023.07.26 |
제어자, 캡슐화/은닉성 (0) | 2023.07.26 |
package와 import (0) | 2023.07.26 |