본문 바로가기
스터디일지/JAVA

[2023.08.01] 자바 객체 지향 프로그래밍

by 똥쟁이핑크 2023. 8. 1.

1. 객체 지향 프로그래밍

https://jongminfire.dev/static/dd4744f231bd4383bd3d69fe2ee1e6f8/2d1ba/abstraction.png

1. 객체

  • 세상에 존재하는 물체
  • 식별이 가능한 것
  • 속성과 행위로 구성 ( 예시) 자동차 )
    • 속성 - 회사, 모델, 색상, 가격, 속도 등등
    • 행위 - 가속, 브레이크, 기어변속, 조명, 경적 등등
  • Java 에서는 이러한 속성과 행위를 필드와 메서드로 정의하여 구현한다. → 속성 = 필드, 행위 = 메서드
  • 현실 세계에 있는 객체를 소프트웨어의 객체로 설계하는 것을 객체 모델링 이라고 한다.

 

2. 특징

  • 캡슐화
    • 속성(필드)와 행위(메서드)를 하나로 묶어 객체로 만든 후 실제 내부 구현 내용은 외부에서 알 수 없게 감추는 것
    • 외부 객체에서는 캡슐화된 객체의 내부 구조를 알 수 없다. → 노출시켜 준 필드 혹은 메서드를 통해 접근 할 수 있다.
    • 캡슐화 하는 이유는 외부 객체에서 해당 필드와 메서드를 잘못 사용하여 객체가 변화하지 않게 한다.
    • 캡슐화된 객체의 필드와 메서드의 노출 유무는 접근제어자를 사용해 결정한다.

https://velog.velcdn.com/images/jinh2352/post/246d386a-fa1b-4b02-89ed-944b42bf9cd1/image.png

 

  • 상속
    • 부모 객체와 자식 객체가 존재한다.
    • 부보 객체가 가지고 있는 필드와 메서드를 자식 객체에 물려주어 사용할 수 있도록 한다.
    • 이유
      1. 객체 간의 구조를 파악하기 쉽다.
      2. 부모 객체에 있는 필드와 메서드를 수정하게 되면 자식 객체 전부 반영이 된다. → 일관성 유지
      3. 자식 객체가 부모 객체를 물려 받기 때문에 코드의 중복이 줄어들고 재사용성이 증가된다.

https://www.fun-coding.org/00_Images/oop.png

 

  • 다형성
    • 객체가 연산을 수행할 때 하나의 행위를 각 객체가 가지고 있는 고유한 특성에 따라 여러가지 형태로 재구성 할수 있는 것

https://images.velog.io/images/lsj16632/post/ef286ebb-e5d2-4410-88fa-e70ba8d192e2/img1.png

 

  • 추상화
    • 객체에서 공통된 부분들을 모아 상위 개념으로 새롭게 선언하는 것
    • 공통적이고 중요한 것들을 모아 객체를 모델링 한다.

https://mblogthumb-phinf.pstatic.net/20160419_104/awesomedev_1461044218755wpe1U_PNG/2.png?type=w2

 

  • 객체와 클래스
    • 객체를 만들기 위해 설계도에 해당하는 클래스가 필요한다.
    • 클래스를 토대로 생성된 객체를 인스턴스, 이러한 과정을 인스턴스화라고 한다.
    • 동일한 클래스로 여러 개의 인스턴스를 만들 수 있다.
    • 클래스를 통해 만들어진 하나의 인스턴스가 여러개 모여 객체

 

2. 클래스 설계

https://i.imgur.com/Ie0c1am.png

  • 클래스 구성은 필드, 생성자, 메서드

 

3. 객체 생성과 참조형 변수

  1. 객체 생성
    • new를 사용하면 클래스로부터 객체를 생성할 수 있다.
    • new 연산자 뒤에 해당 클래스의 생성자 호출 코드를 작성한다.
  2. 참조형 변수
    • new 연사자를 통해서 객체가 생성되면 해당 인스턴스의 주소가 반환된다.
    • 해당 클래스의 참조형 변수를 사용하여 받을 수 있다.
  3. 객체 배열
    • 객체는 참조형 변수와 동일하게 취급된다.
    • 배열 또는 컬렉션에도 저장하여 관리할 수 있다.

 

4. 객체의 속성 - 필드

객체의 데이터를 저장하는 역할

고유한 데이터, 상태 데이터, 객체 데이터로 분류할 수 있다.

  1. 필드의 초기값과 초기화
    • 새로 정의하여 선언한 클래스의 필드들은 기본적으로 초기값을 제공하지 않을 경우 객체가 생성될 때 자동으로 기본 값으로 초기화 된다.
    • '필드타입 필드명 = 값;' 으로 초기화 할 수 있다.
  2. 필드 타입별 기본값
데이터 타입 기본값
byte 0
char \u0000(공백)
short 0
int 0
long 0L
float 0.0F
double 0.0
boolean false
배열 null
클래스 null
인터페이스 null

 

  • 외부 접근
    • 예시 - Car car = new Car(); 
    • 예시처럼 선언했다면 참조변수 car를 이용하여 외부에서 객체 내부 필드에 접근이 가능하다.
  • 내부 접근
    • .(도트) 연산자를 사용하여 접근할 수 있다.
    • 객체 내부 메서드에서도 내부 필드에 접근할 수 있다.

 

5. 객체의 행위 - 메서드

객체의 행위를 뜻한다.

객체간의 협력을 위해 사용된다.

메서드 선언 예시

리턴타입 메서드명(매개변수, ...){
	실행할 코드 작성
}
  • 리턴타입
    • 메서드가 실행된 후 호출을 한 곳으로 값을 반환할 때 해당 값의 타입을 의미한다.
    • return 리턴타입의 반환값;  → 이 형식으로 작성해야 한다.
    • 반환할 값이 없을 떄는 리턴타입에 void를 작서해야 한다. - 반환값이 없으므로 return문을 반드시 지정할 필요는 없다.
  • 매개변수
    • 메서드를 호출할 때 메서드로 전달하려는 값을 받기 위해 사용되는 변수
    • 전달하려는 값이 없다면 생략가능하다.
    • 가변길이의 매개변수도 선언할 수 있다. → double ... speeds의 ...을 사용하면 ,로 구분하여 개수 상관없이 전달 가능하다.
    • 예시
void carSpeeds(double ... speeds) {
    for (double v : speeds) {
    System.out.println("v = " + v);
    }
}

 

  • 메서드 오버로딩 → 함수가 하나의 기능만 구현하는 것이 아닌 하나의 메서드 이름으로 여러기능 구현하도록 하는 기능이다.
    • 오버로딩의 조건
      • 메서드의 이름이 같고, 매개변수의 개수, 타입, 순서가 달라야 한다.
      • 응답 값만 다른 것은 오버로딩 할 수 없다.
      • 접근제어자만 다른 것도 오버로딩을 할 수 없다.
      • 오버로딩은 매개변수의 차이로만 구현 할 수 있다.
    • 오버로딩의 장점
      1. 메서드 이름 하나로 상황에 따른 동작을 개별로 정의할 수 있다.
      2. 메서드의 이름을 절약할 수 있다.
  • 기본형 & 참조형 매개변수
    • 기본형 매개변수 - 값 차제가 복사되어 넘어간다 → 지정된 변수의 원본 값이 변경되지 않는다.
    • 참조형 매개변수 - 지정한 값의 주소를 복사해서 전달한다. → 원본 주소를 알 수 있기 때문에 값을 읽어오고 변경하는 것도 가능하다.

 

6. 인스턴스 멤버와 클래스 멤버

인스턴스 멤버 = 인스턴스 필드 + 인스턴스 메서드

  • 객체를 생성해야 사용할 수 있다.
  • 객체의 인스턴스 필드는 각각의 인스턴스 마다 고유하게 값을 가질 수 있다.
  • 인스턴스를 통해서만 메서드가 사용될 수 있다.

 

클래스 멤버 = 클래스 필드 + 클래스 메서드

  • Java의 클래스 로더에 의해메서드 영역에 저장되고 사용된다.
  • 객체 생성 없이 바로 사용 가능하다.

 

  • 클래스 멤버 선언
    • 필드와 메서드를 클래스 멤버로 만들기 위해 static 메서드를 사용한다.
    • 인스턴스마다 모두 가지고 있을 필요 없는 공용적인 데이터를 저장하는 필드를 클래스 멤버로 선언하는 것이 좋다.
    • 인스턴스 필드를 사용하지 않고 실행되는 메서드가 있다면 static을 사용하여 클래스 메서드로 선언하는 것이 좋다.
    • 클래스 멤버로 선언된 메서드는 인스턴스 멤버를 사용할 수 없다. → 인스턴스 멤버는 객체가 생성되어야 존재할 수 있기 때문이다.
    • 인스턴스 멤버로 선언된 메서드는 클래스 멤버를 사용 할 수 있다.
  • 지역변수
    • 메서드 내부에 선언한 변수다.
    • 메서드가 실행될때마다 독립적인 값을 저장하고 관리한다.
    • 메서드 내부에서 정의될때 생성되고 메서드가 종료될 때가지만 유지 된다.
  • final 필드와 상수 
    • final 필드
      • 최종적이라는 의미를 가진다.
      • 초기값이 지정되면 프로그램이 실행하는 도중에는 절대로 수정할 수 없다.
      • 반드시 초기값을 지정해야 한다.
      • 필드 타입 앞에 final 키워드를 추가하여 선언할 수 있다.
    • 상수
      • 값이 반드시 한개이다.
      • 불변의 값이다.
      • 인스턴스마다 상수를 저장할 필요가 없다.
      • final 앞에 static 키워드를 추가하여 모든 인스턴스가 공유할 수 있는 값이 한개이며 불변인 상수를 선언할 수 있다.
      • 상수는 대문자로 작성하는 것이 관례이다.

 

 

7. 생성자

객체가 생성될 때 호출되며 객체를 초기화 하는 역할을 수행한다.

  • 기본생성자
    • 선언할 떄 괄호 안에 아무것도 넣지않는 생성장
    • 모든 클래스는 생성자가 하나 이상 존재한다.
    • 만약 생성자를 하나도 선언하지 않았다면 컴파일러는 기본 생성자를 바이트코드 파일에 자동으로 추가시킨다.
public class Car {
    public Car(String model) {} // 생성자 선언
// 생성자가 한개 이상 선언되었기 때문에 기본 생성자를 추가하지 않음.
}


public class Car {
    public Car() {} // 컴파일러가 추가시켜줌
}


class Car {
    Car() {} // 컴파일러가 추가시켜줌
}

 

  • 필드 초기화
    • 생성자는 객체를 초기화 하는 역할을 수행한다.
    • 객체를 만들때 인스턴스마다 다른 값을 가져야 한다면 생성자를 통해서 초기화 할 수 있다.
    • 인스턴스마다 동일한 데이터를 가져야 한다면 초기값을 대입하는 것이 좋다.
  • 생성자 오버로딩
    • 생성자를 통하여 필드를 초기화 할대 오버로딩을 적용할 수 있다.
    • 오버로딩 시 개수, 타입. 순서가 동일하고 매개변수명만 다를 경우 오류가 발생한다. → 중복이 불가능하다.

 

8. this와 this()

  • this
    • this는 객체 즉, 인스턴스 자신을 표현하는 키워드다.
    • 객체 내부 생성자 및 메서드에서 객체 내부 멤버에 접근하기 위해 사용할 수 있다.
    • 상황에 따라 this 키워드가 필수가 될 수 있다.
  • this()
    • 인스턴스 자신의 생성자를 호출하는 키워드다.
    • 객체 내부 생성자 및 메서드에서 해당 객체의 생성자를 호출하기 위해 사용될 수 있다.
    • 중복되는 코드를 줄여줄 수 있다.
    • 생성자를 호출할 때는 반드시 해당 생성자의 첫 줄에 작성되어야 한다.

 

9. 접근 제어자

제어자는 클래스, 변수, 메서드의 선언부에 사용되어 부가적인 의미를 부여해 준다.

접근 제어자는 단 하나만 사용할 수 있다.

  1. 접근 제어자
    • 멤버 또는 클래스에 사용, 외부에서 접근하지 못하도록 제한한다.
      • public : 접근 제한이 전혀 없다.
      • protected : 같은 패키지 내에서, 다른 패키지의 자손클래스에서 접근이 가능하다.
      • default : 같은 패키지 내에서만 접근이 가능하다.
      • private : 같은 클래스 내에서만 접근이 가능하다.
    • 사용가능한 접근 제어자
      • 클래스 : public, default
      • 메서드 & 멤버변수 : public, protected, default, private
      • 지역변수 : 없음
    • 접근 제어자를 이용한 캡슐화 (은닉성)
      • 클래스 내부에 선언된 데이터를 보호하기 위해 사용한다.
      • 유효한 값을 유지하도록, 함부로 변경하지 못하도록 접근을 제한하는 것이 필요하다.
    • 생성자의 접근 제어자
      • 인스턴스의 생성을 제한할 수 있다.
      • 일반적으로 클래스의 접근 제어자와 일치한다.
  2. Getter와 Setter
    • 객체의 무결성 즉, 변경이 없는 상태를 유지하기 위해 접근 제어자를 사용하지만 외부에서 private 필드를 읽어오고 저장할 때 Getter와 Setter를 사용하여 해결할 수 있다.
      • Getter
        • private한 필드를 읽을 필요가 있을 때 사용한다.
        • 메서드 이름의 규칙은 get + 필드이름(첫 글자는 대문자)이다.
        • 사용법은 인스턴스 메서드 호출과 동일하다.
      • Setter
        • private한 필드를 저장하거나 수정할 필요가 있을때 사용한다.
        • 메서드 이름의 규칙은 set + 필드이름(첫 글자는 대문자)이다.
        • 사용법은 인스턴스 메서드 호출과 동일하다.
  3. 제어자의 조합
    • 사용가능한 제어자
      • 클래스 :  public, default, final, abstract
      • 메서드 : public, protected, default, private, final, abstract, static
      • 멤버변수 : public, protected, default, private, final, static
      • 지역변수 : final
      • 주의사항
        1. 메서드에 static과 abstract를 함께 사용할 수 없다.
        2. 클래스에 abstract와 final을 동시에 사용할 수 없다.
        3. abstract메서드의 접근 제어자가 private일 수 없다.
        4. 메서드에 private와 final을 같이 사용할 필요는 없다.

 

10. package와 import 이해하기

  1. 패키지
    • 클래스의 일부분이면서 클래스를 식별해준ㄴ다.
    • 상위 패키지와 하위 패키지를 .(도트)로 구분한다. → package.상위패키지.하위패키지
  2. import
    • 다른 패키지에 있는 클래스를 사용하기 위해 명시하는 키워드
    • 예시 → import java.io.BufferedReader;
    • 모든 클래스를 사용하려면 클래스 이름을 생략하고 * 를 사용하여 표현할 수 있다.  import java.io.*;
    • 서로 다른 패키지에 있는 같은 이름의 클래스를 동시에 사용하려면 해당 클래스에 패키지 명을 전부 명시해야 한다.