[TIL] PowerJava chap5 - 클래스와 객체 2

은동·2023년 1월 28일
0

JAVA_TIL

목록 보기
5/8
post-thumbnail

✔️ 가비지 컬렉션(garbage collection)

자바의 자동 메모리 삭제 시스템
c++에서는 delete연산자가 있지만, 자바에는 없음

  • 가비지 컬렉션은 객체가 사용되지 않는다는 것을 어떻게 알까?

모든 객체는 참조 변수를 통해야만 사용할 수 있음
따라서 참조하는 변수가 전혀 없다면 그 객체는 사용이 불가능하고 없애는 것이 좋음

	Television tv1 = new Television();
	Television tv2 = new Television();
	tv2 = tv1;

tv2가 가리키고 있었던 객체는 위의 코드가 실행된 후에는 아무도 참조하지 않게 되어서 더는 아무도 접근할 수 없다. 따라서 가비지 컬렉션의 후보가 됨


✔️ 가비지 컬렉터(garbage collector)

히프 메모리에서 더 이상 필요 없는 객체를 찾아 지우는 작업을 함

  • 전반적인 과정
    히프 메모리 부족 -> JVM은 가비지 컬렉터 수행 -> 가비지 컬렉터를 제외한 나머지 자바 어플리케이션은 모든 동작을 멈춤 -> 가비지 컬렉터가 작업을 완료 -> 중단 작업 다시 시작

하지만 이것이 자바의 성능에 큰 영향을 끼침

  • 가비지 컬렉터 프로세스
  1. 마킹(marking) : 참조되지 않은 객체가 식별됨, 가비지 수집 준비가 된 것으로 표시
  2. 삭제(normal detection) : 표시된 객체가 삭제됨
  3. 압축(compaction) : 메모리를 압축
  • 가비지 컬렉션 요청
    System 객체의 gc()메소드를 호출하여서 가비지 컬렉션 요청 가능
    하지만 가비지 컬렉터가 수행되면 모든 다른 애플리케이션이 멈추기 때문에 컬렉터의 실행 여부는 JVM이 판단
System.gc();	//가비지 컬렉션 요청

위와 같이 가비지 컬렉터를 실행하는 코드에 힌트를 줄 수는 있지만 가비지 컬렉터가 실제로 실행된다는 보장은 없음

  • 가비지 컬렉션 최적화
  1. Young 영역과 Old영역의 힙 크기를 알맞게 조정하는 것
  2. 객체의 할당(Allocation)이나 Old 영역으로의 이동(Promotion)등의 작업을 줄이는 것

https://mangkyu.tistory.com/120 참고해서 2회독 때 다시 봐야겠다🙄


✔️ 인수 전달 방법

자바에서 인수를 메소드로 전달하는 방법은 call-by-value(값에 의한 호출) 이다.
인수의 값이 복사되어 매개변수로 전달됨

int sum = obj.add(25, 47);	//인수 값 복사

int add(int x, int y){	// 파라미터로 전달
	return x+y;
}

✔️ 1. 기초형 값이 전달되는 경우 (int, double 등)

-> call-by-value

int x =10;

obj.inc(x);		// 값이 복사
System.out.println(x);


void inc(int a){	//파라미터로 전달
	a = a+1;
}

출력결과 : 10
즉, 매개변수를 변경하여도 메소드 외부에 있는 인수에 영향을 주지 않음

✔️ 2. 객체가 전달되는 경우

-> 객체를 메소드로 전달하게 되면 객체 자체가 복사되어 전달되는 것이 아닌 객체의 참조값(주소)만 복사되어서 전달됨
그래서 참조값이 매개변수로 복사되면 메소드의 매개변수도 동일한 객체를 참조하게 됨
즉, 매개변수를 통해여 객체의 내용을 변경하면 인수가 가리키는 객체도 변경됨

Pizza obj = new Pizza(10);
obj.inc(obj);	// 참조값 복사
System.out.println(obj.radius);

void inc(Pizza c){	// 참조값 복사되어 동일한 객체인 pizza 가리킴
	c.radius++;
}

출력 결과 : 11
inc()안에서 객체를 변경하면 원본 객체도 변경됨
메소드가 객체를 반환할 때도 객체가 통째로 반환되는 것이 아니라 객체의 참조값만 반환됨
실제 객체가 오가는 것이 아니므로 주의가 필요함

✔️ 3. 배열이 전달되는 경우

자바에서는 배열도 객체
그래서 배열이 전달되는 경우에도 객체가 전달되는 것과 동일하게 처리됨

int[] list = [1,2,3,4,5];
ArrayProc obj = new ArrayProc();
obj.int(list);	// 참조변수 복사


void int (int[] array){	// 동일한 배열 가리킴
	for(int i=0 ; i<array.length ; i++){
    	array[i] = arrar[i]+1;
    }    
}        

즉, 배열이 전달되는 것이 아니라 배열을 가리키는 참조값이 복사되고 메소드에서 매개변수를 통하여 배열을 변경하면 원본 배열이 변경됨


✔️ 정적 멤버 (static member)

쉐어하우스처럼 잠자는 공간은 따로 있지만, 주방이나 화장실을 공유로 사용

이와 비슷하게 프로그램에서도 개별적으로 소유해야 하는 멤버(인스턴스 멤버)들도 있고, 객체들이 공유하는 멤버(정적 멤버)도 있음

- 인스턴스 변수

동일한 클래스를 이용하여 많은 객체들이 생성될 때 객체들은 자신만의 필드를 가짐. 즉 이들 필드는 객체마다 별도로 생성되기 때문에 인스턴스 변수라고 함

- 정적 변수

클래스 당 하나만 생성되는 변수
변수 선언 시 앞에 static을 붙이면 됨 ( ex. static int num;)

	class Television{
	   int channel;	 // 인스턴스 변수
  	   int volume;	 // 인스턴스 변수
  	   boolean onOff;	// 인스턴스 변수
  	   static int count; // 정적 변수
	}     

예를 들어 객체 A, 객체 B, 객체 C가 있다고 하자.
channel, volume, onOff는 인스턴스 변수여서 각 객체가 이들 변수에 대해서 독립적인 공간을 가지고 있고 각기 다른 값을 가질 수 있지만, count는 정적 변수이기 때문에 하나의 클래스에 하나만 만들어지고 동일한 클래스로 생성된 모든 객체들은 하나의 정적 변수를 공유한다.

  • 정적 변수 값 변경
    count에 100을 대입하고 싶다면, dot연산자를 이용해서 변경
  1. 클래스를 객체처럼 사용해서 접근
 Television.count = 100;
  1. 객체의 이름을 통해서 접근
 Television obj = new Television();
 obj.count = 100;
  • 정적 변수 활용
    정적 변수는 상수를 정의하는 용도로 사용됨
    상수를 여러 개의 객체가 공유하는 것이 경제적이고, 객체마다 상수를 가지고 있을 필요가 없기 때문

    그리고 자바에는 전역변수(global variable)의 개념이 없음 이럴 때 정적 변수를 활용하면 일종의 전역변수의 역할로써 사용할 수 있음

✔️ 정적 메소드

정적 변수와 마찬가지로 static 수식자를 메소드 앞에 붙여서 만듦

정적 메소드의 예는 Math클래스 안에 들어 있는 각종 수학 메소드들
예를 들어 실수의 제곱근을 구해야 할 때, Math클래스의 객체를 생성할 필요가 없다는 것!

또 우리가 많이 사용하였던 main() 메소드의 앞에도 static이 붙어있는데 이는 JVM이 객체를 생성할 필요 없이 main() 메소드를 호출할 수 있도록 하기 위해서임

✔️ 정적 변수와 정적 메소드를 사용할 시 주의사항

  1. 정적 메소드는 정적 멤버만 사용할 수 있다.
	class Test{
	 	int a;
     	static int b;
     
    	void sub() {a=0;}
    	static void sub2() {a=0;}	
        // 정적 메소드에서는 인스턴스 멤버를 사용하면 안되기 때문에 오류가 발생한다.
}
  1. 정적 메소드에서 정적 메소드를 호출하는 것은 가능하다.
	public class Test{
	 	public static void main(String args[])	{
			add(10,20);	
            // 정적 메소드 안에서 인스턴스 메소드를 호출하면 오류가 발생한다.
     	}
     	int add(int x, int y){
			return x+y;
     	}
	}

--> 이 경우에 add를 정적 메소드로 만들면 컴파일 오류를 막을 수 있음

  1. 정적 메소드는 this를 사용할 수 없다

this는 현재 객체를 가리키는 참조 변수이다. 하지만 정적 메소드는 객체가 없을 때도 호출될 수 있기 때문에 현재 객체라는 개념이 없음

	class Test{
		static int a;
    
    	static void sub(int x) {this.a = x;} 
    	// 정적 메소드에서는 this를 사용할 수 없다.
	}

✔️ fianl 키워드

final 카워드를 붙이면 상수가 됨
상수를 정의할 때 static과 final 수식어를 동시에 사용하는 경우가 많음

public class Car{
	 static final int MAX_SPEED = 350;
}

✔️ 정적 블록(static block)

클래스가 메모리에 로드될 때 한 번만 실행되는 문장들의 집합

일반적으로 정적 변수들을 초기화하는 용도로 사용되기 때문에 정적 초기화 블록이라고도 불림

public class Test{
	static int number;
    static String s;
    
    static{ // 정적 블록
    	number = 23;
        s = "Hello World";
    }
    
    public stasic void main (String args[]) {
		System.out.println("number: " +number);
        System.out.println("s: " +s);
}
        

✔️ 싱글톤 패턴(singleton design pattern)

하나의 프로그램 내에서 하나의 인스턴스만을 생성해야 하는 경우에 사용

보통 환경설정 클래스나 혹은 네트워크 연결 풀(Pool), 스레드 풀(Pool)을 관리하는 클래스들같이 전체 시스템을 통틀어서 딱 하나만 존재해야 하는 것들을 사용할 때 사용할 수 있는 디자인 패턴

class Single{
	private static Single instance = new Single();
	private Single() {}
	
	public static Single getInstance()	{
		return instance;
	}
}
public class SingleTest {

	public static void main(String[] args) {
		Single obj1 = Single.getInstance();
		Single obj2 = Single.getInstance();
		
		System.out.println(obj1);
		System.out.println(obj2);

	}

}

여기서는 객체가 하나만 생성됨
이러한 객체를 생성할 때는 new를 사용하지 않고 정적 메소드 getInstance()를 호출하여야 함

싱글톤 패턴에서는 getInstance() 호출이 반복적으로 이루어져도 처음 생성된 객체를 계속해서 반환해줌

instance의 접근 지정자와 생성자 모두 private로 선언되어 있어 외부에서는 getInstance()를 통해서 해당 인스턴스를 얻어서 사용할 수 있음

디자인 패턴?

소프트웨어 디자인 패턴(software design pattern)은 소프트웨어 공학의 소프트웨어 디자인에서 특정 문맥에서 공통적으로 발생하는 문제에 대해 재사용 가능한 해결책이다. 소스나 기계 코드로 바로 전환될수 있는 완성된 디자인은 아니며, 다른 상황에 맞게 사용될 수 있는 문제들을 해결하는데에 쓰이는 서술이나 템플릿이다. 디자인 패턴은 프로그래머가 어플리케이션이나 시스템을 디자인할 때 공통된 문제들을 해결하는데에 쓰이는 형식화 된 가장 좋은 관행이다.


✔️ 객체 배열

객체를 저장하는 배열
정수형 배열에는 정수값이 저장되어 있지만, 객체 배열에는 객체에 대한 참조값이 저장되어 있음

객체 배열을 생성하려면, 먼저 배열을 생성한 후에 각각의 배열 요소를 별도로 생성하여 저장해야 함

class Rect {
	int width, height;

	public Rect(int w, int h) {
		super();
		this.width = w;
		this.height = h;
	}
	double getArea() {return (double)width*height;}
	
}
public class RectArrayTest {

	public static void main(String[] args) {
		
		Rect[] list = new Rect[5];	// 배열 객체 생성
		
		for(int i=0;i<list.length;i++) {
			list[i] = new Rect(i,i);
            // 여기서 나도 모르게 list.Rcet(i,i)로 적었는데 
            // 여기서는 객체를 생성해야 하기 때문에 new 연산자를 사용해야 함
		}
		for(int i=0;i<list.length;i++) {
			System.out.println(i+"번째 사각형의 면적 = "+list[i].getArea());
		}		

	}

}

표준 배열은 크기가 정해지면 변경하기 어려움. 그래서 동적 배열을 많이 사용함

  • ArrayList에 객체 저장
import java.util.ArrayList;

public class ArratListTest {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<String>();
        // ArrayList를 생성할 때는 어떤 객체를 저장할 지 <..> 안에 지정해야 함. 
        // 여기서는 String 객체를 저장한다고 지정함
		list.add("홍콩");
		list.add("싱가포르");
		list.add("괌");
		list.add("사이판");
		list.add("하와이");
		
		System.out.println("여행지 추천합니다.");
		int index = (int) (Math.random()*list.size());
		System.out.println("추천 여행지는 "+list.get(index));		

	}

}

ArrayList 객체 추가 => .add()를 사용
ArrayList 객체 추출 => .get()을 호출

profile
자자 선수입장~

0개의 댓글