JAVA 07 : Object, String, StringBuffer, StringBuilder, Wrapper, Class(동적로딩)

LeeWonjin·2022년 7월 19일

2022 백엔드스터디

목록 보기
7/20

Do it! 자바 프로그래밍 입문 11장

java.lang

자동적으로 import되는 패키지
Object, String, Integer, System 등의 클래스 포함

java.lang.Object

모든 클래스의 상위클래스
사용자가 클래스를 정의하면 컴파일러가 자동적으로 extends Object 추가

public String toString()

기본동작 : 패키지명, 클래스 식별자, 주소의 해시값 문자열 반환

package DefaultClass;

class Gorani_1 { // Object's toString()
	String name;
	Gorani_1(String name){
		this.name = name;
	}
}

class Gorani_2 { // Overrided toString()
	String name;
	Gorani_2(String name){
		this.name = name;
	}
	
	@Override
	public String toString() {
		return "I am " + name;
	}
}

public class DefaultClass {
	public static void main(String[] args) {
		Gorani_1 g1 = new Gorani_1("aaa");
		Gorani_2 g2 = new Gorani_2("bbb");
		
		System.out.println(g1.toString()); // DefaultClass.Gorani_1@5ca881b5
		System.out.println(g2.toString()); // I am bbb
	}
}

public boolean equals()

기본동작 : 주소값을 비교하여 true, false 반환 (클래스에 대한 ==연산자와 유사하게 동작)

class Gorani_1 { // Object method
	String name;
	Gorani_1(String name){ this.name = name; }
}

class Gorani_2 { // Overrided method
	String name;
	Gorani_2(String name){ this.name = name; }
	
	@Override
	public boolean equals(Object another) {
		if(this.name == ((Gorani_2)another).name) return true;
		else return false;
	}
}

public class DefaultClass {
	public static void main(String[] args) {
		// (Default Behavior)
		Gorani_1 g1 = new Gorani_1("aaa");
		Gorani_1 g2 = new Gorani_1("aaa");		
		System.out.println(g1.equals(g2)); // false 
		
		// (Overrided Behavior)
		Gorani_2 g3 = new Gorani_2("ccc");
		Gorani_2 g4 = new Gorani_2("ccc");
		System.out.println(g3.equals(g4)); // true 
	}
}

publilc int hashCode()

기본동작 : 인스턴스의 주소 반환 (JVM에서 인스턴스를 힙에 저장할 때 hash방식으로 저장)

  • equals()를 오버라이드한 경우, 일반적으로 hashCode()또한 오버라이드함
class Gorani_1 { // Object method
	String name;
	Gorani_1(String name){ this.name = name; }
}

class Gorani_2 { // Overrided method
	String name;
	Gorani_2(String name){ this.name = name; }
	
	@Override
	public int hashCode() {
		// 올바른 해시함수는 아님. 단순히 리턴값을 만들기 위한 단순한 구현.
		int sum = 0;
		for(int i=0; i<name.length(); i++)
			sum += name.charAt(i);
		return sum%5381;
	}
}

public class DefaultClass {
	public static void main(String[] args) {
		// (Default Behavior)
		Gorani_1 g1 = new Gorani_1("aaa");
		Gorani_1 g2 = new Gorani_1("aaa");		
		System.out.println(g1.hashCode()); // 2055281021
		System.out.println(g2.hashCode()); // 1554547125
		
		// (Overrided Behavior)
		Gorani_2 g3 = new Gorani_2("ccc");
		Gorani_2 g4 = new Gorani_2("ccc");
		System.out.println(g3.hashCode()); // 297
		System.out.println(g4.hashCode()); // 297
	}
}

public Object clone()

기본동작 : 객체의 모든 속성값을 복사해 새로운 인스턴스 생성

  • clone()이 사용가능하다는 것은 정보은닉에 위배되는 일이므로 특별히 이를 허용할 클래스에는 implements Cloneable를 붙임
class Gorani_2 implements Cloneable{ // Overrided method
	String name;
	Gorani_2(String name){ this.name = name; }
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}

public class DefaultClass {
	public static void main(String[] args) throws CloneNotSupportedException {
		// (Overrided Behavior)
		Gorani_2 g3 = new Gorani_2("ccc");
		Gorani_2 g4 = (Gorani_2)g3.clone();
		System.out.println(g3.name + " " + g4.name); // ccc ccc
		System.out.println(System.identityHashCode(g3) == System.identityHashCode(g4)); // false
	}
}

java.lang.String

선언 방법

String s1 = new String("gorani");
String s11 = new String("gorani");

String s2 = "GORANI";
String s22 = "GORANI";

s1s11은 인스턴스로 생성되어 힙영역에 적재된다.
따라서 두 변수가 참조하는 주소는 다르다.

s2s22는 Constant pool에 있는 문자열 "GORANI"를 참조한다.
따라서 두 변수가 참조하는 주소는 같다.

불변성 (Immutable)

문자열은 final byte[]로 선언된 것으로 내용이 불변하다.
"abc" + "def"를 하게 되면 새로운 공간에 "abcdef"를 적재한다.
---> concat()등 문자열 변경과정에서 오버헤드 발생 가능

StringBuilder, StringBuffer

가변 문자열 클래스

  • toString()으로 String반환
  • 가변적인 char[]을 가짐. 문자열이 변경될 때 이 배열의 내용을 변경
  • garbage생성 없음

java.lang.StringBuilder

StringBuffer는 동기화를 보장하지 않는 가변 문자열클래스.

java.lang.StringBuffer

멀티스레드 환경에서 동기화를 보장하는 가변 문자열 클래스
** 동기화 : 자원에 lock을 걸어 스레드간 작업순서를 보장하는 것

  • 단일 스레드 환경에서는 StringBuffer가 아닌 StringBuilder를 사용하도록 권장
public class DefaultClass {
	public static void main(String[] args) {
		int prev, current;
		
		// String
		String str = new String("gorani");
		prev = System.identityHashCode(str);
		
		str = str.concat("appended");
		current = System.identityHashCode(str);
	
		System.out.println(prev==current); // false
		
		
		// StringBuilder
		StringBuilder strBld = new StringBuilder("gorani");
		prev = System.identityHashCode(strBld);
		
		strBld.append("appended");
		current = System.identityHashCode(strBld);
		
		System.out.println(prev==current); // true
		
		
		// StringBuffer
		StringBuffer strBuf = new StringBuffer("gorani");
		prev = System.identityHashCode(strBuf);
		
		strBuf.append("appended");
		current = System.identityHashCode(strBuf);
		
		System.out.println(prev==current); // true
	}
}

Wrapper 클래스

원시자료형을 래핑한 클래스
원시형의 키워드 첫글자를 대문자로 바꾸면 대체로 Wrapper클래스 식별자

e.g.

  • boolean의 Wrapper는 Boolean
  • float의 Wrapper는 Float
  • int의 Wrapper는 Integer

인스턴스화

public class DefaultClass {
	public static void main(String[] args) {
		Character ch1 = new Character('a');
		Character ch2 = 'a';
		System.out.println(ch1 + " " + ch2); // a a
	}
}

ch1, ch2는 동일한 결과를 냄.
new Character() 생성자를 호출하는 것은 java9 이후로 deprecated된 방법

오토박싱, 언박싱

  • 언박싱 : Wrapper클래스에서 원시형의 값을 조회 intValue()
  • 오토방식 : 원시형을 이 값을 가진 Wrapper클래스로 변환 Wrapper클래스.valueOf(원시형 변수)
public class DefaultClass {
	public static void main(String[] args) {
		int primitive = 5;
		Integer wrapper = 3;
		
		primitive = primitive + wrapper; // wrapper unboxing
		System.out.println(primitive); // 8
		wrapper = wrapper + primitive; // primitive autoboxing
		System.out.println(wrapper); // 11
	}
}

java.lang.Class 클래스

Java18 Doc Class\

.java파일의 컴파일 결과 생성된 .class파일로부터 객체의 정보를 조회
e.g. 필드, 메소드, 생성자

reflection 프로그래밍에 사용할 수 있다. (java.lang.relfect)
자료형을 알지 못할 때 객체 정보만을 이용하여 인스턴스 생성 및 사용

package ClassTest;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException {
		Gorani g = new Gorani("aaa");
		
        // 정적로딩
		// c1, c2 는 Gorani클래스가 컴파일 된 다음 성립하는 문장
		Class c1 = g.getClass();
		Class c2 = Gorani.class;
		System.out.println(c1.getName() + " " + c2.getName()); // ClassTest.Gorani ClassTest.Gorani
		
		// 동적로딩 : 문자열에 해당하는 클래스가 있으면 메모리에 적재
        // ClassTest.Gorani가 존재하는지는 런타임에 알 수 있음
		Class c3 = Class.forName("ClassTest.Gorani");
		System.out.println(c3.getName()); // ClassTest.Gorani
		
		// c3 클래스의 public 멤버 정보 조회
		Constructor[] arrC = c3.getConstructors();
		for(Constructor item : arrC)
			System.out.println(item);
		
		Field[] arrF = c3.getFields();
		for(Field item : arrF)
			System.out.println(item);
		
		Method[] arrM = c3.getMethods();
		for(Method item : arrM)
			System.out.println(item);
		
		// c3 클래스의 인스턴스 생성
		Gorani c4 = (Gorani) arrC[0].newInstance("namename"); // namename is constructed
		c4.printInfo(); // I am namename
	}
}
profile
노는게 제일 좋습니다.

0개의 댓글