백엔드/JAVA

객체 지향 프로그래밍 이론(1)

두개의 문 2023. 5. 3. 20:20
클래스 선언

 

- 클래스명 작성 규칙

 ① 하나 이상의 문자로 구성

 ② 첫 글자에는 숫자가 올 수 없음

 ③ '$', '_'외의 특수문자 사용 불가

 ④ 자바 키워드 사용 불가

 

- 보통 하나의 소스파일에 하나의 클래스만을 정의하지만, 둘 이상의 클래스를 정의하는 것도 가능

  단, 소스파일의 이름(.java)은 반드시 public class의 이름과 일치해야 함

  ( 소스파일 내에 public class가 없는 경우, 소스 파일의 이름은 어떤 클래스 이름을 사용해도 무관 )

 

- 클래스 이름을 고쳐야 될 때 

   ① Package Explorer 뷰의 파일 클릭 → 마우스 오른쪽 클릭

   ② Refactor → Rename : 새로운 이름 설정

   ③ next 눌러서 확인 → Finish

새로운 이름 설정 후, next 눌러서 변경될 내용 확인

 

 


객체 생성과 클래스 변수

 

- 클래스 선언은 설계도를 작성한 것일 뿐, 클래스로부터 객체를 생성해야 사용할 수 있음

 

▶ new 연산자 + 생성자

 - new

  ① 객체를 생성시키는 연산자 

  ② new 연산자로 생성된 객체는 Heap 영역에 생성시킨 후, 객체의 번지를 리턴 → 참조변수에 저장

     ∴ 참조변수에 저장된 객체의 주소를 이용해 객체 사용 가능

 - 생성자 

  ① new 연산자에 의해 호출 → 객체 생성 시 초기화 담당

  ② 쿨래스 이름과 동일

  ③ 리턴 타입 없음

 

① 클래스의 객체를 참조하기 위한 참조변수 선언                     클래스명 변수명 ;
 클래스의 객체 생성 후, 객체의 주소를 참조변수에 저장        변수명 = new 클래스명();

                                                                                            → 클래스명 변수명 = new 클래스명();

⇒ 정리해보자면,

   new 연산자에 의해 객체가 생성되고, 객체가 생성될 때마다 생성자가 호출된다.

   호출된 생성자에 의해 인스턴스 초기화가 되고, 참조변수에는 객체의 주소가 저장됨

 

 

→ s1과 s2가 참조하는 Student 객체는 완전히 독립된 서로 다른 객체

 

▷ Student / StudentApp의 클래스 용도

 ① 라이브러이용 클래스 : class Student

   : 다른 클래스에서 이용할 목적으로 설계  

 ② 실행 클래스 : class StudentApp

  : 프로그램의 실행 진입점인 main() 메소드를 제공하는 역할

→ 물론 하나의 클래스 내에 라이브러리 클래스와 실행 클래스를 동시에 생성 가능하지만,

   대부분의 객체 지향 프로그램은 라이브러리 클래스와 실행 클래스를 분리시킴

 

 

 


클래스의 구성 멤버
public class ClassName {
   ① 필드 ( Field )
   int fieldname;
   ② 생성자 ( Constructor )
   ClassName();
   ③ 메소드 ( Method )
   void methodName() { … }
}

   ① 필드 ( Field )

     - 객체의 데이터가 저장되는 곳 

     - 필드 vs 변수

      · 변수 : 생성자와 메소드 내에서만 사용 → 생성자와 메소드가 종료 시 자동 소멸됨 ( 변수의 scope )

      · 필드 : 생성자와 메소드 전체에서 사용 / 객체가 소멸되지 않은 한 객체와 함께 존재
   ② 생성자 ( Constructor )

    - 객체가 생성될 때마다 new 연산자에 의해 호출 → 객체의 초기화 담당

    - 클래스 이름과 동일하고, 리턴타입 없음 

   ③ 메소드 ( Method )
    - 객체의 동작에 해당

    - 메소드 호출 시, 메소드의 중괄호 블록 내 모든 코드들이 일괄적으로 실행

      → 객체 간의 데이터 전달하는 수단 : 외부로부터 매개값을 받아 실행에 이용한 후, 결과값을 호출한 메서드로 다시 리턴함 

 

 

 

 


필드

- 필드 : 객체의 데이터가 저장되는 곳

  → 객체의 고유 데이터, 객체가 가져야 할 부품, 객체의 현재 상태 데이터를 저장

      즉, 클래스 설계 시, 이 정보들은 필드에 선언되어야 함

 

▶ 필드 선언

 - 클래스 중괄호 { } 블록 어디서든 선언 가능

   단, 생성자와 메소드 중괄호 { } 블록 내부에 선언 시, 모두 로컬 변수가 됨 

 타입 필드 = 초기값 ; 

- 타입 : 필드에 저장할 데이터의 종류

  ① 기본 타입 : byte, short, int, long, float, double, char, boolean

  ② 참조 타입 : 배열, 열거, 인터페이스

 

- 초기값 : 필드 선언 시 주어질 수도 있고 생략될 수도 있음

  → 초기값이 지정되지 않은 필드는 객체 생성 시 자동으로 기본 초기값으로 설정됨

분류 타입 초기값
기본 타입 정수 타입 byte
char
short
int
long
0
\u0000(빈 공백)
0
0
0L
실수 타입 float
double
0.0F
0.0
논리 타입 boolean false
참조 타입 배열
클래스(String 포함)
인터페이스
null
null
null

※ null : 객체를 참조하고 있지 않은 상태를 의미

 

▶ 필드 사용

  : 필드값을 읽고 변경하는 작업을 의미

  ① 클래스 내부의 생성자나 메소드에서 사용할 경우

    → 필드 이름으로 읽고 변경

  ② 클래스 외부에서 사용할 경우

    → 객체 생성한 뒤, 필드 사용

 

  

 

 


생성자

 

- 생성자 ( Constructor )  : 인스턴스가 생성될 때 호출되는 인스턴스 초기화 메서드

  · 인스턴스 변수의 초기화 담당

  · 인스턴스 생성 시에 실행되어야 하는 작업을 위해 사용

 

- 생성자의 조건

  ① 생성자의 이름은 클래스 이름과 동일

  ② 리턴값이 없음

  ③ 모든 클래스는 반드시 하나 이상의 생성자를 가져야 함

    → 지금까지 클래스에 생성자를 만들지 않고 객체를 생성할 수 있었던 이유 

        : 클래스 내에 생성자가 하나도 없을 경우, 컴파일러가 자동적으로 기본 생성자를 추가해주기 때문

  ※ 기본 생성자가 컴파일러에 의해서 추가되는 경우는 클래스 내에 정의된 생성자가 하나도 없을 때만 해당

데이터 클래스 실행 클래스
class Data1 {
       int value;
}
// Data1 클래스에 정의된 생성자가 하나도 없으므로,
컴파일러에 의해 자동적으로 기본 생성자가 추가됨

class Data2 {
       int value;

       Data2 ( int x ) {
            value = x;
       }
}
// Data2에는 기본생성자가 정의되어 있지 않음
class DataApp {
        public static void main( String [] args ) {
               Data1 d1 = new Data1();
               Data2 d2 = new Data2();
               // 컴파일 에러 : The constructor Data2 () is undefined
         }
}

→ 에러 해결 방안
1. Data2에 기본 생성자 추가
2. Data2( int x ) 생성자 사용

 

- 생성자 또한 오버로딩 가능 → 하나의 클래스에 여러 개의 생성자 존재

· 생성자 오버로딩 : 매개변수를 달리하는 생성자를 여러 개 선언하여 다양한 객체 생성 가능

  → 매개변수의 타입, 개수, 순서를 다르게 선언

· new 연산자로 생성자를 호출할 때, 제공되는 매개값의 타입과 수에 의해 호출될 생성자 결정

데이터 클래스 실행 클래스
public class Car {
        // 필드 선언
        String company = "현대자동차";

        String model ;
        String color ;

        // ①기본생성자
        Car ( ) { 
        }   

        // ② 매개변수 1개인 생성자 
        Car ( String model ) { 
                 this.model = model;
         } 

         // ③ 매개변수 2개인 생성자
         Car ( String model, String color ) { 
                 this.model = model;
                 this.color = color;
         }

}
public class CarEx {

      public static void main( String [] args ) {
             Car car1 = new Car();                      // ①기본생성자 선택
             System.out.println("car1.company = " + car1.company );

             Car car2 = new Car("그랜저");       // ② 매개변수 1개인 생성자 선택
             System.out.println("car2.company = " + car2.company );
             System.out.println("car2.model = " + car2.model );
 
             Car car3 = new Car("그랜저", "블랙");
                                                                       // ③ 매개변수 2개인 생성자 선택

             System.out.println("car3.company = " + car3.company );
             System.out.println("car3.model = " + car3.model );
             System.out.println("car3.color = " + car3.color);
      }
 }
 - 필드 초기화 방법
   ❶ 필드 선언 시 초기값 설정  → Car 클래스에 의해 설계된 객체의 company 필드에는 모두 "현대자동차"가 저장됨
   ❷ 생성자에서 초기값 설정 → 객체 생성 시점에 매개값을 통해 다양한 값 설정 가능
 출력 결과 )
 car1.company = 현대자동차
 car2.company = 현대자동차
 car2.model = 그랜저
 car3.company = 현대자동차
 car3.model = 그랜저
 car3.color = 블랙

 

▶ 생성자 호출

    ❶ 기본 생성자 호출

데이터 클래스 실행 클래스
class Car {
        // 필드 선언
         String model ;
         String color ;
         int maxSpeed ;


         Car () { }             
       // 기본 생성자 - 생략되어도 현재 이 클래스에는 생성자가 없으므            로 자동적으로 추가해줌

}
public static void main( String [] args ) {
          Car myCar = new Car();              ① 객체 생성 후
          myCar.model = "현대자동차";        ② 객체 초기화
          myCar.color = "검정";
          myCar.maxSpeed = 300;
}

    ❷ 매개변수가 있는 생성자 호출

데이터 클래스 실행 클래스
class Car {
        // 필드 선언
         String model ;
         String color ;
         int maxSpeed ;

         Car ( String m, String c, int s ){
                model = m;

                color = c;
                maxSpeed = s;
         }
}
public static void main( String [] args ) {
          Car myCar = new Car( "현대자동차", "검정", 300 );                   // 객체 생성과 동시에 객체 초기화
        

}

∴ 실행 클래스에서 기본생성자로 호출하는 방법과 매개변수가 있는 생성자 호출하는 방법을 비교했을 때, 후자가 더 간결한 것을 알 수 있다.

   매개변수 있는 생성자의 경우, 1번만 선언해놓으면 실행클래스에서 작성할 코드가 더 간결해지고 데이터 파악이 더 쉬워진다. 

 

 

▶ 객체 자신을 가리키는 참조변수 : this

 - this를 이용해 인스턴스 변수에 접근 가능 / 객체의 주소가 저장되어 있음

 - 생성자를 포함한 모든 인스턴스 메소드에는 자신이 관련된 인스턴스를 가리키는 참조변수 this가 지역변수로 숨겨진 채 존재함

   ( 선언 없이 사용 가능 )

Car ( String model, String color, int maxSpeed ) {
        model = model;
        color = color;
        maxSpeed = maxSpeed;

 생성자의 매개변수로 선언된 변수의 이름인스턴스 변수의 이름이 같을 경우, 서로 구별이 안됨
  Car ( String model, String color, int maxSpeed ) {
        this.model = model;
        this.color = color;
        this.maxSpeed = maxSpeed;

 인스턴스 변수 앞에 this를 붙여 지역변수와 구별하기

 

▶ 생성자에서 다른 생성자 호출 : this( ) 

 ① 생성자 이름으로 클래스 이름 대신 this( ) 사용

 ② 한 생성자에서 다른 생성자 호출 시, 반드시 첫 줄에서만 호출 가능

Car ( String model ) {
       color = "파랑";
       Car( model,  "빨강", 200 ) ;
}
❶ 첫 줄에서만 호출 가능 
∵ 생성자 내에서 초기화 작업 중 다른 생성자를 호출하게 되면, 호출 이전의 초기화 작업이 무의미
❷ 클래스 이름 대신 this 사용

 - 다른 생성자 호출해서 중복 코드 줄이기

public class Car {
         String company = "현대자동차";
         String model;
         String color;
         int maxSpeed;

        Car ( String model ) {
             this.model = model;
              this.color = "은색";
              this.maxSpeed = 250;
         }

        Car ( String model, String color ) {
             this.model = model;
              this.color = color;
              this.maxSpeed = 250;
         }

        Car ( String model, String color, int maxSpeed ) {
             this.model = model;
              this.color = color;
              this.maxSpeed = maxSpeed;
         }

}
public class Car {
         String company = "현대자동차";
         String model;
         String color;
         int maxSpeed;
        
        Car ( ) {   
        }
        
        // 매개변수 3개인 생성자 호출
        Car ( String model ) {
            this( model, "은색", 250 );
         }

         // 매개변수 3개인 생성자 호출
        Car ( String model, String color ) {
            this( model, color, 250 );
         }

        Car ( String model, String color, int maxSpeed ) {
            // 공통 실행 코드를 한번만 작성
              this.model = model;

              this.color = color;
              this.maxSpeed = maxSpeed;
         }

}
 왼쪽 코드의 3개의 생성자의 내용이 비슷하므로, this( )를 이용해 마지막 생성자를 호출
 → 공통 실행 코드를 한번만 작성하기 때문에 중복 코드 최소화 가능