▶ 중첩 클래스 및 중첩 인터페이스를 사용하는 이유


- 자바는 객체 지향 프로그램으로 각 클래스가 관계를 맺으며 상호작용을 한다. 어떤 클래스는 많은 클래스와 상호작용을 하기도 하지만, 다른 어떤 클래스는 특정 클래스하고만 상호작용을 하기도 한다. 여러 클래스와 상호작용을 할 때는 해당 클래스를 독립적으로 생성하는 것이 좋지만, 특정 클래스하고만 상호작용을 할 경우 특정 클래스 내부에 해당 클래스를 생성하는 것이 효율적이다.


- 중첩 인터페이스는 해당 클래스와 깊은 상호작용을 하는 구현 클래스를 생성하기 위해 사용된다.




▶ 중첩 클래스(Nested Class)


- 하나의 클래스 내부에 선언된 다른 클래스를 의미한다. 즉, 포함되어지는 클래스이다.


- 두 클래스의 멤버간에 접근이 용이하다. 중첩 클래스는 자신을 포함하는 클래스의 모든 멤버에 접근할 수 있다. 즉, 접근 제한자가 private인 멤버라 할지라도 중첩 클래스는 접근할 수 있다.


- 불필요한 상호작용을 맺은 클래스들을 외부로부터 감춤으로써 코드가 간결해진다.



class ClassName {

class NestedClassName {

...

}

}





▶ 멤버 클래스


- 클래스의 멤버로서 선언되는 중첩 클래스


- 해당 클래스나 객체가 사용 중일 경우 재사용이 가능하다.


- 멤버 클래스도 하나의 클래스이기 때문에 컴파일하면 바이트 코드 파일(~.class)가 생성된다.


멤버 클래스의 바이트 코드 파일 이름 : 바깥클래스명$ 멤버클래스명.class

로컬 클래스의 경우 : 바깥클래스명$1 로컬클래스명.class


- 인스턴스 멤버 클래스


class A {

class B { ... } // A객체를 생성해야 B 중첩 클래스(인스턴스 멤버 클래스)를 사용할 수 있다.

}


  • 중첩 클래스를 포함한 클래스를 생성해야만 해당 중첩 클래스를 사용할 수 있다.
  • 정적 필드와 메소드는 선언할 수 없다.
  • 외부 클래스에서 인스턴스 멤버 클래스를 생성하려면 바깥 클래스를 먼저 선언(객체 생성)해야 한다.
- 정적 멤버 클래스


class A {

static class B { ... } // A 클래스로 바로 접근 가능한 B 중첩 클래스(정적 멤버 클래스)

}


  • 중첩 클래스를 포함한 클래스로 바로 접근 가능한 중첩 클래스
  • 모든 종류의 필드와 메소드를 선언할 수 있다.
  • 바깥 객체를 생성하지 않아도 바로 정적 멤버 클래스를 이용할 수 있다.



▶ 로컬 클래스

- 메소드 내부에서 선언된 중첩 클래스

- 메소드 실행 시에만 사용되며, 메소드가 종료되면 사라진다.

- 로컬 클래스는 접근 제한자(public, private, protected) 및 static을 붙일 수 없다. 메소드 내부에서 사용되므로 접근을 제한할 필요가 없기 때문이다.

- 정적 필드와 메소드를 선언할 수 없다.

- 로컬 클래스가 선언된 메소드는 new 연산자를 통해 객체를 생성해야 해당 로컬 클래스를 사용할 수 있다.

- 다음과 같이 비동기 처리를 위한 스레드 객체 생성 시 사용된다.

void method() {

class DownloadThread extends Thread { ... } //로컬 클래스

DownloadThread th = new DownloadThread(); // 선언과 초기화 필수

th.start();

}





▶ 중첩 클래스의 접근 제한


- 멤버 클래스

  • 인스턴스 멤버 클래스는 바깥 클래스의 인스턴스 필드를 통해 객체를 생성하거나 인스턴스 메소드 내부에서 객체를 생성할 수 있지만 정적 필드나 메소드는 해당되지 않는다. 즉, 바깥 클래스의 정적 멤버에 포함될 수 없다.
  • 인스턴스 멤버 클래스 내부에서 바깥 클래스로 접근할 때 모든 필드와 메소드가 가능하다. 즉, 바깥 클래스의 정적 멤버에 접근가능하다.
  • 정적 멤버 클래스는 바깥 클래스의 모든 필드의 초기값으로 혹은 모든 메소드에서 객체를 생성할 수 있다.
  • 정적 멤버 클래스 내부에서는 바깥 클래스의 정적 필드와 메소드에만 접근할 수 있다. 즉, 바깥 클래스의 인스턴스 멤버에 접근할 수 없다.

- 로컬 클래스
  • 로컬 클래스 내부에서는 바깥 클래스로 제한 없이 접근할 수 있다.
  • 로컬 클래스에서 사용되는 매개변수와 로컬 변수는 모두 final 특성(최종값)을 갖는다.
☞ 로컬 클래스의 객체는 메소드 실행이 끝나도 힙 메모리에 남아있으므로 사용할 수 있지만, 메소드의 매개변수 및 로컬변수는 메소드 실행이 끝나면 사라지므로 로컬 객체에서 사용할 경우 에러가 발생한다. 해결 방법으로 컴파일 시 로컬 클래스에서 사용하는 매개변수 및 로컬변수는 로컬 클래스 내부의 기억장소에 두고 사용한다. 그러나 값이 수정되면 복사해 둔 기억장소가 변경되므로 이 문제를 해결하고자 변수를 final로 선언하여 수정을 맞는다. 쉽게 말해, final 로 선언된 매개변수와 로컬변수만 로컬 클래스에서 사용가능하다. 자바 8부터는 final 키워드 없이 선언되어도 여전히 값을 수정할 수 없는 final 특성을 갖는다.

☞ final 키워드의 존재 여부의 차이점은 로컬 클래스의 복사 위치이다. final 키워드가 있을 경우 로컬 클래스를 포함한 메소드 내부에서 지역 변수로 복사된다. 없을 경우 로컬 클래스의 필드로 복사된다.


- 중첩 클래스 내부에서 바깥 클래스의 객체 참조를 얻으려면 아래와 같이 선언해야한다.

바깥클래스명.this.필드명;

바깥클래스명.this.메소드명;




▶ 중첩 인터페이스(Nested Interface)


- 클래스의 멤버로 선언된 인터페이스


- 주로 UI(User Interface) 프로그래밍에서 이벤트를 처리할 때 사용된다. 즉 해당 이벤트를 처리하는 구현 클래스를 만드는 것이다.


class ClassName {

interface NestedInterfaceName {

...

}

}









1. Object-Oriented Programming(객체 지향 프로그래밍)


 - 현실 세계를 모델링하여 소프트웨어도 객체 단위로 개발하는 방법이다.

 - 즉, 자동차도 부품이 있어야 조립되듯이 특정한 기능을 하는 소프트웨어 객체들을 조합하여 자기가 원하는 기능을 구현하는 것을 의미한다.

 - 절차 지향 프로그래밍처럼 데이터보다 함수(문제 해결 절차)에 집중하는 것이 아니라, 데이터와 알고리즘을 함께 고려하여 하나의 객체로 묶어서 하는 방법을 의미한다.


* 자바는 객체 지향 기법을 지원하지만, 절차 지향 기법을 지원하지 않는 것은 아니다. 실제 객체의 내부를 설계할 때 절차 지향 프로그래밍을 이용한다.



2. 객체 지향 프로그래밍의 특징


 - 캡슐화(Encapsulation) : 관련된 데이터와 알고리즘(코드)이 하나로 연관되어 잘 정리되어 있는 것으로 데이터와 알고리즘을 캡슐에 넣어서 포장한다는 것을 의미한다. 자바에서는 이 때 이 캡슐을 클래스라고 부른다.


 - 정보 은닉(Information hiding) : 캡슐화는 내부의 데이터를 캡슐로 보호하는 역할을 한다. 즉, 캡슐화를 통해 데이터를 감추고 외부 세계와의 상호작용은 메소드(함수)를 통해 이루어진다.


 - 상속 : 기존의 코드를 재활용하기 위한 기법으로 이미 작성된 클래스(부모 클래스)를 이어받아서 새로운 클래스(자식 클래스)를 생성하는 기법이다. 즉, 공통적으로 쓰이는 변수나 함수가 있다면, 하나의 클래스로 지정해놓고 세부적으로 변수나 함수를 덧붙여서 그 클래스를 포함하는 새로운 클래스를 작성할 때 사용된다.

예를 들어, Vehicle 이 부모 클래스이고, 나머지 Car, Truck, Bus의 경우 Vehicle의 속성을 물려받은 자식 클래스에 해당한다.


  ┌ Car

ex) Vehicle ─┼ Truck

  └ Bus



 - 다형성 : 객체가 구현한 기능(동작)이 상황에 따라 바뀌는 것을 의미한다. 예를 들어 Animal 클래스에서 speak() 라는 메소드(함수)가 있다면, Animal 클래스를 상속받은 Dog 클래스와 Cat 클래스가 있을 때 speak() 라는 하나의 메소드로 두 가지 동작을 구현할 수 있게 된다.



3. Class(클래스)


 - 객체를 찍어내는 틀 또는 설계도

 - 클래스로부터 만들어지는 각각의 객체를 그 클래스의 인스턴스(instance)라고 한다.

 - 객체를 만드는 과정을 인스턴스화라고한다.

 - 데이터와 알고리즘으로 이루어진다. 

 - 변수(필드)와 함수(메소드 or 생성자)의 기능을 정의한다.

 - 객체는 클래스로부터 new 연산자를 통해 생성되며, new 연산자는 힙(heap) 영역에 객체를 생성시킨 후, 객체의 주소를 리턴한다.

 


4. Object(객체)


 - 클래스를 선언하여 변수와 함수를 상태와 동작으로 구현한 객체를 생성한다.

 - 객체의 상태(state)란 객체의 속성을 의미하고, 객체의 동작(behavior)또는 행동은 객체가 취하는 기능(행위)를 의미한다.

 - 객체 안의 변수를 필드(field)라고 하고, 객체 안의 함수를 메소드(method)라고 부른다. 즉 객체는 필드와 메소드로 이루어져있다.

정리하자면, 필드란 객체의 속성을 나타내고, 메소드란 객체의 동작을 나타낸다.

 - 객체는 힙(heap)이라는 메모리 공간에서 생성된다.

 - 객체의 소멸 : 자바의 실행 환경은 사용이 끝난 객체를 스스로 판별하여 소멸시키고 그 객체가 가지고 있던 자원을 시스템에 반납시킨다. 예시로 객체를 가리키는 참조형 변수가 하나도 사용되지 않거나 소멸되거나 혹은 프로그램에서 의도적으로 null값을 설정했다면, 객체의 사용이 끝났다고 판단할 수 있다.



5. 클래스 선언 시 작성 규칙


 - 하나 이상의 문자로 이루어져야 한다. ex) Car, Sport

 - 첫 번째 글자는 숫자가 올 수 없다. ex) Car, 3Car(X)

 - '$', '_'외의 특수문자는 사용할 수 없다. ex) $Car, _Car, @Car(X)

 - 자바 키워드는 사용할 수 없다. ex) int(X), for(X)



6. 클래스의 구성멤버


 - 필드(Field) : 객체의 고유 데이터, 부품 객체, 상태 정보(속성)을 저장한다. 

  • 선언 형태는 변수(variable)와 비슷하나, 필드를 변수라고 부르진 않는다.
  • 필드는 객체에 소속도니 데이터이므로 객체가 존재하지 않으면 필드도 존재하지 않는다.
  • 변수는 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 실행 종료되면 자동 소멸된다. 그러나 필드는 모든 클래스 내부에서 사용되며, 객체가 소멸되어야 객체와 함께 사라진다.
  • 필드의 선언은 생성자와 메소드 사이나 앞과 뒤에서 존재할 수 있다. 단, 생성자와 메소드 블록 내부에 선언된 것은 필드가 아니라 로컬 변수(local variable)이다.
  • 필드도 변수처럼 자료형(type)이 존재하며, 참조형에는 대표적으로 배열, 클래스, 인터페이스가 올 수 있다.


 - 생성자(Constructor)클래스로부터 new 연산자를 사용하여 객체가 생성될 때 가장 먼저 호출되는 특별한 중괄호 블록(block)이다.

  • 생성자의 역할은 객체 생성 시 초기화를 담당한다.
  • 쉽게 말해서 가장 먼저 실행되는 메소드로 볼 수 있다.
  • 형태는 메소드와 다르다. 생성자의 이름은 무조건 클래스의 이름과 일치해야 하고 리턴타입이 없다.
  • 모든 클래스는 생성자가 반드시 존재하며, 매개변수를 달리하는 생성자 여러 개를 선언할 수 있다. 이것을 생성자 오버로딩이라고 한다.
  • 만약 생성자 선언을 생략하면, 컴파일러는 중괄호 블록 내용이 비어있는 기본 생성자(Default Constructor)를 바이트 코드에 추가한다.


 - 메소드(Method) : 객체의 동작에 해당하는 중괄호 블록(block)이다. 

  • 형태는 C언어의 함수와 비슷하며, 메소드는 호출되면 블록 안의 모든 코드들이 일괄적으로 실행된다. 
  • 메소드의 역할은 객체 간의 데이터 전달의 수단으로 사용된다. 
  • 외부로부터 매개값을 받거나 실행 후 어떤 값을 리턴할 수 있다.
  • 클래스 내부에 매개변수가 다르나 같은 이름의 메소드를 여러 개 선언하는 것을 메소드 오버로딩(overloading)이라고 한다.
  • 메소드 오버로딩의 조건은 매개 변수의 타입, 개수, 순서 중 하나가 달라야 한다. 리턴 타입은 무관하다.



7. 객체의 필드와 메소드 접근


 - 객체의 외부에서 객체에 포함된 멤버(필드와 메소드)를 참조(접근)하려면 도트 연산자(.)를 사용한다.

 - ex) Car 객체의 speed라는 필드를 외부의 객체에서 접근할 때,


class 외부클래스 {

//객체는 참조형 변수로 선언된다. 객체의 주소를 가르키기 때문이다.

Car myCar = new Car(); //객체는 무조건 new 연산자를 통해 생성된다. 대입연산에 관하여 참조형 변수와 기본형 변수는 다르다.


myCar.speed = 100;


}

 - 객체 지향의 개념에서 보면 필드를 외부에서 직접 접근하는 것은 바람직하지 않다. 되도록 객체 내의 필드는 메소드를 통해서 간접적으로 접근하도록 클래스를 설계해야한다.



8. 문자열 객체


 - 문자열은 프로그램에서 많이 자료형으로 문자들의 나열이다. 결론적으로, 자바에서는 문자열을 저장할 수 있는 기본 자료형이 없다. 즉, 문자열은 객체로 취급된다.

 - 문자열은 String 클래스를 이용하여 객체로 생성된다.

 아래의 문장은 "Hello World!" 라는 문자열을 가진 String 클래스의 객체를 생성한 것이다. 이 때, s는 생성된 객체의 주소를 가리키는 참조형 변수이다.


String s = new String("Hello World!); //선언과 동시에 초기화


 - 문자열은 자주 사용되므로 new 연산자를 사용하지 않고 문자열 상수로 표기해도 자동적으로 객체가 생성된다.


String s = "Hello World!";


 - 객체의 메소드 호출 : 도트 연산자(.)를 사용한다.


String s = new String("Hello World!");

int size = s.length(); // 여기서 length()는 String클래스에서 제공하는 메소드이다.


 - 참조 변수끼리의 대입 연산


String s1 = "I am very strong";

String s2 = "You are good boy";


s2 = s1; //객체의 번지를 대입.


여기서 s1과 s2가 가리키고 있던 객체는 서로 다르다. 그러나 아래의 s2에 s1이 가리키는 객체의 번지를 대입하면서 s1과 s2는 같은 String 객체를 가리킨다. 



9. Garbage Collection(쓰레기 수집)


 - 자바 실행 환경이 해당 객체가 더 이상 사용되지 않는 다고 판단되면 소멸시키는 기능

 - stop-the-world : 쓰레기 수집(이하 GC)를 실행하기 위해 자바 가상 기계가 애플리케이션 실행을 멈추는 기능이다. 

stop-the-world가 발생하면 GC를 실행하는 쓰레드를 제외한 나머지 쓰레드는 작업을 모두 중단한다. 그리고 GC작업이 종료된 후에 나머지 쓰레드가 작업을 다시 시작한다.(여기서 쓰레드는 프로그램의 실행흐름을 의미한다.) 어떤 경우라도 이 기능은 무조건 발생한다. 자바에서는 소스 코드에서 메모리를 확실하게 지정하거나 해제하지 않는다. 간혹 명시적으로 해제하는 방법은 해당 객체를 null로 지정하거나 System.gc()메소드를 호출하는 방법이 있으나, 후자의 경우 시스템의 성능에 영향을 크게 주기 때문에 되도록 사용하지 않는 것을 추천한다. 아무튼 자바에서는 개발자가 메모리를 확실히 해제하지 않기 때문에 쓰레기 수집 기능이 객체를 판별하여 소멸시키는 작업을 하는 것이다.





+ Recent posts