til(11_12)

김태은·2024년 11월 12일

객체지향의 특징과 개념

개념

객체 란?

세상에 존재하는 물체, 식별이 가능한것 ex 자동차, 도서관 ... 을 말한다.

구성 : 속성(필드)과 행위(메서드)를 가진다.

부속 내용

객체 모델링 : 현실의 객체를 소프트웨어의 객체로 설계되는 것이다.

객체 간의 협력 : 서로 독립적인 객체가 행위를 통해 상호 작용하는 것을 말한다. ex 사람 객체 자동차 객체 사람 객체가 자동차에 엑셀을 밟으면(메서드 호출) 자동차 객체는 이에 반응하여 속도를 증가시킨다(속성 값 변동).

객체들은 메서드를 통해 데이터를 주고 받을 수 있다(매개변수 = 시스템 값). ex 사람 객체가 현재 연료 메서드에 50의 값을 넣어 주면, 자동차 객체가 이를 받는다.

자동차 객체가 정의한 명세대로 데이터를 받는다.

객체 관의 관계

종류 : 사용관계(사람 과 자동차) , 포함관계(자동차 - 타이어, 핸들 , ...) , 상속관계 ( 공장 메커니즘 > 자동차 , 공장 메커니즘 > 기차 ..)

상속관계 : 큰틀을 아래 상속받는 객체에게 큰 틀을 상속시켜주는 관계

특징

객체 지향의 특징 종류

캡슐화, 상속, 다형성, 추상화 가 있다.

캡슐화 : 속성과 메서드를 하나로 묶어서 객체로 만들고 , 외부에서 알 수 없게 감추는 것이다.

보완에서 좋다! 객체가 변화하지 않는다! , < - 외부에서 알 수 없게 감추는 것이다.

접근 제어자를 통해 이를 제어한다! - public , private ...

상속 : 부모 객체가 가지는 필드와 메서드를 자식 객체에게 물려주어 자식 객체가 이를 사용할 수 있도록 해준다.( 물려 받은 것을 쓸지, 혹은 안쓸지는 자식 객체가 결정할 수 있다.)

일관성에 좋다 코드 중복이 줄어든다. < - 부모 객체가 가지는 필드와 메서드를 자식 객체에게 물려주어 자식 객체가 이를 사용할 수 있도록 해준다.

overriding 의 개념 추가 예정

다형성 : 연산을 수행시 하나의 행위에 대해 각 개체가 가지고 있는 고유한 특성에 따라 다른 여러가지 형태로 재구성하는 것을 의미 ex 자동차 클래스에 차1 객체와 차2 객체를 만들었을 때, 객체의 경적소리가 다른 경우(행위의 결과가 다르다 - 메서드가 서로 다르게 정의되어있다.)

  • 메모 3 -1 다형성

추상화 : 구체적인 것(공통적인)을 모호하게(상위개념) 빼는 것을 말함 , 공통된 부분을 모아 상위 개념으로 새롭게 선언하는 것 ex 자동차의 공통적으로 가지는 가속, 브레이크 등을 모아 , 자동차(상위) 라는 객체를 모델링 할 수 있다.

  • 메모 3 -1 추상화

부속

객체와 클래스

객체를 생성하기 위해선 클래스(설계도)가 필요하다.

클래스를 토대로 만들어진 객체를 인스턴스 라 한다. 해당과정을 인스턴스화 라고 한다.
동일 클래스로 여러 인스턴스를 만들 수 있다.

class 클래스 이름 - > 객체의 설계도

클래스의 설계

step

  1. 만들려고 하는 설계도를 선언(클래스 선언)
  2. 객체가 가지고 있어할 속성(필드)을 정의 - 변수
  3. 객체를 생성하는 방식을 정의(생성자) - 어떤 인풋을 넣어서 생성할 지 , 생성할 때 어떤 로직을 넣을지 생각하자. - constructor

    생성자는 클래스 명과 동일하게 지어준다. - > public 생성자명<-클래스명과 동일 (){ 로직 }

    로직 자리에 아무것도 정의되어 있지 않은 것을 '기본 생성자' 라 한다. - 기본생성자는 생략이 가능하다!
    처음 객체가 생성될 때(인스턴스화 할때)어떤 로직을 수행하여, 어떤 값이 필수로 들어와야 하는지 정의

  4. 객체가 가지고 있어야할 행위(메서드)를 정의

클래스를 이용하여 객체 만들기

ex 작성한 car 클래스를 이용하여 객체들 때, new 키워드 를 이용한다. ps new 키워드를 만들 때엔 생성자가 사용됨을 알자!

신규 객체를 만들 때 new 키워드 가 이용된다


필드

필드 종류 :
고유 데이터(말 그대로 고정된 값 - ex 자동차를 만든 회사 ) , 상태 데이터(언제든지 바뀔 수 있는 값) , 객체 데이터( ex 자동차를 만들기 위한 하위 부품 - 객체화한다(하위 객체) > 바퀴 핸들 등등 은 자동차에만 쓰이지않고, 비행기 포크레인 등에서 쓰인다. )

한 객체에서 하위 객체를 가질 수 있다. - 객체 데이터

필드 선언만 했을 경우

선언만 했을 때, 값의 초기화 값

필드를 사용한다 란? 필드의 값을 변경하거나 읽는 것을 의미한다.

ps 인스터스화를 해줌으로 써 필드를 사용할 수 있다.(선언 만 했다고 사용할 수 있는 것이 아님! - 클래스는 실체가 아닌 설계도!!!)

클레스가지고 필드에 접근하는 법

  1. 외부 접근 :

Car car = new Car(); > 인스터스화 - 객체로 만들고~

car.color = "blue"; > 도트(.) 연산자를 사용하여 내부 필드에 접근

  1. 내부접근 :

설계도 안에 있을 때 , 그냥 바로 접근 !!(메서드 호출하면 사용 가능)


메서드

메서드 선언

리턴타입 메서드명(매개변수, ...) {
실행할 코드 작성
}

반환 값이 없을 땐, void - return을 안써도 된다. 다만, 해당 메서드를 종료시키고자 할 때는 써도 무방하다.

매개변수는 메서드를 호출 할때, 메서드로 전달하려는 값을 받기 위해 사용되는 변수

타입순서를 맞춰줘야한다.

매개변수는 처음 정의시 없으면 적지 않아도 무방

가변길이의 매개변수도 사용 가능하다.

(타입 ... 매개변수명) 로 작성

void carSpeeds(double ... speeds)
가변으로 들어 온다는 것은 return 값도 가변! >> for 문을 이용하여 처리 해줘야한다

메서드 호출
1. 외부 접근 : 변수명.메서드명(매개변수) 로 사용 - 필드 값과 마찬가지로 인스터스화를 진행해야 사용 가능하다!

  1. 내부 접근 : 바로 호출 가능! -메모

메서드 오버로딩
함수가 하나의 기능만을 구현하는 것이 아니라 매개변수의 타입 혹은 순서 등에 따라 동일한 이름( 한 클래스 내에 )의 메서드임에도 다르게 쓰이는 것을 말함

  • 조건

    메서드의 이름이 같고, 매개변수의 갯수, 타입 , 순서 의 일부가 다르다!

    응답 값만 다른것은 오버로딩 할 수 없다.
    매개변수의 차이 로만 구현할 수 있다.

  • 장점
    메서드의 이름을 절약
    메서드 하나로 여러기능!

매개변수

  • 기본형 : 매개변수의 타입이 기본형일 때는 값 자체가 복사되어 넘어가기 때문에 매개값으로 지정된 변수의 원본 값이 변경되지 않는다. (읽기 가능) - 메모 3-5
  • 참조형 : 매개변수를 참조형으로 선언하면 값이 저장된 곳의 원본 주소를 알 수 있기 때문에 값을 읽어 오는 것은 물론 값을 변경하는 것도 가능하다.(읽고, 변경이 가능)

    메서드의 매개변수뿐만 아니라 반환 타입도 참조형이 될 수 있다.
    반환 타입이 참조형이라는 것은 반환하는 값의 타입이 “실제 값의 주소”라는 의미한다.


인스턴스 맴버 와 클래스 맴버

맴버 란? 필드 + 메서드

알아두자

  • 필드 , 메서드 는 선언하는 방법 에 따라서 인스터스 맴버와 클래스 맴버로 구분
    ps 선언하는 방법에는 접근 제어자 static nonstatic 등이 있다.

  • 인스턴스 맴버는 객체 생성 후에 사용가능하고, 클래스 맴버는 객체 생성 없이도 사용가능하다.

    main 메서드를 생각해보면 필드와 메서드를 객체화 하지 않고, 사용했었다! -> 처음 psvm 안에서

인스턴스 맴버
모든 객체의 인스턴스 필드는 각각의 독립적이다. ex 차 클래스 로 만든 car1 car2 car3 의 객체의 필드 값은 다 다르게 수정, 변경 될 수 있다. (< -독립적)
단, 메서드의 경우 메서드 영역을 공유한다. 각각 생성된 인스턴스에게 공유되어 사용(< - 메모리 아낀다!)
또! 대신 무조건 객체를 생성(인스턴스화)해야 메서드를 사용할 수 있게 끔 제한만을 걸어둔 것이라 생각하자~

클래스 맴버
java의 클래스 로더에 의해 메서드 영역에 저장되고 사용한다.
메서드 영역의 클래스와 같은 위치에 고정적으로 위하고 있는 맴버를 의미 -메모 3-6

클래스 맴버 선언
static 키워드를 사용한다.
인스턴스 마다 모두 가지고 있을 필요없는 공용적인 데이터르 저장하는 필드는 클래스 맴버로 선언하는 것이 좋다. 인스턴스 필드를 사용하지 않고 실행되는 메서드가 존재한다면 static 키워드를 사용하여 클래스 메서드로 선언하는 것이 좋다 -메모 3-6

// static 이 붙으면 class로 생각하자 - 메모 
static String company = "GENESIS"; // < - 필드를 클래스로
// 자동차 회사 : GENESIS < - 공용으로 쓸 부분(모두 같은 부분)

String getCompany() { < - 메서드는 인스턴스
    return "(주)" + company; 
    // 객체도 클래스 맴버를 쓸 수 있다.
} 

< - >

static String setCompany(String companyName) { 
    // System.out.println("자동차 모델 확인: " + model); // 인스턴스 사용 불가
    company = companyName;
    return company;
} 

클래스 맴버 사용 -메모 3-6

static 을 선언되어 클래스를 만들었 기 때문에 바로 클래스 이름으로 접근이 가능하다.

Car.company = "Audi";
String companyName = Car.setCompany("Benz");

메서드의 지역변수 : 메서드 안에서만 저장되고, 메서드 종료시 삭제!

final 필드와 상수
final 필드는 초기값이 저장되면 수정 x (최종값이다.)
ps 초기값을 반드시 정해야한다!

상수
값이 반드시 한개이며 불변의 값 ( - > static final ) 을 말한다.
인스턴스마다 상수를 지정할 필요 없다.
ps 상수는 전체 문자가 대문자 (- 변수명)

생성자

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

public Car() {} // 선언

...

Car car = new Car(); // 호출

기본 생성자
() 안에 아무것도 없는 것을 의미한다.
모든 클래스는 반드시 생성자가 하나 이상은 존재해야한다!

인스턴스를 생성할때마다 필드을 각각 정해줘야할 때 , 생성자에서 이름을 받을 때 필드을 지정해준다.

public Car(String modelName, String colorName, double priceValue) { 
// 이처럼 매개변수를 정해줬는데
    model = modelName;
    color = colorName;
    price = priceValue;
}

...

Car car = new Car(); 
// 안하면 오류

오버로딩을 생성자에도 적용가능!

public Car(String modelName, String colorName, double priceValue)
public Car(String colorName, String modelName, double priceValue)

String, String, double : 매개변수의 개수, 타입, 순서가 동일하기 때문에 중복이 불가능하다. 변수명이 다른건 해당안된다.

this 와 this()
this
자바에서 this 와 this()는 인스턴스 자신을 가리킨다.

생선자를 선언하는데 매개변수명과 객체의 필드명이 동일한 경우 > 오류가 나지는 않는다.
다만, 가장 가까운 곳에서 매개변수를 찾기 때문에 ??? 필드에서 값을 가지고 오는 것이 아닌, 자기 자신을 대입한다. -메모 3-8

객체자체를 리턴해야하는 경우 this를 쓰면 된다.

Car returnInstance() {
// Car = return type
// returnInstance = 메서드명
    return this;
}

this()
인스턴스의 생성자를 표현한것

public Car(String model) {
    this(model, "Blue", 50000000); //  요것이!
}

// 요것
// 여기서 this으로 인해 자기 자신 호출 + (model, "Blue", 50000000) 매개 변수 값 입력
public Car(String model, String color, double price) {
    this.model = model;
    this.color = color;
    this.price = price;
}

⚠️주의점
this()를 사용시 위에 어떤 로직이 같이 있으면 안됨! 그래서 반드시 첫줄에 쓴다!

public Car(String model) {
    System.out.println("model = " + model); // < - 이처럼 this() 위에 무엇이 있으면 안됨!
    this(model, "Blue", 50000000);
}

접근 제어자

제어자 : 클래스 변수 메서드의 선언부에 사용 가능하고, 부가적인 의미를 부여한다.

접근 제어자
폴더상에서 어디까지 접근을 허용할 지를 정해준다. public, protected, default, private

클래스 내부에 선언된 데이터를 보호하기 위해서 사용 < - 캡슐화
변경이 없는 상태를 유지하기 위해 사용 < - 객체의 무결성

그 외 제어자
static, final, abstract(추상화를 할 적에)

접근 제어자의 종류
외부에서 접근 못하게 혹은 하도록 만든 장치 , default 값은 default 이다
public : 같은 프로젝트 내에서는 접근 제한이 전혀 없다.
protected : 같은 패키지 내에서, 다른 패키지의 자손 클래스에서 접근이 가능하다 -메모 3-9

말이 어려우니 같은 패키지 내에서 가능하다 정도만 기억하자

default : 같은 패키지 내에서만 접근이 가능합니다.
private : 같은 클래스 내에서만 접근이 가능합니다.

사용가능한 접근 제어자
클래스에선 public default
ps 생성자의 접근 제어자도 클래스의 접근 제어자와 동일
메서드와 맴버변수에선 모든 접근 제어자 사용 가능하다.
지역변수에선 사용 불가

Getter 와 Setter < - 매우 중요한 개념! ( 캡슐화를 머리에 박고 해당 개념을 이해하는 것이 좋다! )

Getter 와 Setter
직접적으로 값의 조회 세팅을 방지하기 위한 장치
ps Getter 와 Setter 는 메서드이다.

Getter
외부에서 객체의 private 한 필드를 읽을 필요가 있을 때 , Getter 메서드를 사용

? 왜? private 만들고? >> 그 이유는 캡슐화가 답이다. 중요한 정보를 은닉하고('{ }' 의 내부 코드), 필요할 때만 쏙쏙 쓰는!( - return 값만을 추출! )

Getter 메서드 사용
get + 필드명 ( < - 첫글자는 대문자 ) (){}


private double speed;  // 자동차 속도 , km/h
private char gear = 'P'; // 기어의 상태, P,R,N,D
private boolean lights; // 자동차 조명의 상태

public String getModel() { < - 필드명 앞에 get
    return model;
}

public String getColor() {
    return color;
}

public double getPrice() {
    return price;
}

Setter
외부에서 객체의 private 한 필드를 저장 수정이 필요할 때 , Setter 메서드를 사용
ps 사용법은 Getter와 같다!

제어자의 조합 < - 위에는 접근 제어자!!
사용가능한 제어자
클래스 : public, default, final, abstract
메서드 : public, protected, default, private, final, abstract, static
멤버 변수 : public, protected, default, private, final, static
지역변수 : final

⚠️ 제어자 사용 시 주의 사항

메서드에 staticabstract를 함께 사용할 수 없다. < - 추상화 개념 -메모
클래스에 abstractfinal을 동시에 사용할 수 없다. < - 추상화 개념 -메모
abstract메서드의 접근 제어자가 private일 수 없다. < - 추상화 개념 -메모
메서드에 privatefinal을 같이 사용할 필요는 없다.


패키지와 임포트

패키지와 임포트
같은 패키지에 있지않은 클래스를 이용하여 객체를 만들려면, import 를 통해서 해당 클래스가 있는 패키지를 가지고온다.

하위패키지를 .(도트)로 구분한다.

ps import 를 이용하지 않을 시, 생성자를 통해 객체를 만들 때, 이를 명시하면 된다.

package oop.pk1; // < - 패키지 oop.pk1

public class Car { // < - 패키지 oop.pk1 에 Car 클래스
    public void horn() {
        System.out.println("pk1 빵빵");
    }
}

// 1.

package oop.main; // < - 패키지 oop.pk1 와 다른 
					// oop.main; 패키지!

public class Main {
    public static void main(String[] args) {
        oop.pk1.Car car = new oop.pk1.Car(); // < - 이 처럼 해준다!
        								// import 를 안했을 시
        car.horn(); // pk1 빵빵

    }
}

// 2.

package oop.main;

import oop.pk1.Car; // < - 이 처럼도 가능!

public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        car.horn(); // pk1 빵빵

    }
}


회고

자바의 객체 지향을 공부 중이다. 오늘 공부는 대충 흘러가면서 듣던 객체 지향이라는 것을 정리해 가면서 들을 수 있는 시간이라 좋았던 거 같다. 하지만 너무 얕고 좁게 알아서... 배움에 조금은 힘듬이 있다.

강의 전체를 다 듣지는 못했지만, 객체 지향을 쓰면서 자바에서 얻어가려는 것이 무엇인지는 조금은 감을 잡은 듯하다.

오늘 조금 더 공부하고, 내일은 3주차 강의(객체 지향)을 마무리하면 좋겠다는 소망이 있다.

ps 아~~~ 알고리즘 문제 풀고 싶어!~!!!!

profile
Spring_4

0개의 댓글