1. 추상화의 결과 : class
2. 공통의 특징 :
1) 추상화의 결과 -> class
2) 공통의 특징 :
* 데이터로 표현 -> 변수
* 동작으로 표현 -> 메소드
- 객체 지향 프로그래밍
1) 객체(Object)란?
* 물리적으로 존재하는 것(자동차, 책, 사람)
* 추상적인 것(회사, 날짜) 중에서 자신의 속성과 동작을 가지는 모든 것
* 객체는 필드(속성)과 메소드(동작)으로 구성된 자바 모델링 기능
2) 객체의 상호작용
* 객체들은 서로간에 기능(동작)을 이용하고 데이터를 주고받음 (= 대화한다, 메서드 호출)
3) 객체간의 관계
* 객체 지향 프로그램에서는 객체는 다른 객체와 관계를 맺음
* 관계의 종류
** 집합 관계 : 완성품과 부품의 관계
** 사용 관계 : 객체가 다른 객체를 사용하는 관계
** 상속 관계 : 종류 객체와 구체적인 사물 객체 관계
4) 객체 지향 프로그래밍의 특징
* 캡슐화
** 객체의 필드 메소드를 하나로 묶고, 실제 구현 내용을 감추는 것
** 외부 객체는 객체 내부 구조를 알지 못하며 객체가 노출해 제공하는 필드와 메소드만 이용 가능
** 필드와 메소드를 캡슐화하여 보호하는 이유는 외부의 잘못된 사용으로
* 상속
**
5) 객체와 클래스
* 현실세계 : 설계도 -> 객체
* 자바 : 클래스 -> 객체
* 클래스에는 객체를 생성하기 위한 필드와 메소드가 정의
* 클래스로부터 만들어진 객체를 해당 클래스의 인스턴스 객체
* 인스턴스 = 예
- 클래스 선언
1) 클래스의 이름
* 자바 식별자 작성 규칙에 따라야
** 1. 하나 이상의 문자로 이루어져야 한다.
** 2. 첫 번째 글자는 숫자가 올 수 없다. (Pascal Case)
** 3. '$', '_' 외의 특수문자는 사용할 수 없다.
** 4. 자바 키워드는 사용할 수 없다.
2) 클래스 선언와 컴파일
* 소스 파일 생성: 클래스이름.java (대소문자 주의)
* 소스 작성 :
public class 클래스 이름 {} -> 컴파일 javac.exe -> 클래스이름.class (JVM-java.exe가 실행시키는 바이너리 코드)
* 소스 파일당 하나의 클래스를 선언하는 것이 관례
** 두 개 이상의 클래스도 선언 가능
** 소스 파일 이름과 동일한 클래스만 public으로 선언 가능
** 선언한 개수만큼 바이트코드 파일이 생성
3) 객체 생성과 클래스 변수
* new 연산자 = 객체 생성 역할
new 클래스(); -> 생성자 호출
-> heap에 인스턴스가 들어가고 멤버변수가 잡힘, 그리고 0으로 초기화 함.
** 클래스()는 생성자를 호출하는 코드
** 생성된 객체는 힙 메모리 영역에 생성
* new 연산자는 객체를 생성 후, 객체 생성 번지 리턴
4) 클래스 변수
* new 연산자에 의해 리턴된 객체의 번지 저장 (참조 타입 변수)
* 힙 영역의 객체를 사용하기 위해 사용
타입 변수;
타입(클래스명과 동일) 변수 = new 클래스();
5) 클래스의 용도
* 라이브러리(API: Applicatio Program Interface) 용
** 자체적으로 실행되지 않음
** 다른 클래스에서 이용할 목적으로 만든 클래스
* 실행용
** main() 메소드를 가지고 있는 클래스로 실행할 목적으로 만든 클래스 :
1개의 애플리케이션 = (1개의 실행클래스) + (n개의 라이브러리 클래스)
- 클래스의 구성 멤버
1) 클래스의 구성 멤버
* 필드 : 객체의 데이터가 저장되는 곳
* 생성자 : 객체 생성시 초기화 역할 담당
* 메소드 : 객체의 동작에 해당하는 실행 블록
- 필드
1) 필드의 내용
* 객체의 고유 데이터
* 객체가 가져야 할 부품 객체
* 객체의 현재 상태 데이터
=> String company에서 String은 클래스이다.
=> 자바 어딘가에서 정의가 되어있기 때문에 가져다 쓸 수 있는 것이다.
2) 타입 필드 [=초기값];
publc class Car {
String company = "현대자동차";
String model = "그랜저";
int maxSpeed = 300;
int productionYear;
int current speed;
boolean enginePart;
}
3) 필드 사용
* 필드 값을 읽고, 변경하는 작업
* 필드 사용 위치
* 객체 내부 : "필드이름"으로 바로 접근
* 객체 외부 : "변수.필드이름" 으로 접근
- 생성자
1) 생성자
* new 연산자에 의해 호출되어 객체의 초기화 담당 (멤버 변수 초기화)
* 필드의 값 설정
* 메소드 호출해 객체를 사용할 수 있도록 준비하는 역할 수행
2) 기본 생성자
* 모든 클래스는 생성자가 반드시 존재하며 하나 이상 가질 수 있음
* 생성자 선언을 생략하면 컴파일러는 기본생성자를 추가
* 모든 클래스는 생성자를 가진다.
* new 했을 대 반드시 생성자 호출함.
* 모든 언어들은 이 매카니즘을 동일하게 갖고 있다.
- 생성자
1) 생성자 선언
* 개발자 선언한 생성자 존재 시 컴파일러는 기본 생성자 추가하지 않음.
2) 생성자를 다양화해야 하는 이유 (오버로딩)
* 객체 생성할 때 외부 값으로 객체를 초기화할 필요
* 외부 값이 어떤 타입으로 몇 개가 제공될 지 모름
** 여러 버전의 생성자가 준비
* [생성자의 오버로딩] : 매개변수의 타입, 개수, 순서가 다르게 선언. -> 매개변수의 이름과 리턴타입은 관여하지 않음.
==> 오버로딩시 기본생성자와 모든 것을 다 받는 생성자 2가지를 디폴트(기본적으로)로 만듦.
3) 다른 생성자 호출 (this()) --> 이거 뭐 정리하려고 했던거더라.. 흠...
<정리>
- 생성자 :
1) 기본생성자
2) 모든 필드를 전달받는 생성자
==> 이렇게 일반적으로 2가지를 모두 만듬.
<static (정적)>
- static변수
* 객체생성(== 인스턴스 == new)과 상관없이 클래스에 1개만 갖고 있으면서, 생성된 여러 개의 객체들이 공유할 목적으로 만든 변수
* 객체생성시는 멤버변수가 객체마다 따로 생성 (다이나믹한 성격, 인스턴스 변수)
* static 변수 : RAM 중에서 클래스의 원본영역에 있음. static 영역, 메소드 영역
* 인스턴스변수 : 힙영역(랜덤접근하여 크기가 맞으면 할당이 가능)
==> 인스턴스(객체생성)를 하지 않으면 클래스를 불러오지 않으므로 실체가 없다고 할 수 있음.
==> 하지만, static 키워드를 붙이면 인스턴스와 상관 없이 항상 존재함.
- static은 method, field(변수)에 붙일 수 있음.
- 메소드 영역 안에 static 영역이 있는데, static 변수는 이 안에 존재한다.
- static 변수는 프로그램이 시작될 때 할당되며, 프로그램이 끝날 때 사라진다. == 전역변수와 비슷함. (하지만, 자바에는 전역변수가 없다. 명심..!)
- 하지만 어디서나 쓸 수 있는 것은 아니다. 접근제한자에 따라서 결정이 됨.
- Life Time : 프로그램이 시작할때 생성, 프로그램이 끝날 때 사라짐(정확하게는 해당 클래스가 메모리에 로드될때 생성되고, 프로그램이 끝날 대 사라짐) == 정적이다.
System.out.println(); ==> System은 클래스(이름이 대문자로 시작), out은 static 변수('.'으로 불러올 수 있고, 이탤릭체로 표시됨.), println()은 메소드(()로 끝나므로)
- static 메소드 안에서는 this를 못씀.
- static은 인스턴스와 무관한 정보를 보관하는 것.
<final>
- final은 상수, 더이상 수정 불가라는 뜻.
- 그러나 static이 붙으면 의미가 달라짐.
<static>
- 계산을 통해서 값이 결정되는 경우 : 여러 줄 계산해서 나중에 값이 결정될 때... => 정적 초기화 블록
- 정적 초기화 블록
static {
...
}
==> 맨 마지막에 초기화함.
- 정적 메소드와 정적 블록 작성시 주의할 점
* this 를 사용 못함.
* 객체가 없어도 사용 가능
package java_study.chapter07.sec06;
public class Tv {
static String company = "Samsung";
static String model = "LCD";
static String info;
static {
// static 메서드 내에서는 static 변수만 사용 가능하다.
// this로 접근을 못하기 때문에.
info = company + " - " + model;
}
}
- 싱글톤(Singleton) : 하나의 애플리케이션 내에서 단 하나만 생성되는 객체
인스턴스가 있는데, 딱 하나만 있는거..? 라고?
명칭은 얼마든지 바꿀 수 있음.
하지만, 절차는 맞춰줘야 함.
* Singleton : GoF(Gangs of Four)의 디자인 패턴 16가지 중 하나.
싱글턴 패턴이라고도 부름.
public class Singleton {
private static Singleton singleton = new Singleton();
// 자동초기화
// 이때 딱 1번 생성이 됨.
// private도 중요함.
// 왜냐하면 외부에서 Singleton.singleton = null; 로 없애버릴 수 있기 때문에.
// 결론적으로 외부에서 생성 및 소멸을 막기 위해서 만들어진 패턴임.
private Singleton() {
}
public static Singleton getInstance() {
return singleton;
}
private String dbname = "bbs 데이터베이스";
public void open() {
System.out.println(dbname + " 열기");
}
public void close() {
System.out.println(dbname + " 닫기");
}
public void read() {
System.out.println(dbname + " 읽기");
}
}
<상속 (Inheritance)>
- OOP의 꽃
- 학습목표 : 클래스를 재사용하여 다른 클래스를 만들 수 있다.
- 상속의 활용
* 상속 : 부모님의 재산을 물려받는거..?
* 객체지향에서는 자식 클래스가 부모 클래스의 멤버를 물러받는 것을 말한다.
* 부모 : 기존에 만들어진 클래스.
- 상속의 효과
* 코드 재사용하기 매우 좋아짐.
public class A {
int field1;
void method1() { ... }
}
public class B extends A {
String filed2;
void method2() { ... }
}
* 메모리 보단 UML이라는 용어를 자주 사용할 것임.
* UML : Unified Modeling Language
- extends 키워드
* 자바는 단일상속만 허용..
-> use
➡ 상속
<UML Class Diagram - 실제로 실무에서 쓰임>
1. 네모를 그리고 그 안에 클래스 명을 쓴다.
2. CellPhone안에 변수명을 적음. (타입 및 접근제한자와 함께)
* + : public
* - : private
* : default (기호가 아무것도 없음)
* # : protected
< 부모 생성자 호출 (super (...)) >
1) 자식 객체 생성하면 부모 객체도 생성되는가?
- 부모 없는 자식 없음
* 자식 객체 생성할 때는 부모 객체부터 생성 후 자식 객체 생성
* 부모 생성자 호출 완료 후 자식 생성자 호출 완료
DmbCellPhone dmbCellPhone = new DmbCellPhone();
* 부모 생성자의 변수 초기화는 부모 클래스에서 하는게 좋음.
* 자식 클래스 생성자에서 가장 먼저 부모생성자를 호출함.
public CellPhone() {
String model;
}
public DmbCellPhone() {
// 자식 생성자
super(); // <= 부모 생성자 호출
}
2) 명시적인 부모 생성자 호출
- 부모 객체 생성할 때, 부모 생성자 선택해 호출
자식클래스 (매개변수선언, ...) {
super(매개값, ...);
...
}
3) super(매개값, ...)
- 가장 첫줄에 위치해야 함.
- 매개값과 동일한 타입, 개수, 순서 맞는 부모 생성자 호출
- 부모 생성자 없다면 컴파일 오류 발생
- 반드시 자식 생성자의 첫 줄에 위치
- 부모 클래스에 없는 기본(매개변수 없는) 생성자가 없다면 필수 작성
==> 에러나는 이유 : extends로 부모 클래스를 상속받았는데, 부모 클래스에 기본 생성자가 없기 때문.
==> super() 를 별도로 지정하지 않으면 컴파일러가 자동으로 super() 를 만들어주는데, 이것은 기본생성자를 불러오겠다는 뜻이기 때문이다.
- super (...) : 부모 생성자 호출
- this (...) : 자신의 다른 생성자 호출
보통 클래스에서 extends가 존재하지 않는 경우도 있는데,
이때는 extends Object가 생략된 상태인것이다.
이것은 부모가 존재한다는 뜻이다.
- 모든 자바클래스는 기본적으로 Object 라는 최상위 클래스의 자식이다.
<메소드 재정의(@Override)>
1) 메소드 재정의(@Override)
- 부모 클래스의 상속 메소드 수정해 자식 클래스에서 재정의하는 것.
2) 메소드 재정의 조건
- 부모 클래스의 메소드와 동일한 시그니처(모양 - 리턴값, 이름, (매개변수..)) 가져야 함.
- 접근 제한을 더 강하게 오버라이딩 불가
* public을 default나 private으로 수정 불가
* 반대로 default는 public으로 수정 가능
- 새로운 예외(Exception) throws 불가 (예외처리는 10장 참조)
3) @Override의 역할 :
재정의 하고자 하는 부모의 메서드와 완전히 이름이 동일해야 재정의가 가능한데,
이름이 조금만 달라져도 재정의가 불가능 하므로 재정의 할 클래스를 잘 설정했는지 확인해주는 역할을 함.
(만약에 부모의 메서드와 다른 이름으로 메서드를 재정의하려고 하면 빨간줄로 표시해줌.)
(@ : annotation - 주석)
일종의 컴파일러에게 주는 지시사항인 것임.
4) 부모 메소드 사용(super)
- 메소드 재정의는 부모 메소드 숨기는 효과!!!
5) 부모 method() { ... } => 자식 method() { ... } 인 경우
- 수정 없이 그대로 쓰는 경우
- 완전히 다르게 대체하는 경우
- 부모메소드 사용하면서 추가코드를 넣는 것.
- 생성자가 아닌 다른 메소드에서는 아무 곳에서나 불러올 수 있다. (굳이 맨 처음이 아니어도 됨.)
6) 전처리, 후처리 개념
- 전처리 : 내 할일 먼저 하고, 그 후에 부모 일 하는 것.
- 후처리 : 부모 일 먼저 하고, 내 할일을 나중에 하는 것.
보통은 후처리의 코드가 많이 쓰임.
7) final 클래스와 final 메소드
- final 키워드의 용도
* final 필드 : 수정불가 필드 (상수)
* final 클래스 : 부모로 사용 불가한 클래스 (상속 불가한 클래스) -> 대표적으로 String 클래스
* final 메소드 : 자식이 재정의할 수 없는 메소드 (override 불가)
- 상속할 수 없는 final 클래스
* 자식 클래스 만들지 못하도록 final 클래스로 생성
public final class 클래스 {...}
public final class String {...}
public class NewString extends String {...} <- 불가능
<protected 접근제한자>
1. public : 모두 공개
2. default : 같은 패키지에서 공개
3. private : 공개하지 않겠다.
4. protected :
protected는 상속에서 약간 부족함.
멤버변수는 일반적으로 private로 숨겨야 함.
private는 상속은 되지만, 메서드를 통해서만 접근이 가능함. (직접 접근 불가능.)
-> 이것이 매우 불편함.
그럼 결국에는 default를 사용해야 하는데, 이때의 전제는 같은 패키지 안에서만 사용 가능하다는 것이다.
하지만, 일반적으로 같은 패키지 안에서 사용할 가능성이 매우 드물다.
왜냐하면 부모 클래스가 주로 라이브러리가 되기 때문이다.
-> 이 문제를 해결해주는 접근제한자가 바로 protected 이다.
접근 가능 범위
private < default < protected(같은 패키지, 상속 관계일 때 접근 허용) < public
1) protected 접근 제한자
- protected 접근 제한자
* 상속과 관련된 접근 제한자
* 같은 패키지 : default와 동일
* 다른 패키지 : 자식 클래스만 접근 허용
그래서 강사님은 일반적으로 무조건 protected를 주신다고 함.
조심해야 할 것
‼️ 생성자문제
!! override
SOLID 원칙
S : SRP (Single Responsibility Principle)
O : Open Close Principle (기능확장, 변화... -> 기능확장이 되었다고 해서 내 코드가 변경되면 안된다..?)
L : Liscope 치환원리
I : Interface Seperate (인터페이스 분리원칙)
D : DIP (Dependency Inversion Principle, 의존역전성의 원칙)
<타입변환과 다형성(OOP의 꽃) - polymorphism>
1) 다형성
- 같은 타입이지만, 실행 결과가 다양한 객체 대입(이용) 가능한 성질
* 부모 타입에는 모든 자식 객체가 대입 가능 : 자식 타입은 부모 타입으로 자동 타입 변환
* 효과 : 객체 부품화 가능
2) 자동 타입 변환(Promotion)
- 프로그램 실행 도중에 자동 타입 변환이 일어나는 것
부모클래스 타입의 변수는 자식 클래스 타입을 지칭할 수 있음.
-> 이게 어떤 의미냐 하면
동물 > 고양이, 사람 > 학생인데,
고양이를 동물로 부르는게 가능하고, 학생을 사람으로 부르는게 가능하기 때문임.
작은 범위에서 큰 범위로 변경은 가능하나, 큰 범위에서 작은 범위로의 변경은 불가능하다.
자식 -> 부모로 변환되는 것을 UpCasting이라고 부름.
부모 -> 자식으로 변환되는 것, 또는 큰 타입에서 작은타입으로 변환되는 것을 DownCasting이라고 부름.
DownCasting은 상황에 따라서 될 수도, 안될 수도 있다.
다운캐스팅은 개발자가 일종의 책임을 지고 변환해야 하는 위험성을 감수해야 함.
3) 자동 타입 변환(Promotion)
- 프로그램 실행 도중에 자동 타입 변환이 일어나는 것
Cat cat = new Cat(); -> ok
Animal animal = cat; -> 가능은 함.. 다만 위험을 감수해야 함.
// Animal animal = new Cat(); 도 가능하다
cat == animal -> true
- 바로 위의 부모가 아니더라도 상속 계층의 상위면 자동 타입 변환 가능
- 변환 후에는 부모 클래스 멤버만 접근 가능
==> 이런 상황이 가능한 이유는
이 부분때문이다. (이 부분 때문에 오버라이드 되기 때문에.)
'멀티캠퍼스 > Spring' 카테고리의 다른 글
20230810 (목) (0) | 2023.08.10 |
---|---|
20230809 (수) (0) | 2023.08.09 |
20230807 (월) (0) | 2023.08.07 |
20230731 (월) (0) | 2023.08.04 |
20230802 (수) (0) | 2023.08.02 |