Do it! 자바 프로그래밍 입문 11장
자동적으로 import되는 패키지
Object, String, Integer, System 등의 클래스 포함
모든 클래스의 상위클래스
사용자가 클래스를 정의하면 컴파일러가 자동적으로 extends Object 추가
기본동작 : 패키지명, 클래스 식별자, 주소의 해시값 문자열 반환
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
}
}
기본동작 : 주소값을 비교하여 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
}
}
기본동작 : 인스턴스의 주소 반환 (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
}
}
기본동작 : 객체의 모든 속성값을 복사해 새로운 인스턴스 생성
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
}
}
String s1 = new String("gorani");
String s11 = new String("gorani");
String s2 = "GORANI";
String s22 = "GORANI";
s1과 s11은 인스턴스로 생성되어 힙영역에 적재된다.
따라서 두 변수가 참조하는 주소는 다르다.
s2와 s22는 Constant pool에 있는 문자열 "GORANI"를 참조한다.
따라서 두 변수가 참조하는 주소는 같다.
문자열은 final byte[]로 선언된 것으로 내용이 불변하다.
"abc" + "def"를 하게 되면 새로운 공간에 "abcdef"를 적재한다.
---> concat()등 문자열 변경과정에서 오버헤드 발생 가능
가변 문자열 클래스
toString()으로 String반환StringBuffer는 동기화를 보장하지 않는 가변 문자열클래스.
멀티스레드 환경에서 동기화를 보장하는 가변 문자열 클래스
** 동기화 : 자원에 lock을 걸어 스레드간 작업순서를 보장하는 것
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클래스 식별자
e.g.
boolean의 Wrapper는 Booleanfloat의 Wrapper는 Floatint의 Wrapper는 Integerpublic 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된 방법
intValue()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파일의 컴파일 결과 생성된 .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
}
}