Post

TIL-20240426

TIL-20240426

2024-04-26

오늘의 학습 🌠


1

학습 내용 개념 정리 📃

  • 객체

    • 속성과 행위로 구성
    • 수많은 관계를 맺고 살아감

    • Java에서는 속성 -> 필드, 행위 -> 메서드
    • 현실 세계에 있는 객체를 SW의 객체로 설계하는 것 : 객체 모델링
    • ex) 현실 세계에서 사람이라는 객체와 자동차라는 객체는 서로 행위를 통해 상호작용을 하며 협력
    • ❓ 소프트웨어의 객체들끼리는 어떻게 상호작용할까?
      • 행위를 정의하는 Java의 메서드를 통해
    • 사람 객체는 메서드를 호출할 때 괄호( ) 안에 데이터를 넣어 호출할 수 있는데 이 괄호 안에 넣는 데이터는 ‘파라미터’ 혹은 ‘매개값’이라고 표현

    • ex) gasPedal(50) 에서 50이 파라미터 혹인 매개값임

    • 자동차 객체는 gasPedal(50); 메서드에서 속도를 바꾸는 작업을 수행한 후 사람 객체에게 실행 결과인 속도 값을 반환할 수 있음. 이 반환값을 ‘리턴값’이라고 표현

    • ex) return speed; 에서 speed가 리턴값
  • 객체 간의 관계

    • 예시로 현실 세계의 자동차 🚗
    • 사용 관계
      • 사람 객체는 자동차 객체를 사용
    • 포함 관계
      • 타이어 객체, 차 문 객체, 핸들 객체는 자동차 객체에 포함
    • 상속 관계
      • 공장에 자동차만 생산하는 게 아니라 기차도 생산한다고 가정

      • 자동차, 기차 객체는 하나의 공통된 기계 시스템 객체를 토대로 만들어진다고 가정
      • 자동차 객체와 기차 객체는 기계 시스템 객체를 상속받는 상속 관계

객체지향 프로그래밍 특징

  • 캡슐화 - 속성(필드)와 행위(메서드)를 하나로 묶어 객체로 만든 후 실제 내부 구현 내용은 외부에서 알 수 없게 감추는 것

    • 외부 객체에서는 캡슐화된 객체의 내부 구조를 알 수 없기 때문에 노출시켜 준 필드 혹은 메서드를 통해 접근할 수 있음
    • 캡슐화된 객체의 필드와 메서드를 노출시킬지 감출지 결정하기 위해 접근 제어자 사용 ```
  • ❓ 굳이 왜 숨기는 걸까?
    외부 객체에서 해당 필드와 메서드를 잘못 사용하여 객체가 변화하지 않게 하기 위해서 ```
  • 상속
    • 객체지향 프로그래밍에는 부모 객체와 자식 객체가 존재

    • 부모 객체는 가지고 있는 필드와 메서드를 자식 객체에게 물려주어 자식 객체가 이를 사용할 수 있도록 만들 수 있음
    • ❓ 왜 상속을 사용하는 걸까?
      • 각각 객체들을 상속 관계로 묶음으로써 객체 간의 구조를 파악하기 쉬움

      • 필드와 메스드를 변경하는 경우 부모 객체만 수정하면 자식 객체에 전부 반영되므로 일관성 유지에 좋음
      • 자식 객체가 부모 객체의 필드와 메서드를 물려받아 사용할 수 있기 때문에 코드의 중복이 줄며 코드의 재사용성이 증가
  • 다형성
    • 객체가 연산을 수행할 때 하나의 행위에 대해 각 객체가 가지고 있는 고유한 특성에 따라 다른 여러가지 형태로 재구성되는 것

    • ex) Car 클래스를 토대로 자동차 객체를 만들 때 A 자동차 객체, B 자동차 객체의 경적 소리가 다르다면 ‘경적을 울리다’라는 행위 즉, horn(); 메서드의 구현을 다르게 재정의 하여 사용

  • 추상화
    • 객체에서 공통된 부분들을 모아 상위 개념으로 새롭게 선언
  • 우리가 현실 세계에서 예를 들어 자동차를 만들기 위해서는 자동차 설계도를 토대로 자동차를 생산하기에 자동차 설계도가 필요함!

  • 소프트웨어에서도 객체를 만들기 위해 설계도에 해당하는 클래스가 필요함

  • 이때 클래스를 통해 생성된 객체를 해당 클래스의 인스턴스라고 부르며 이 과정을 인스턴스화라고 부름

-> 동일한 클래스에 여러 개의 인스턴스 생성 가능

📌 더욱 쉽게 설명 : 자동차 클래스를 통해 만들어진 하나의 자동차를 인스턴스라고 부르며 이러한 여러 개의 인스턴스들을 통들어 자동차 객체라고 표현할 수 있음

(자동차 인스턴스1, 자동차 인스턴스2, … ) : 자동차 객체


클래스 설계

  • 클래스
    • 객체를 설계하기 위한 설계도

    • 구성 멤버 : 필드, 생성자, 메서드

  • 📌 클래스를 만들기 위한 STEP
    • 만들려고 하는 설계도를 선언(클래스 선언)

    • 객체가 가지고 있어야 할 속성(필드)을 정의
    • 객체를 생성하는 방식 정의(생성자)
    • 객체가 가지고 있어야 할 행위(메서드) 정의
  • 이해하기 쉽게 자동차 클래스로 설명 🚗💨

  • 클래스 선언
1
2
    public class Car {
    } //공개된 자동차 클래스 선언
  • 클래스 필드 정의
1
2
3
4
5
6
7
String company; // 자동차 회사
String model; // 자동차 모델
String color; // 자동차 색상
double price; // 자동차 가격
double speed;  // 자동차 속도 , km/h
char gear; // 기어의 상태, P,R,N,D
boolean lights; // 자동차 조명의 상태	

필드는 객체의 속성으로 데이터를 저장하는 역할

  • 클래스 생성자 정의

    1
    
      public Car() {}
    

    생성자는 반환 타입 X, 이름은 클래스 이름과 동일, 괄호 ( ) 안에 아무것도 없는 생성자는 기본 생성자

    • 클래스 메서드 정의
    1
    2
    3
    4
    
      double gasPedal(double kmh) {
      speed = kmh;
      return speed;
      }
    

객체 생성과 참조형 변수

  • 객체 생성
    1
    
      new Car(); //Car 클래스 객체 생성
    
    • 객체 생성 연산자인 new 를 사용하여 클래스로부터 객체를 생성
  • 참조형 변수
    1
    2
    
      Car car1 = new Car(); // Car클래스의 객체인 car1 인스턴스 생성
      Car car2 = new Car(); // Car클래스의 객체인 car2 인스턴스 생성
    
    • new 연산자를 통해 객체가 생성되면 해당 인스턴스의 주소가 반환되기 때문에 해당 클래스의 참조형 변수를 사용하여 받아줄 수 있음

객체 속성(필드)

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

  • 객체의 필드는 크게 고유 데이터, 상태 데이터, 객체 데이터로 분류
  • 우리가 처음 SW 부품을 객체라고 표현한다고 했고, 객체 데이터를 자동차를 만들기 위한 부품 데이터라고 이해하면 쉬움!

  • 📌 헷갈리는 부분 ❓
    • 필드를 사용한다라는 의므는 필드의 값을 변경하거나 읽는 것을 의미
      • 이 말은 클래스에 필드를 정의하여 선언했다고 바로 사용할 수 있는 것은 아니고 객체를 생성한 후에 필드를 사용할 수 있음. 실제로 필드의 데이터를 가지고 있는 것은 객체니까!
  • 필드 사용법
    • 외부 접근
      • Car car = new Car();
        • 참조변수 car를 이용해 외부에서 객체 내부의 필드에 접근하여 사용 가능
        • 내부 필드 접근 방법 : 도트(.) 연산자
        • car.color = "red";
    • 내부 접근
      • 도트 연사자를 사용하여 외부에서 객체 내부 접근 뿐만 아니라 객체 내부 메서드에서도 내부 필드 접근 가능
      1
      2
      3
      4
      
        double brakePedal() {
        speed = 0;
        return speed;
        }
      

객체 행위(메서드)

  • 📌 메서드는 객체의 행위를 뜻하며 메서드의 행위를 정의하는 방법은 블록{ } 내부에 실행할 행위를 정의

  • 메서드 선언
    1
    2
    3
    
      리턴타입 메서드명(매개변수, ...) {
               실행할 코드 작성
      }
    
    • 가변길이의 매개변수 선언 가능
      1
      2
      3
      4
      5
      
        void carSpeeds(double ... speeds) {
        for (double v : speeds) {
            System.out.println("v = " + v);
        }
        }
      
    • double … speeds처럼 …을 사용하면 매개값을 , 로 구분하여 개수 상관없이 전달 가능
  • 메서드 호출
    • 메서드를 호출한다 라는 의미는 메서드의 내부에 작성된 코드를 실행한다는 의미

    • 필드와 마찬가지로 클래스의 메서드를 정의하고 선언했다고 해서 바로 사용 불가, 객체를 생성한 후 메서드 사용 가능

    • 외부 접근
      • Car car = new Car(); 과 같이 객체를 생성하면 도트(.) 연산자를 사용하여 객체의 내부 메서드에 접근 car.brakePedal();
    • 내부접근
      • 도트 연산자를 사용하여 외부-> 객체 내부에 접근할 수 있을 뿐만 아니라 객체 내부 메서드에서도 내부 메서드에 접근하여 호출 가능
  • 메서드 오버로딩
    • 오버로딩은 함수가 하나의 기능만을 구현하는 것이 아니라 하나의 메서드 이름으로 여러 기능을 구현하도록 하는 것 -> 한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메서드가 있더라도 매개변수의 개수, 타입, 순서가 다르면 동일한 이름을 사용하여 메서드 정의 가능
      1
      2
      3
      
       ❓ 오버로딩이 왜 중요할까?
        : 예를들어 println()을 보면 매개변수에 int, double, String 등 다양하게 넣을 수 있어 메서드 이름 하나로 상황에 따른 동작을 개별로 정의할 수 있음
        또한 오버로딩이 안되면 println()은 printlnInt(), printlnDouble()처럼 메서드명이 길어지고 낭비 되었을 것
      
  • 기본형 매개변수
    • 매개변수 타입이 기본형이면 값 자체가 복사되어 넘어가기 때문에 매개값으로 지정된 변수의 원본 값이 변경되지 않음
  • 참조형 매개변수
    • 저장된 곳의 원본 주소를 알 수 있기 때문에 값을 읽어오는 것 + 값 변경 가능

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

  • 멤버 = 필드 + 메서드
    • 인스턴스 멤버 = 인스턴스 필드 + 인스턴스 메서드
    • 클래스 멤버 = 클래스 필드 + 클래스 메서드

    • 인스턴스 멤버는 객체 생성 후에 사용 가능, 클래스 멤버는 객체 생성 없이도 사용 가능

    • 📌 헷갈리는 부분
      • 인스턴스 멤버는 객체를 생성해야 사용 가능하고 객체의 인스턴스 필드는 각각의 인스턴스마다 고유하게 값을 가질 수 있음.
      • 객체가 인스턴스화 할 때마다 객체의 메서드들은 인스턴스에 포함되어 매번 생성될까?
        • 아님. 매번 저장하면 중복 저장으로 메모리 효율성이 떨어지므로 메서드는 메서드 영역에 두고 모든 인스턴스들이 공유해서 사용함!
        • 대신 인스턴스를 통해서만 메서드가 사용될 수 있도록 제한을 걸어둔 것
  • 필드와 메서드를 클래스 멤버로 만들기 위해 static 키워드 사용
    • 일반적으로 인스턴스마다 모두 가지고 있을 필요 없는 고용적인 데이터를 저장하는 필드는 클래스 멤버로 선언하는 것이 좋음
    • 주의 💫 : 클래스 멤버로 선언된 메서드는 인스턴스 멤버를 사용할 수 없음. 클래스 멤버는 객체 생성 없이 바로 사용 가능하기 때문에 객체가 생성되어야 존재할 수 있는 인스턴스 멤버를 사용할 수 없음.
  • 지역변수
    • 메서드 내부에 선언한 변수로, 메서드 내부에서 정의될 때 생성되어 메서드가 종료될 때까지만 유지됨.
  • final 필드
    • final 필드는 초기값이 저장되면 해당 값을 프로그램이 실행하는 도중에 절대로 수정 불가, 반드시 초기값을 지정
  • 상수
    • 값이 반드시 한 개, 불변의 값을 의미
    • final 앞에 static 키워드를 추가하여 모든 인스턴스가 공유할 수 있는 값이 한 개이며 불변인 상수를 선언할 수 있음

생성자

  • new 연산자에 의해 객체 생성

  • 기본 생성자

    • 모든 클래스는 반드시 생성자가 하나 이상 존재

    • 클래스에 생성자를 하나도 선언하지 않았다면 컴파일러는 기본 생성자를 바이트코드 파일에 자동으로 추가시켜줌. -> 이러한 경우 기본 생성자 생략 가능
    • 반대로 하나라도 생성자가 선언되어 있다면 컴파일러는 기본 생성자를 추가하지 않음

    • 생성자는 객체를 초기화하는 역할을 수행
      • 객체를 만들 때 인스턴스마다 다른 값을 가져야 한다면 생성자를 통해 필드를 초기화할 수 있음
      • 반대로 인스턴스마다 동일한 데이터를 가지는 필드는 초기값을 대입하는 것이 좋음

this와 this()

  • this는 객체 즉 인스턴스 자신을 표현하는 키워드
    • 객체 내부 멤버에 접근할 때 this 키워드가 필수는 아니지만 상황에 따라 필수가 될 수 있음
      1
      2
      3
      4
      5
      
        public Car(String model, String color, double price) {
        model = model;
        color = color;
        price = price;
        }
      
  • 위의 코드처럼 생성자를 선언하는데 매개변수명과 객체의 필드명이 동일할 경우 오류가 발생하지는 않지만 생성자 블록 내부에서 해당 변수들은 객체의 필드가 아닌 가장 가까운 매개변수명을 가리키게 됨으로 자기 자신에게 값을 대입하는 상황이 됨.

  • this 키워드 사용하여 해결 : this 키워드를 통해 변수명에 해당하는 객체의 필드에 접근하여 받아온 매개변수의 매개값을 객체의 필드에 대입하여 저장할 수 있음

  • this(…) 는 객체 즉, 인스턴스 자신의 생성자를 호출하는 키워드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public Car(String model) {
    this.model = model;
    this.color = "Blue";
    this.price = 50000000;
}

public Car(String model, String color) {
    this.model = model;
    this.color = color;
    this.price = 50000000;
}

public Car(String model, String color, double price) {
    this.model = model;
    this.color = color;
    this.price = price;
}

해당 코드를 this() 키워드를 사용하여 다음과 같이 코드 중복 제거

1
2
3
4
5
6
7
8
9
10
11
12
13
public Car(String model) {
    this(model, "Blue", 50000000);
}

public Car(String model, String color) {
    this(model, color, 100000000);
}

public Car(String model, String color, double price) {
    this.model = model;
    this.color = color;
    this.price = price;
}
  • 📌 주의할 점
    • this() 키워드를 사용해서 다른 생성자를 호출할 때는 반드시 해당 생성자의 첫 줄에 작성되어야 함!

접근 제어자

  • 접근 제어자 : public, protected, default, private
  • 그 외 제어자 : static, final, abstract
  • 접근 제어자
    • 멤버 또는 클래스에 사용, 외부에서 접근하지 못하도록 제한
      • 클래스, 멤버 변수, 메서드, 생성자에 사용되고 지정되어 있지 않다면 default임
        • public : 접근 제한이 전혀 없음
        • protected : 같은 패키지 내에서, 다른 패키지의 자손 클래스에서 접근 가능
        • default : 같은 패키지 내에서만 접근 가능
        • private : 같은 클래스 내에서만 접근 가능
    • 사용가능한 접근 제어자

      • 클래스 : public, default
      • 메서드 & 멤버 변수 : public, protected, default, private
      • 지역변수 : 없음
  • Getter, Setter
    • 객체의 무결성 즉, 변경이 없는 상태를 유지하기 위해 접근 제어자 사용
      • 외부에서 필드에 직접 접근하는 것을 막기 위해 필드에 private, default 등의 접근 제어자를 사용할 수 있음
      • 어떻게 객체의 private 필드를 읽어오거나 저장할 수 있을까?
    • Getter
      • 외부에서 객체의 private 한 필드를 읽을 필요가 있을 때 Getter 메서드 사용
      • 메서드 이름 규칙 : get+필드이름(첫 글자 대문자)
    • Setter
      • 외부에서 객체의 private한 필드를 저장/수정할 필요가 있을 때 Setter 메서드 사용
      • 메서드 이름 규칙 : set + 필드 이름(첫 글자 대문자)

package, import

  • package란 클래스의 일부분이면서 클래스를 식별해 주는 용도
    • 상위 패키지, 하위 패키지를 도트(.)로 구분
    • package 상위 패키지.하위 패키지;
  • import란 다른 패키지에 있는 클래스를 사용하기 위해 명시하는 키워드

상속

  • 상속
    • 부모가 자식에게 물려주는 행위
    • 상속의 키워드 extends로 개념을 확장의 개념으로 이해해야 함.

    • Java는 다중 상속을 허용하지 않음

    • 이유 : 만약 자식 클래스에서 상속받는 서로 다른 부모 클래스들이 같은 이름의 멤버를 가지고 있다면? 자식 클래스에서는 이 멤버를 구별할 수 있는 방법이 없음
  • Object
    • Object는 말 그래도 “객체”를 의미하는 단어, 보통 Object 클래스를 의미

    • Java 내 모든 클래스들의 최상위 부모 클래스
    • 모든 클래스는 Object의 메서드를 사용할 수 있음 ```
  • Object clone() : 해당 객체의 복제본을 생성하여 반환함.
  • boolean equals(Object object) : 해당 객체와 전달받은 객체가 같은지 여부를 반환함.
  • Class getClass() : 해당 객체의 클래스 타입을 반환함.
  • int hashCode() : 자바에서 객체를 식별하는 정수값인 해시 코드를 반환함.
  • String toString() : 해당 객체의 정보를 문자열로 반환함. & Object 클래스에서는 클래스이름 @해쉬코드값 리턴함.

오버라이딩

  • 부모 클래스로부터 상속받은 메서드의 내용을 재정의 하는 것

  • 오버라이딩 조건
    • 선언부가 부모 클래스의 메서드와 일치

    • 접근 제어자를 부모 클래스의 메서드보다 좁은 범위 변경 불가
    • 예외는 부코 믈래스의 메서드보다 많이 선언 불가능
  • super : super는 부모 클래스의 멤버를 참조할 수 있는 키워드
    • 객체 내부 생성자 및 메서드에서 부모 클래스의 멤버에 접근하기 위해 사용

    • 자식 클래스 내부에서 선언한 멤버와 부모 클래스에서 상속받은 멤버와 이름이 같을 경우 이를 구분하기 위해 사용

  • super(…)는 부모 클래스의 생성자를 호출할 수 있는 키워드

다형성

  • 자동 타입 변환
    • 부모 타입 변수 = 자식 타입 객체;는 자동으로 부모 타입으로 변환이 일어남
  • 강제 타입 변환
    • 자식 타입 변수 = (자식 타입) 부모 타입 객체;는 자동으로 타입 변환되지 않고 강제로 자식 타입으로 변환할 수 있음
  • 다형성
    • 여러가지 형태를 가질 수 있는 능력
  • instanceof
    • 다형성 기능으로 인해 해당 클래스 객체의 원래 클래스명을 체크하는 것이 필요한데 이때 사용할 수 있는 명령어는 instance of

추상 클래스

  • 추상 클래스
    • 클래스가 설계도라면 추상 클래스는 미완성된 설계도

    • 예를 들어 부모가 완성시키지 않은 메서드를 자식이 extends 즉, 상속받아서 완성시켜서 쓰는 형태 -> 추상 클래스는 자식 클래스에 상속되어 자식 클래스에 의해서만 완성될 수 있음
    • abstract 키워드
1
2
3
public abstract class 추상클래스명{
	abstract 리턴타입 메서드이름(매개변수, ...);
}
  • 일반적인 메서드와 다르게 블록{}이 없음. 정의만 할 뿐, 실행 내용은 가지고 있지 않음.

인터페이스

  • 인터페이스
    • 두 객체를 연결해주는 다리 역할

    • 예시 : 삼성티비, 엘지티비 존재, 사람 객체는 멀티 리모컨 인터페이스를 통해 삼성티비 객체의 채널을 변경할 수 있음.
    • 상속 관계가 없는 다른 클래스들이 서로 동일한 행위 즉, 메서드를 구현해야할 때 인터페이스는 구현 클래스들의 동일한 사용 방법과 행위를 보장함

    • 인스턴스
      • 멤버변수 : public static final
        • 생략 가능
      • 메서드 : public abstract
        • 생략 가능
      • 인터페이스의 추상 메서드는 구현될 때 반드시 오버라이딩 되어야 함
    • 인터페이슨느 추상 클래스와 마찬가지로 직접 인스턴스를 생성할 수 없기 때문에 클래스에 구현되어 생성됨
    • implements 키워드를 사용하여 인터페이스 구현
    • 인터페이스의 추상 메서드는 구현될 때 반드시 오버라이딩 되어야 함
    • 인터페이스 간 상속의 implements가 아니라 extends 키워드 사용
    • 클래스와 다르게 다중 상속 가능
  • 디폴트 메서드
    • 추상 메서드의 기본적인 구현을 제공하는 메서드
    • 메서드 앞에 default 키워드를 붙이며 블럭{}이 존재
    • 접근 제어자 public이며 생략 가능

추가 🕤


1

  • 친구가 보내준..사진입니다. 오늘의 tmi는 이 사진이 전부라고 생각이 드네요,,😅

🐱‍🏍— —🤸🏻‍♀️ ~~~ 야~호~

This post is licensed under CC BY 4.0 by the author.