TIL-20240426
2024-04-26
오늘의 학습 🌠
학습 내용 개념 정리 📃
객체
- 속성과 행위로 구성
수많은 관계를 맺고 살아감
- 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 키워드를 통해 변수명에 해당하는 객체의 필드에 접근하여 받아온 매개변수의 매개값을 객체의 필드에 대입하여 저장할 수 있음
- 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 : 같은 클래스 내에서만 접근 가능
- 클래스, 멤버 변수, 메서드, 생성자에 사용되고 지정되어 있지 않다면 default임
사용가능한 접근 제어자
- 클래스 :
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
- 생략 가능
- 인터페이스의 추상 메서드는 구현될 때 반드시 오버라이딩 되어야 함
- 멤버변수 : public static final
- 인터페이슨느 추상 클래스와 마찬가지로 직접 인스턴스를 생성할 수 없기 때문에 클래스에 구현되어 생성됨
- implements 키워드를 사용하여 인터페이스 구현
- 인터페이스의 추상 메서드는 구현될 때 반드시 오버라이딩 되어야 함
- 인터페이스 간 상속의 implements가 아니라 extends 키워드 사용
- 클래스와 다르게 다중 상속 가능
- 디폴트 메서드
- 추상 메서드의 기본적인 구현을 제공하는 메서드
- 메서드 앞에 default 키워드를 붙이며 블럭{}이 존재
- 접근 제어자 public이며 생략 가능
추가 🕤
- 친구가 보내준..사진입니다. 오늘의 tmi는 이 사진이 전부라고 생각이 드네요,,😅
🐱🏍— —🤸🏻♀️ ~~~ 야~호~