[Java] 6. 클래스

2022. 5. 30. 21:50Java

 

제주도,,, 또 가고 싶으면서 가기 싫고 그래,,,

어제 '어떻게 되긴 할까. 뭐 할 수 있는 게 없는 것 같은데 뭘 하지...? 내 인생 답이 있나...?' 하면서 멘탈 와르르 와장창창 바사삭 파사삭 상태였지만 아주 조금 극복하고 '어떻게든 되겠지. 그러니까 어떻게든 되게 뭐라도 하자.' 상태로 돌아왔다. 그러니까 오늘도 뭐라도 하자.

 

6-1) 객체 지향 프로그래밍

  • 객체
    · 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있으면서 식별 가능한 실체
    · 속성(필드)과 동작(메소드)으로 구성
  • 객체 모델링
    · 현실 세계의 객체를 소프트웨어 객체로 설계하는 것
    · 현실 세계 객체의 속성과 동작을 추려내어 소프트웨어 객체의 필드와 메소드로 정의하는 과정
  1. 객체의 상호작용
    • 객체들은 각각 독립적으로 존재하고 다른 객체와 서로 상호작용하며 동작한다.
    • 객체들 사이의 상호작용 수단은 메소드
    • 메소드 호출: 객체가 다른 객체의 기능을 이용하는 것
    • 메소드 호출의 형태
   리턴값      =      전자계산기객체.     메소드(매개값1, 매개값2, ...);
 int result      =         Calculatoe.            add      (10,20);             //예시
① 객체에 도트(.) 연산자를 붙이고 메소드 이름을 기술하기. 도트 연산자는 객체의 필드와 메소드에 접근할 때 사용.
② 매개값은 메소드를 실행하기 위해 필요한 데이터. 리턴값은 메소드가 실행되고 난 후 호출한 곳으로 돌려주는(리턴하는) 값.

  1. 객체 간의 관계
    • 집합 관계
      - 집합 관계에 있는 객체는 하나는 부품이고 하나는 완성품에 해당.
      - ex. 자동차는 엔진, 타이어, 핸들 등으로 구성되므로 자동차와 부품들은 집합관계.
    • 사용 관계
      - 객체 간의 상호작용을 말함.
      - 객체는 다른 객체의 메소드를 호출하여 원하는 결과를 얻어낸다.
          ex. 사람은 자동차를 사용하므로 사람과 자동차는 사용 관계.
          ex. 사람은 자동차를 사용할 때 '달린다', '멈춘다' 등의 메소드를 호출하는 것.
    • 상속 관계
      - 상위(부모) 객체를 기반으로 하위(자식) 객체를 생성하는 관계.
      - 일반적으로 상위 객체는 종류를 의미하고, 하위 객체는 구체적인 사물에 해당.
          ex. "자동차는 기계의 한 종류이다."에서 기계는 상위, 자동차는 하위의 상속 관계에 있다고 볼 수 있다.
  2. 객체와 클래스
    • 클래스
      - 자바에서의 설계도
      - 객체를 생성하기 위한 필드와 메소드가 정의되어있다.
    • 인스턴스
      - 클래스로부터 만들어진 객체
      - ex. 자동차를 만드는 설계
      ★☆설계도는 클래스, 클래스로 만든 객체는 인스턴스☆★        //사실 아직도 잘 모르것슈,,,,
    • 객체 지향 프로그래밍 개발의 세 가지 단계
      ① 클래스 설계
      ② 설계된 클래스를 가지고 사용할 객체 생성
      ③ 생성된 객체를 이용
  3. 클래스 선언
    • 클래스 이름은 다른 클래스와 식별할 목적으로 사용되므로 자바의 식별자 작성 규칙에 따라 만들어야 한다.
      ① 하나 이상의 문자로 이루어져야 한다.
      ② 첫 글자에는 숫자가 올 수 없다.
      ③ 달러 기호'$'와 언더바'_' 외의 특수문자는 사용 불가.
      ④ 자바 키워드는 사용할 수 없다. (ex. int, for...)
      ⑤ 통상적으로 클래스 이름의 첫 글자를 대문자로 하고 나머지는 소문자로 작성한다.
           두 단어 이상인 경우에는 각 단어의 첫 글자를 대문자로 작성한다. 
    • 소스 파일 이름과 클래스 이름은 대소문자까지 똑같아야 한다.
    • 소스 파일 하나에 여러 클래스를 선언할 수 있지만 되도록 하나의 소스파일에는 하나의 클래스를 사용하는 것이 좋다.
  4. 객체 생성과 클래스 변수
    • 클래스로부터 객체를 생성하려면 new 연산자를 사용한다.
      - new 연산자는 클래스로부터 객체를 생성시키는 연산자.
      - new 연산자 뒤에는 생성자가 오는데 생성자는 클래스() 형태를 가지고 있다.
      - new 연산자는 heap 영역에 객체를 생성시킨 후 객체의 번지를 리턴하고 이 주소를 참조 타입인 클래스 변수에 저장해두면 변수를 통해 객체를 사용할 수 있게 된다.
      -   ex. 클래스명    변수명   =   new   클래스명();
  5. 클래스의 구성 멤버
    • 클래스에는 객체가 가져야 할 구성 멤버가 선언된다.
    • 구성 멤버들은 생략되거나 복수의 개수로 작성될 수 있다.
      • 필드
        - 객체의 데이터가 저장되는 곳으로 객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳.
        - 선언 형태는 변수와 비슷하지만 필드를 변수라고 부르지는 않는다.
        - 변수는 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 실행 종료되면 자동으로 소멸되지만 필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재한다는 점에서 차이가 있다.
      • 생성자
        - new 연산자로 호출되는 특별한 중괄호{} 블록
        - 객체 생성 시 초기화를 담당한다.
        - 필드를 초기화하거나 메소드를 호출하여 객체를 사용할 준비를 한다.
        - 생성자는 메소드와 비슷하게 생겼으나 클래스 이름으로 되어있고 리턴 타입이 없다.
      • 메소드
        - 객체의 동작에 해당하는 중괄호{} 블록.
        - 메소드를 호출하게 되면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행된다.
        - 메소드는 필드를 읽고 수정하는 역할도 하지만 다른 객체를 생성하여 다양한 기능을 수행하기도 한다.
        - 메소드는 객체 간의 데이터를 전달하는 수단.
        - 외부(호출한 곳)로부터 매개값을 받아 실행에 이용하고, 실행 후 결과 값을 외부(호출한 곳)로 리턴할 수도 있다.

6-2) 필드

  - 객체의 고유 데이터, 객체가 가져야 할 부품, 객체의 현재 상태 데이터를 저장하는 곳.

  1. 필드 선언
    • 필드 선언은 클래스 중괄호{} 블록 어디서든 존재할 수 있다.
      - 생성자와 메소드 중괄호의 내부에 선언한 것은 모두 필드가 아닌 로컬 변수가 된다.
    • 초기값이 지정되지 않은 필드는 객체 생성 시 자동으로 해당 타입의 기본 초기값이 설정된다.
      - 정수 타입 필드: 0
      - 실수 타입 필드: 0.0
      - boolean 필드: false
      - 참조 타입 필드: (객체를 참조하고 있지 않은 상태인) null
  2. 필드 사용
    • 필드를 사용한다. = 필드값을 읽고 변경하는 작업을 수행한다.
    • 클래스 내부의 생성자나 메소드에서 필드를 사용할 경우 단순히 필드 이름으로 읽고 변경하면 되지만
      클래스 외부에서 사용할 경우 우선적으로 클래스로부터 객체를 생성한 뒤 필드를 사용해야 한다.
      - 필드가 객체에 소속된 데이터이므로 객체가 존재하지 않으면 필드도 존재할 수 없다. 

객체 생성 안해서 주소를 모르는데 어떻게 클래스로 가요! 라고 혼자서 생각하려고 한다. (맞는지는 모름)

6-3) 생성자  

  - 생성자: new 연산자로 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당.

  - 객체 초기화: 필드를 초기화하거나 메소드를 호출해서 객체를 사용할 준비를 하는 것.

  - 생성자를 실행하지 않고는 클래스로부터 객체를 만들 수 없음.

  - new 연산자에 의해 생성자가 성공적으로 실행되면 heap 영역에 객체가 생성되고 객체의 번지가 리턴된다.

  - 리턴된 객체의 번지는 클래스 변수에 저장.

  1. 기본 생성자
    • 클래스 내부에 생성자 선언을 생략한 경우 컴파일러는 '[public] 클래스명() {}'과 같이 중괄호 블록 내용이 비어있는 기본 생성자를 바이트 코드에 자동 추가한다.
    • 클래스 내부에 명시적으로 선언한 생성자가 1개라도 있는 경우 컴파일러는 기본 생성자를 추가하지 않기 때문에 따로 작성해주어야 한다. 
  2. 생성자 선언
    • 생성자는 메소드와 비슷한 모양을 가지고 있으나 리턴타입이 없고 클래스 이름과 동일하다.
    • 생성자 블록 내부에는 객체 초기화 코드가 작성된다.
      - 일반적으로 필드에 초기값을 저장하거나 메소드를 호출하여 객체 사용 전에 필요한 준비를 한다.
      ex.    클래스명 ( 매개변수선언, …){
                        //객체의 초기화 코드
                 }
    • 매개 변수 선언은 생략할 수도 있고 필요에 따라 여러 개를 선언할 수도 있다.
    • 매개 변수는 new 연산자로 생성자를 호출할 때 외부의 값을 생성자 블록 내부로 전달하는 역할을 한다.
    • 클래스에 생성자가 명시적으로 선언되어 있을 경우에는 반드시 선언된 생성자를 호출해서 객체를 생성해야 한다.
  3. 필드 초기화
    • 클래스로부터 객체가 생성될 때 필드는 기본 초기값으로 자동 설정된다.
    • 다른 값으로 초기화 하는 방법
      ① 필드를 선언할 때 초기값을 주는 방법
      - 동일한 클래스로부터 생성되는 객체들은 모두 같은 값을 갖게 된다. (후에 초기값 변경 가능)
      ② 생성자에서 초기값을 주는 방법
      - 객체 생성 시점에 외부에서 제공되는 다양한 값들로 초기화되어야 한다면 생성자에서 초기화 해야 한다.
    • this.
      - 매개 변수와 객체 자신이 가지고 있는 변수의 이름이 같은 경우 이를 구분하기 위해 this를 붙인다.
  4. 생성자 오버로딩
    • 매개 변수를 달리하는 생성자를 여러 개 선언하는 것을 말한다.
    • 다양한 방법으로 객체를 생성할 수 있도록 한다.
    • 같은 클래스 내에서 같은 이름의 생성자명을 여러 개 선언하는 것으로 매개 변수의 타입과 개수, 그리고 선언된 순서가 다르면 된다.
  5. 다른 생성자 호출: this()
    • 자신의 다른 생성자를 호출하는 코드로 반드시 생성자의 첫 줄에서만 허용된다.
    • this()의 매개값은 호출되는 생성자의 매개 변수에 맞게 제공해야한다.

6-4) 메소드

  ex.    리턴타입     메소드이름  ([매개변수선언, …]){

                           실행할 코드 작성하는 곳

           }    

  1. 메소드 선언
    • 리턴 타입: 메소드를 실행한 후의 결과값인 리턴값의 타입
      - void: 리턴값이 없는 어떠한 기능만 수행하는 경우 (ex. 전원을 켠다.)
      - 리턴값이 있는 메소드는 리턴값의 타입을 적고 메소드 실행 블록 내에서 return문을 작성해야한다. (ex. 덧셈을 한다.)
    • 메소드 이름: 메소드의 기능이 드러나도록 식별자 규칙에 맞게 이름을 정한다.
      - 숫자로 시작하면 안되고, $와 _를 제외한 특수 문자는 사용할 수 없다.
      - 관례적으로 메소드 이름은 소문자로 작성한다.
      - 서로 다른 단어가 혼합된 이름이라면 뒤이어 오는 단어의 첫 글자는 대문자로 작성한다.
    • 매개 변수 선언: 메소드를 실행할 때 외부로부터 필요한 데이터를 받기 위한 변수를 선언한다.
      - 매개 변수는 필요에 따라 개수가 달라지므로 존재하지 않거나 여러 개가 존재할 수 있다.
    • 메소드 실행 블록: 실행할 코드를 작성한다.
  2. 리턴(return)문
    • 리턴값이 있는 메소드
      - 메소드 선언에 리턴 타입이 있는 메소드는 반드시 return문을 사용하여 리턴값을 지정해야 한다.
      - return 문이 없다면 컴파일 에러가 발생하고 return문이 실행되면 메소드는 즉시 종료된다.
      -return문의 리턴값은 리턴 타입이거나 리턴 타입으로 변환될 수 있어야 한다.
    • 리턴값이 없는 메소드: void
      - 리턴값이 없는 메소드는 리턴 타입으로 void를 사용.
      - void로 선언된 메소드 내에서 return문을 사용하면 메소드 실행을 강제 종료시키는 역할을 한다.
  3. 메소드 호출
    • 객체 내부에서 호출
      ≫   메소드(매개값, … );
      - 클래스 내부에서 다른 메소드를 호출할 경우로 메소드가 매개 변수를 가지고 있을 때에는 매개 변수의 타입과 수에 맞게 매개값을 제공해야 한다.
      ≫    타입 변수 = 메소드 (매개값, … );
      - 리턴값이 있는 메소드를 호출하고 리턴값을 받고 싶다면 변수를 선언하고 리턴값을 대입한다.
      - 이때 변수 타입은 메소드 리턴 타입과 동일하거나 자동 타입 변환이 될 수 있어야 한다.
    • 객체 외부에서 호출
      ≫ 클래스 참조변수 = new 클래스 (매개값, … );
      - 외부 클래스에서 메소드를 호출하려면 클래스로부터 객체를 생성해야한다. (메소드는 객체에 소속된 멤버이므로 객체가 존재하지 않으면 메소드도 존재하지 않기 때문.)
      ≫참조변수.메소드(매개값, … );           //리턴값이 없거나 있어도 리턴값을 받지 않는 경우
      ≫타입 변수 = 참조변수.메소드(매개값, … );          //리턴값이 있고 리턴값을 받고 싶은 경우
      - 객체가 생성되었다면 참조 변수와 함께 도트(.) 연산자를 사용하여 메소드를 호출할 수 있다.
      - 도트(.)연산자는 객체 접근 연산자로 객체가 가지고 있는 필드나 메소드에 접근할 때 사용된다.
  4. 메소드 오버로딩
    • 클래스 내에 같은 이름의 메소드를 여러 개 선언하는 것을 메소드 오버로딩이라고 한다.
    • 메소드 오버로딩의 조건은 매개 변수의 타입, 개수, 순서 중 하나가 달라야 한다.
      (매개변수의 이름이 다르다고 오버로딩은 아니니 주의.)
    • 매개값을 다양하게 받아 처리할 수 있다.

6-5) 인스턴스 멤버와 정적 멤버

  1. 인스턴스 멤버와 this
    • 인스턴스멤버
      - 객체를 생성한 후 사용할 수 있는 필드와 메소드로 각각 인스턴스 필드, 인스턴트 메소드라고 부른다.
      - 인스턴스 필드와 메소드는 객체에 소속된 멤버이기 때문에 객체 없이는 사용할 수 없다.
    • this
      - 주로 생성자와 메소드의 매개 변수 이름이 필드와 동일할 때 인스턴스 멤버인 필드임을 명시하고자 할 때 사용.
  2. 정적 멤버와 static
    • 정적 멤버: 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메소드.
    • 정적 멤버 선언
      - 선언 시 static 키워드를 추가적으로 앞에 붙인다. 
      - 객체마다 가지고 있어야 할 데이터라면 인스턴스 필드로, 객체마다 가지고 있을 필요가 없는 공용 데이터라면 정적 필드로 선언한다.
      - 메소드의 경우 인스턴스 필드를 포함하고 있으면 인스턴스 메소드로, 포함하고 있지 않다면 정적 메소드로 선언
    • 정적 멤버 사용
      - 클래스가 메모리로 로딩되면 정적 멤버를 바로 사용할 수 있게 되고 클래스 이름과 함께 도트(.)연산자로 접근한다.
      ex.   클래스.필드;
              클래스.메소드(매개값, … );
    • 정적 메소드 선언 시 주의할 점
      - 객체가 없어도 실행된다는 특징 때문에 정적 메소드를 선언할 때는 이들 내부에 인스턴스 필드나 인스턴스 메소드를 사용할 수 없다.
      - 정적 메소드에서 인스턴스 멤버를 사용하고자 할 때에는 객체를 먼저 생성하고 참조 변수로 접근해야 한다.
  3. 싱글톤
    • 전체 프로그램에서 단 하나의 객체만 만들도록 보장하는 것.
    • 클래스 외부에서 new 연산자로 생성자를 호출할 수 없도록 막아야 하기 때문에 생성자 앞에 private 접근 제한자를 붙여준다. 
    • 자신의 타입인 정적 필드를 하나 선언하고 자신의 객체를 생성해 초기화한다.
    • 외부에서 객체를 얻는 방법=getInstance() 메소드를 호출하기.
      - getInstance()는 한 번에 단 하나의 객체만 리턴한다.
  4. final 필드와 상수
    • final 필드
      - final 필드는 초기값이 저장되면 이것이 최종적인 값이 되어 프로그램 실행 도중 수정할 수 없다.
    • final 필드의 초기값을 줄 수 있는 방법
      ① 필드 선언 시에 주는 방법
      - 단순 값일 때 좋은 방법
      ② 생성자에서 주는 방법
      - 복잡한 초기화 코드가 필요하거나 객체 생성 시에 외부 데이터로 초기화해야할 때
    • 생성자는 final 필드의 최종 초기화를 마쳐야 한다.
      - 초기화하지 않은 final 필드를 그대로 남겨두면 컴파일 에러 발생
    • 상수
      - 일종의 불변의 값. (ex. π, 지구의 무게·둘레)
      - static(공용)이면서 final(객체마다 저장할 필요가 없음)
      - static final 필드는 객체마다 존재하지 않고 클래스에만 존재하며 한 번 초기값이 저장되면 변경할 수 없다.
      - 상수 이름은 모두 대문자로 작성하는 것이 관례이고 서로 다른 단어가 혼합된 이름이라면 언더바(_)로 단어들을 연결해준다.

6-6) 패키지와 접근 제한자

  1. 패키지 선언
    • 클래스를 작성할 때 해당 클래스가 어떤 패키지에 속할 것인지를 선언하는 것
    • 패키지는 클래스의 일부이므로 만약 클래스를 이동해야한다면 패키지 전체를 이동시켜야 한다.
    • 패키지 명명 규칙
      - 숫자로 시작해서는 안되고 _,$ 외의 특수문자는 사용 불가.

      - java로 시작하는 패키지는 자바 표준 API에서만 사용하므로 사용해서는 안된다.
      - 모두 소문자로 작성하는 것이 관례
    • import문
      - 사용하고자 하는 클래스 또는 인터페이스가 다른 패키지에 소속되어있을 때 import문으로 해당 패키지의 클래스나 인터페이스를 가져와 사용할 것임을 컴파일러에게 알려야 한다.

      - import 문은 패키지 선언과 클래스 선언 사이에 작성한다.
      - 사용하고자 하는 클래스들이 동일 패키지 소속이라면 개별로 작성하는 것보다 *를 이용하여 해당 패키지에 소속된 클래스들을 사용할 것임을 명시하는 것이 좋음.

      - 상위 패키지를 import했다고 하여 하위 패키지까지 import되는 것은 아님.
  2. 접근 제한자
    • public 접근 제한자: 외부 클래스가 자유롭게 사용할 수 있도록 한다.
    • protected 접근 제한자: 같은 패키지 혹은 자식 클래스에서 사용할 수 있도록 한다.
    • private 접근 제한자: 외부에서 사용될 수 없도록 한다.
    • default 접근 제한: 위 세 가지 접근 제한자를 적용하지 않으면 적용되는 접근 제한으로 같은 패키지에 소속된 클래스에서만 사용 가능.
  3. 생성자의 접근 제한
    • public 접근 제한: 모든 패키지에서 아무런 제한 없이 생성자를 호출할 수 있도록 한다.
    • protected 접근 제한: 같은 패키지에 속하는 클래스에서 생성자를 호출할 수 있도록 한다. 다른 패키지에 속한 클래스가 해당 클래스의 자식 클래스라면 생성자를 호출할 수 없도록 한다.
    • private 접근 제한: 동일한 패키지이건 다른 패키지이건 관계없이 생성자를 호출할 수 없도록 제한한다. 클래스 내부에서만 가능.
  4. 필드와 메소드의 접근 제한
    • public 접근 제한: 모든 패키지에서 아무런 제한 없이 필드와 메소드를 사용할 수 있도록 한다.
    • protected 접근 제한: 같은 패키지에 속하는 클래스에서 필드와 메소드를 사용할 수 있도록 한다. 다른 패키지에 속한 클래스가 해당 클래스의 자식 클래스라면 필드와 메소드를 사용할 수 있다.
    • default 접근 제한: 필드와 메소드 선언 시 접근 제한자를 생략하면 적용되는 접근 제한으로, 같은 패키지에서는 아무런 제한 없이 필드와 메소드를 사용할 수 있으나 다른 패키지에서는 필드와 메소드를 사용할 수 없도록 한다.
    • private 접근 제한: 동일한 패키지이건 다른 패키지이건 다른 패키지이건 상관없이 필드와 메소드를 사용하지 못하도록 제한한다. 오직 클래스 내부에서만 사용 가능.
  5. Getter(읽기)와 Setter(쓰기) 메소드
    • 객체지향 프로그램에서는 객체 외부에서 객체의 필드를 직접적으로 접근하는 것을 막기 위해 별도의 메소드를 통해 필드를 변경하는 방법을 사용한다. 외부에서 마음대로 변경할 경우 객체의 무결성이 깨질 수 있기 때문. 
    • 필드는 외부에서 접근할 수 없도록 막고 메소드는 공개해서 외부에서 메소드를 통해 필드에 접근하도록 유도한다.
      = 메소드는 매개값을 검증해서 유효한 값만 객체의 필드로 저장할 수 있기 때문
    • 외부에서 객체의 데이터를 읽을 때도 메소드를 사용하는 것이 좋다.
      =필드값을 직접 사용하면 부적절한 경우도 있기 때문.
    • 필드 타입이 boolean일 경우에는 Getter는 get으로 시작하지 않고 is로 시작하는 것이 관례.

'Java' 카테고리의 다른 글

[Java] 8. 인터페이스  (0) 2022.06.02
[Java] 7. 상속  (0) 2022.06.02
[Java] 5. 참조 타입  (0) 2022.05.26
[Java] 4. 조건문과 반복문  (0) 2022.05.26
[Java] 3. 연산자  (0) 2022.05.23