7월 20일 (목) 자바 개념 정리
OOP is A PIE
Polymorphism = 하나의 클래스가 다양한 클래스로 참조될 수 있음 ex) 나 => 강의실 : 수강생, 출근길 : 대중교통 이용자, 국방부 : 예비군 아저씨 등 상황에 따라 해석이 다르게 된다.
Homogeneous-Array : 특정 클래스만 원소로 가질 수 있는 배열 Heterogeneous-Array : 슈퍼 타입으로 가리켜 하위 클래스 변수를 원소로 가질 수 있는 배열
Inheritance = 부모 클래스의 자산을 자식 클래스에서 재사용 혹은 확장할 수 있는 것
Singleton-Pattern 수정 가능한 멤버 변수가 없고 기능만을 가진 클래스의 효율성을 위해 사용한다. ex) request마다 서비스 객체를 매번 생성해야 한다면? 자원 낭비로 이어진다. 하나의 객체를 통해 서비스를 제공한다면 일관성과 성능에 있어서 효율적인 방법을 제시할 수 있다.
- 멤버 변수 (state) 가 없고 기능만 있는 객체를 stateless한 객체라고 한다.
Modifier = Access Modifier + Usage Modifier private, (default), protected, public static, final, abstract
로컬 변수는 final을 제외한 지정자를 사용할 수 없다. main 호출 시점은 객체 생성 전이므로 static이 붙는다. instance 메소드가 static 변수를 사용하는 건 가능하다. (static이 메모리에 로드된 후 객체를 생성하기 때문. 이와 같은 이유로 반대는 불가하며 main에서 인스턴스 메소드를 객체 생성없이 호출하는 것은 불가능하다.)
1
2
3
4
5
6
7
8
9
10
11
12
class A {
private static A instance = null; // 객체 생성 전 객체 존재 여부를 확인하기 위해 static 키워드 사용
private A() {} // 클래스 A에서만 객체 생성을 담당하기 위해 private 키워드 사용
public static A getInstance() { // A가 메모리에 할당되지 않은 경우에만 생성하고, 이후 항상 같은 객체를 재사용
if(instance == null)
instance = new A();
return instance;
}
}
메모리에 처음부터 로드해서 하나만 쓸거면 static으로 사용하면 안되나? => 싱글톤 패턴은 원하는 시점에 함수를 호출해 메모리에 올릴 수 있고, 객체 메소드나 데이터도 가질 수 있다. 이에 반해 static은 garbage collection 대상도 아닐 뿐더러 메소드를 가질 수 없고 로드 시점을 정할 수 없다.
ArrayList는 Object의 배열인데, Primitive Type 변수가 담길 수 있을까?
1
2
3
4
5
6
7
8
9
10
11
import java.util.ArrayList;
public class ArrayListTest {
public static void main(String[] args)
{
ArrayList<Integer> a = new ArrayList<Integer>();
a.add(1);
System.out.println(a.toString()); // [1]
}
}
Auto-Boxing을 통해 Primitive Type도 Object 클래스를 상속 받는 Wrapper 클래스를 통해 최상위 클래스 Object로 가리킬 수 있는 다형성을 제공한다. 즉, Object 클래스는 모든 걸 가리킬 수 있다. (type-casting을 해야하는 고비용 작업이기도 하다.)
synchronized 키워드는 lock을 걸어 스레드 수행 중 다른 스레드의 접근을 막는데 사용한다. 최대한 쓰지 않는 것이 좋은데 각각의 객체가 영향을 주지 않도록 함수 내에서 new를 통해 생성한다면, 어디서든 접근 가능한 static 변수와는 다르게 접근 가능한 reference 변수가 없으므로 synchronized 없이 안정적으로 스레드 사용이 가능하다.
입출력 장치의 명령어 수행 과정은 현재 진행 중인 모든 일을 잠시 멈추고, 연결된 하드웨어의 동작을 수행해야기 때문에 매우 느린 작업이다.
1
2
3
4
5
6
7
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
정적 바인딩 (compile time) vs 동적 바인딩 (runtime)
정적 바인딩 : 참조 변수의 타입에 따라 연결이 달라진다. 상속 관계에서 객체의 static, instance 변수 중복 시 혹은 static 메소드가 중복 시 일어난다. (static, private, final method와 같이 override 불가능하여 컴파일 시점에 타입이 결정된다.)
동적 바인딩 : 상속 관계에서 객체의 instance 메소드가 재정의되었을 때, 자식 클래스의 메소드가 호출된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/////////////////////////////정적 바인딩/////////////////////////////////
public class Vehicle{
public static void drive() {
System.out.println("vehicle drive");
}
public static void main( String args[]) {
Vehicle vehicle = new Vehicle();
Vehicle electric = new Electric();
vehicle.drive(); // vehicle drive
electric.drive(); // vehicle drive
}
}
class Electric extends Vehicle{
public static void drive(){ // 오버라이딩이 된 것이 아니라 새로 추가된 것이다.
System.out.println("electric drive");
}
}
/////////////////////////////////////////////////////////////////////////
/////////////////////////////동적 바인딩/////////////////////////////////
public class Vehicle{
public void drive() {
System.out.println("vehicle drive");
}
public static void main( String args[]) {
Vehicle vehicle = new Vehicle();
Vehicle electric = new Electric();
vehicle.drive(); // vehicle drive
electric.drive(); // electric drive
}
}
class Electric extends Vehicle{
public void drive(){
System.out.println("electric drive");
}
}
/////////////////////////////////////////////////////////////////////////
System 객체가 out, in 등의 변수를 갖는 이유? out은 PrintStream 객체고, in은 InputStream 객체라 System.out.println() 할 필요없이 static으로 선언한 public static final PrintStream out 객체로 직접 접근해 out.println()을 해도 되지만, 이렇게 되면 import java.io.PrintStream, import java.io.InputStream과 같이 귀찮은 작업을 해줘야 하기 때문에 주로 쓰는 객체를 묶어서 관리한다.
자바에서 class instance, array, enum은 레퍼런스 데이터다. String은 배열을 활용한 레퍼런스 데이터이므로 String 데이터를 concat하는 것 혹은 append 하는 등의 작업은 새로운 String 객체를 eden 영역에 생성하게 된다.
1
2
3
4
5
ex) String a = "java"; String b = "java";
String c = a + b; // instance (배열은 사이즈가 고정되어 있어서 concat 시 새로운 객체를 생성해야한다. String의 immutable 속성)
String d = "java" + "java"; // literal pool
String e = "javajava";
d == e; // true
컴파일러는 String 클래스 변수를 StringBuilder 클래스로 바꾸는데 이는 단일 스레드를 위한 클래스다. 이것이 멀티스레드에서 문제가 되지 않는 이유는 함수를 통해 Stack 메모리 내에서 reference 변수로 가리키면 다른 스레드에서 이를 침범하지 않기 때문에 컴파일러는 String 클래스를 StringBuilder로 변환하여 생성한다. (단 String str = “0” + “1” + “2”; 와 같이 변수 생성없이 리터럴을 이어놓은 건 StringBuilder로 변환하지 않고 리터럴 풀에 저장된다.)
DAO : Data Access Object DB와 Service 사이에 데이터 엑세스를 도와주는 객체 (jdbc로 연결)