Java

[Java] 4주차 복습 - Chap 07, 08, 09

공부하는 나무꾼 2022. 1. 6. 20:51

Chap 07. 클래스와 인스턴스

07-1 클래스의 정의와 인스턴스 생성

프로그램의 기본 구성

BankAccount라는 프로그램의 

데이터 : balance(잔액), amount

기능 : 입금, 출금, 예금 조회

함수 단위로 정의된 데이터와 기능들을 새로운 단위로 묶은 것이 Class!

같은 데이터를 공유하는 기능들을 묶어서 사용하는 것이 생산성이 높기 때문에 class를 생성 (재사용성을 높인다.)

클래스 => (사용을 위한)객체 = 인스턴스

클래스에서 정의되었던 클래스 변수, 클래스 메소드를 => 인스턴스가 생기면서 인스턴스 변수, 인스턴스 메소드가 생성된다.

 

new를 통해 인스턴스를 생성하게 되면, 메모리에만 잡혀있게되고 해당 메모리를 가리키는 것이 없다.

이때, 참조변수가 인스턴스를 참조할 수 있도록 가리키면 이제 해당 인스턴스에 접근하여 사용할 수 있다!

참조변수 : new를 통해 생성된 인스턴스를 가리키는 변수
- 참조 : c, c++의 포인터는 주솟값을 직접 받아서 메모리에 access하지만, 자바에서는 jvm이 객체마다 reference값을 생성해준다. 따라서 참조변수가 ref를 호출하면 mapping되는 객체의 메모리를 사용할 수 있게된다.
(메모리에 직접 접근하여 생기는 위험을 줄이기 위하여, jvm이 생성해준 ref를 통해 인스턴스를 생성한다.)
- 변수 : 가리키는 대상을 바꿀 수 있음(상수가 아님)

참조변수의 특성

- 참조변수는 인스턴스의 기능, 데이터를 직접 엑세스 할 수 있다.

-  참조변수가 가리키는 대상을 바꿀 수 있다.  

BankAccount Lee = new BankAccount();
...
Lee = new BankAccount();	//Lee가 새 인스턴스를 참조한다.
...				//이때, Lee가 참조했던 첫번째 인스턴스는 메모리상의 쓰레기가 되는데
				//이를 jvm의 가비지콜렉터가 작동하여 해당 쓰레기를 제거한다.

 

참조변수의 매개변수 선언

-ref와 acc모두 참조값을 받았으므로, 동일한 인스턴스를 가리킨다.

 

참조변수에 null 대입

- ref가 참조하는 인스턴스와의 관계를 끊음

BankAccount ref1 = new BankAccount();
BankAccount ref2 = new BankAccount();
...
ref1 = null;			//ref가 참조하는 인스턴스와의 관계를 끊음

BankAccount ref2 = null;
if (ref == null)		//ref가 참조하는 인스턴스가 없다면
...				//(null 저장 유무에 대한 비교연산가능)

07-2 생성자와 String 클래스의 소개

문자열을 메소드의 인자로 전달할 수 있다.

매개변수로 String형 참조변수를 선언하여 문자열을 인자로 전달받을 수 있다.

String 클래스에 대한 첫 소개

더보기
더보기

contant pool에 "Happy"와 "Birthday" 인스턴스가 생성된다.

str1 → "Happy"

str2 → "Birthday"

 

참조변수 yoon과 park로 두개의 인스턴스를 생성했을 때, 

BankAccount yoon = new BankAccount;
BankAccount park = new BankAccount;

왼쪽의 클래스 정의는

- 인스턴스 내의 정보로는 해당 정보(balance)가 누구의 데이터인지 식별이 되지 않는다. (기능과 잔액뿐임)

 

반면에, 오른쪽의 클래스 정의는

- 계좌번호(accNumber)와 주민번호(accNumber)를 통해 해당 인스턴스 데이터의 주인이 누군지 식별할 수 있다.

 

생성자의 이름은 클래스의 이름과 동일하게 만든다!

new BankAccount(809, 000314, 10000);	//매개변수가 3개인 생성자 호출(데이터 초기값으로 인스턴스생성)
new BankAccount();			//매개변수가 없는 디폴트 생성자 호출(인스턴스 생성)

 

07-3 자바의 이름 규칙

클래스의 이름의 첫 문자는 대문자로 시작한다.

둘 이상의 단어가 묶여서 하나의 이름을 이룰 때, 새로 시작하는 단어는 대문자로 한다. (변형된 Camel Case 모델)

 

ex) 

Add + Your + Money = addYourMoney

Your + Age = yourAge

 

상수의 이름 규칙

상수의 이름은 모든 문자를 대문자로 구성한다.

둘 이상의 단어가 묶여서 하나의 이름을 이룰 때 단어 사이를 언더바로 연결한다.

 

ex)

final int COLOR_RAINBOW = 7;


 

Chap 08. 패키지와 클래스 패스

08-1 클래스 패스

클래스패스란? 자바 가상머신의 클래스 탐색 경로

물리적으로 떨어져있는 위치를 연결시킨다. 

절대 경로 VS 상대경로

더보기
더보기

절대경로 : 루트 디렉토리를 시작으로 지정한 경로

C:\PackageStudy>set classpath=.;C:\PackageStudy\MyClass

더보기
더보기

상대경로 : 현재 디렉토리를 기준으로 지정한 경로 

C:\PackageStudy>set classpath=.;.\MyClass

 

08-2 패키지의 이해

▶공간적, 접근적 충돌 해결을 위한 패키지 선언

클래스 접근 방법의 구분

- 서로 다른 패키지의 두 클래스는 인스턴스 생성 시 사용하는 이름이 다르다.

 

클래스의 공간적인 구분

- 서로 다른 패키지의 두 클래스 파일은 저장되는 위치가 다르다.

(컴파일 과정에서, 클래스 파일이 저장되어야하는 위치를 상대적으로 결정이 된다. 그리고 이렇게 결정된 위치는 컴파일 이후에 바꿀 수 있다.)

 

패키지 선언에 따른 문제 해결

 

패키지 선언이 필요한 상황의 연출. 내용은 다른데, 클래스 이름이 동일한 경우

더보기
더보기

com.wxfx.smart.Circle c1 = new com.wxfx.smart.Circle(3.5);

com.fxmx.simple.Circle c2 = enw com.fxmx.simple.Circle(5.5);

으 이제 그만하고싶다.......... 노잼.... 이 내용좀 건너뛸래요.....

 

클래스 하나에 대한 import 선언

imort 명령어를 통해 명명을 해놓으면, Circle이라고 불러도 해당 패키지 위치에 있는 Circle 클래스를 불러다 쓸 수 있다.

( 동일한 이름의 두 클래스를 동시에 import하면 컴파일 오류가 발생한다.)

 

더보기
더보기

패키지 전체에 대해 import 하려면 

import com.wxfx.smart.*;        //com.wxfx.smart 패키지로 묶인 전체 클래스에 대한 패키지 선언


Chap 09. 정보 은닉 그리고 캡슐화

09-1 정보 은닉

(1) 정보를 은닉해야 하는 이유

우선, 위의 Circle 클래스를 분석해보면

Circle 생성자 함수 - 인스턴스를 할때 반지름 길이를 인자로 받아 setRad 함수의 인자로 넣어준다.

setRad 함수 - 생성자 함수에서 호출되어, rad의 값을 초기화해준다. 이때, r이 0보다 작으면 return으로 끝낸다.

getArea 함수 - main에서 호출되면 해당 값을 반환해준다. 

 

문제점 : c.rad = -4.5로 인스턴스변수에 직접 접근하여 값을 할당하였을 경우, 생성자를 호출하면서 초기화한 경우와 달리 컴파일 오류가 발생되지 않는다. (c.rad = 4.5로 초기화 된다)

 

(2) 정보 은닉을 위한 private 선언

private 선언을 해줌으로써 변수 rad를 Circle 클래스 안에서만 사용할 수 있도록 만든다. 즉, setter함수와 getter 함수 내에서만 private 변수를 접근할 수 있게 만들기 때문에 데이터를 안전하게 관리할 수 있게 된다. 

 

따라서 c.rad = -4.5로 인스턴스 변수에 직접 접근하면 컴파일 오류로 이어진다.(Circle 클래스 밖에서 접근했기 때문에)

 

09-2 접근 수준  지시자

(1) 네 가지 종류의 접근 수준 지시자

(왼쪽으로 갈수록 접근할 수 있는 범위가 넓다.)

더보기
더보기

public : 모든 범위에서 사용이 가능하다.

protect : 상속받은 상속자들만 사용이 가능하다. (자식 class)

default : 같은 폴더(패키지) 안에서만 사용이 가능하다. 명시하지 않아도 사용이 가능하다.

private : 가장 강력한 접근제한으로, 같은 class 내에서만 사용이 가능하다. 

더보기
더보기

클래스 정의 대상 : public, default

인스턴스 변수와 메소드 대상 : public, protected, default, private

 

(2) 클래서의 public, default 선언 관련 예

public 클래스는 어디에서든지 접근이 가능하므로, 이름이 중요하다.

=> Duck.java가 아니라 Dog.java 가 돼야한다. (하나의 소스파일에는 public class가 단 하나만 존재 가능!)

 

Dog.java

package zoo

class Duck {			//디폴트 클래스이기때문에 zoo내에서만 접근 가능
    public void makeSound() {
	System.out.println("Quack~");
    }
}

public class Dog {
    public void makeSound() {
    	System.out.println("Bowwow~");
    }
}

Animal.java

public class Animal {
    public static void main(String[] args) {
	zoo.Dog dog = new zoo.Dog();
	dog.makeSound();		//OK!
	zoo.Duck duck = new zoo.Duck();
	duck.makeSound();		//Error!
    }
}

Dog는 public 클래스이므로, 어디에서든지 접근이 가능하다.

하지만, Duck은 디폴트 클래스이기 때문에 동일 패키지 안에서만 호출이 가능하다. (Animal은 zoo 밖에 있는 class)

 

(3) 인스턴스 멤버의 private 선언이 갖는 의미

class Duck {
    private int numLeg = 2;			//클래스 내부에서만 접근 가능
    
    public void md1() {
	System.out.println(numLeg);		//접근 가능
	md2();
    }
    
    private void md2() {
	System.out.println(numLeg);		//접근 가능
    }
    
    void md3() {
	System.out.println(numLeg);		//접근 가능
	md2();
    }
}

 

09-3 캡슐화

(1) 캡슐화가 무너진 예

(가정: 코감기는 콧물, 재채기, 코막힘을 늘 동반한다.)

약의 복용 순서가 중요하다면 ? 

클래스 SinivelCap, SneezeCap, SunffleCap 의 적용 및 사용 방법이 별도로 존재한다면? 

>>> 사용자는 모든 클래스의 이름과 함수 이름을 알고 있어야 하며, 순서에 맞춰서 불러내야한다.

 

무너진 캡슐화의 결과

(2) 적절한 캡슐화의 예

감기약에 관련된 캡슐로 캡슐화한다! >>> Take()를 부르기만 하면 순서에 맞게 사용할 수 있게 된다.

결과적으로, cap.take()를 호출하기만 하면 자동으로 약을 순서에 맞춰 복용하게된다.

적절한 캡슐화로 인한 코드 수준의 향상

ColdPatient에서는 cap.take() 함수를 호출한다. cap.take() 함수를 호출하려면 SinusCap 인스턴스가 하나 필요하다.

따라서 takeSinus함수의 인자로 SinusCap cap을 받아, 해당 인스턴스의 take() 함수를 사용한다.

 

(3) 포함 관계로 캡슐화 완성하기

 

(클래스 안의 기능들이 복잡할 때)

클래스들은 그대로 유지하면서, 이 클래스들의 인스턴스만 모아놓고 인스턴스의 조치들을 하나의 메소드로 만든다.

>>> 사용자는 SinusCap과 take() 만 호출하여 사용하면 된다.

각각의 조치들을 take() 함수 안에 넣어준다. (처치 내용)

=> 캡슐화 = 은닉의 기능!