자바기본 ? -

존스노우·2024년 1월 13일
0

JAVA

목록 보기
3/5

영한님 강의가 나온기념으로 적는 자바 강의 리뷰

클래스?

  • 자바는 클래스랑 객체로 이루어짐

  • 왜 필요 할까..

  • 변수로 학생들 표현

  • 배열로 학생을 표현
  • 참 불편하다.
  • 데이터 관리도 조심해야되고 여러가지 문제점이 많지.
  • 클래스를 이용해 학생이란 개념으로 하나로 묶는게 제일 좋지

  • 요렇게 정리하고
  • 멤버 변수(Member Variable): 이 변수들은 특정 클래스에 소속된 멤버이기 때문에 이렇게 부른다.
  • 필드(Field): 데이터 항목을 가리키는 전통적인 용어이다. 데이터베이스, 엑셀 등에서 데이터 각각의 항목을 필드 라 한다.

  • 관리가 좀더 쉬워 졌다.

클래스와 사용자 정의 타입

  • 타입은 데이터의 종류나 형태를 나타낸다.

  • int 라고 하면 정수 타입, String 이라고 하면 문자 타입이다.

  • 학생( Student )이라는 타입을 만들면 되지 않을까?

  • 클래스를 사용하면 int , String 과 같은 타입을 직접 만들 수 있다.

  • 사용자가 직접 정의하는 사용자 정의 타입을 만들려면 설계도가 필요하다. 이 설계도가 바로 클래스이다.

  • 설계도인 클래스를 사용해서 실제 메모리에 만들어진 실체를 객체 또는 인스턴스라 한다.

    변수선언

객체 생성

  • Student클래스는String name,int age,int grade` 멤버 변수를 가지고 있다. 이 변수를 사용하는 데 필요한 메모리 공간도 함께 확보한다.

참조값 보관

  • 객체를 생성하면 자바는 메모리 어딘가에 있는 이 객체에 접근할 수 있는 참조값(주소)( x001 )을 반환한다.

  • new 키워드를 통해 객체가 생성되고 나면 참조값을 반환한다. 앞서 선언한 변수인 Student student1 에 생 성된 객체의 참조값( x001 )을 보관한다

  • Student student1 변수는 이제 메모리에 존재하는 실제 Student 객체(인스턴스)의 참조값을 가지고 있 다.

    • student1 변수는 방금 만든 객체에 접근할 수 있는 참조값을 가지고 있다. 따라서 이 변수를 통해서 객체 를 접근(참조)할 수 있다. 쉽게 이야기해서 student1 변수를 통해 메모리에 있는 실제 객체를 접근하고 사용할 수 있다.

참조값을 변수에 보관해야 하는 이유

  • 객체를 생성하는 new Student() 코드 자체에는 아무런 이름이 없다. 이 코드는 단순히 Student 클래스를 기반으 로 메모리에 실제 객체를 만드는 것이다. 따라서 생성한 객체에 접근할 수 있는 방법이 필요하다. 이런 이유로 객체를 생 성할 때 반환되는 참조값을 어딘가에 보관해두어야 한다. 앞서 Student student1 변수에 참조값( x001 )을 저장 해두었으므로 저장한 참조값( x001 )을 통해서 실제 메모리에 존재하는 객체에 접근할 수 있다
Student student1 = new Student(); //1. Student 객체 생성
Student student1 = x001; //2. new Student()의 결과로 x001 참조값 반환
student1 = x001; //3. 최종 결과
  • 그러니까 으음 변수 = new Student() 변수에 참조값보관!?
  • 접근할 방법이 필요하니 변수에다 저장

  • 참조값들을 확인

객체 값 대입

  • 변수( student1 )에 들어있는 참조값( x001 )을 읽어서 메모리에 존재하는 객체에 접근한다.
student1.name="학생1" //1. student1 객체의 name 멤버 변수에 값 대입
x001.name="학생1" //2.변수에 있는 참조값을 통해 실제 객체에 접근, 해당 객체의 name 멤버 변수에 값
대입
  • student1x001 이라는 참조값을 가지고 있으므로 x001 위치에 있는 Student 객체에 접근한다.

객체 값 읽기

//1. 객체 값 읽기
System.out.println("이름:" + student1.name);
//2. 변수에 있는 참조값을 통해 실제 객체에 접근하고, name 멤버 변수에 접근한다.
System.out.println("이름:" + x001.name);
//3. 객체의 멤버 변수의 값을 읽어옴
System.out.println("이름:" + "학생1");

클래스 객체 인스턴스 정리

  • 클래스는 설계도 ! 객체를 생성하기위한 .
  • 속성(변수) 기능(메서드)) 정의

객체 - Object
객체는 클래스에서 정의한 속성과 기능을 가진 실체이다. 객체는 서로 독립적인 상태를 가진다.
예를 들어 위 코드에서 student1 은 학생1의 속성을 가지는 객체이고, student2 는 학생2의 속성을 가지는 객체이 다. student1student2 는 같은 클래스에서 만들어졌지만, 서로 다른 객체이다.

인스턴스 - Instance
인스턴스는 특정 클래스로부터 생성된 객체를 의미한다. 그래서 객체와 인스턴스라는 용어는 자주 혼용된다. 인스턴스 는 주로 객체가 어떤 클래스에 속해 있는지 강조할 때 사용한다. 예를 들어서 student1 객체는 Student 클래스의 인스턴스다. 라고 표현한다.

객체 vs 인스턴스
둘다 클래스에서 나온 실체라는 의미에서 비슷하게 사용되지만, 용어상 인스턴스는 객체보다 좀 더 관계에 초점을 맞춘 단어이다. 보통 student1Student 의 객체이다. 라고 말하는 대신 student1Student 의 인스턴스이다. 라고 특정 클래스와의 관계를 명확히 할 때 인스턴스라는 용어를 주로 사용한다.
좀 더 쉽게 풀어보자면, 모든 인스턴스는 객체이지만, 우리가 인스턴스라고 부르는 순간은 특정 클래스로부터 그 객체가 생성되었음을 강조하고 싶을 때이다. 예를 들어 student1 은 객체이지만, 이 객체가 Student 클래스로부터 생성되 다는 점을 명확히 하기 위해 student1Student 의 인스턴스라고 부른다.
하지만 둘다 클래스에서 나온 실체라는 핵심 의미는 같기 때문에 보통 둘을 구분하지 않고 사용한다.

  • 결론 구분하지 말고 쓰자

배열

  • Student 타입의 변수는 Student 인스턴스의 참조값을 보관한다. Student 배열의 각각의 항목도 Student 타입의 변수일 뿐이다. 따라서 Student 타입의 참조값을 보관한다.
    student1 , student2 변수를 생각해보면 Student 타입의 참조값을 보관한다.
    배열에는 아직 참조값을 대입하지 않았기 때문에 참조값이 없다는 의미의 null 값으로 초기화 된다.

  • 이제 참조 값을 보관하자면 ?

  • students[0] = student1; 이런식으로..

  • students[0] = x001;

  • students[1] = x002;

  • 이런식으로 참조값이 보관된다.


  • 배열 참조 -> 배열 0 / 1번 가서 또 주소값 참조값을 가짐
  • 두 학생을 모두 접근 가능

자바에서 대입은 항상 변수에 들어 있는 값을 복사해서 전달한다.
students[0] = student1;
students[1] = student2;
//자바에서 대입은 항상 변수에 들어 있는 값을 복사한다.

students[0] = x001;
students[1] = x002;

  • 자바에서 변수의 대입( = )은 모두 변수에 들어있는 값을 복사해서 전달하는 것이다. 이 경우 오른쪽 변수인
    student1 , student2 에는 참조값이 들어있다. 그래서 이 값을 복사해서 왼쪽에 있는 배열에 전달한다. 따라서 기존 student1 , student2 에 들어있던 참조값은 당연히 그대로 유지된다.

주의!

  • 변수에는 인스턴스 자체가 들어있는 것이 아니다! 인스턴스의 위치를 가리키는 참조값이 들어있을 뿐이다! 따라서 대입 ( = )시에 인스턴스가 복사되는 것이 아니라 참조값만 복사된다.

학생1 예제

System.out.println(students[0].name); //배열 접근 시작
System.out.println(x005[0].name); //[0]를 사용해서 x005 배열의 0번 요소에 접근
System.out.println(x001.name); //.(dot)을 사용해서 참조값으로 객체에 접근
System.out.println("학생1");
  • 배열 접근 -> 참조값 접근

기본 참조형

  • 사용하는 값을 변수에 직접 넣는 기본형
  • 객체가 저장된 메모리 위치를 가르키는 참조값을 넣는 참조형

  • 쉽게 구분하는 기본형과 참조형

  • but 대문자로 시작하는 String 은 참조형! 클래스이기 때문

기본 참조형 2

  • 자바는 항상 변수의 값을 복사해서 대 입한다.. 복사해서 대입

int a = 10
int b= a; //a의 값을 복사해서 넣어주기 때문에 복사값이다.

Student s1 = new Student(); // x001 참조값
Student s2 = s1;

// 기본형 -> 해당 값을 복사해서 바로 대입
// 참조값 -> 객체의 위치를 가르키는 참조값만 복사

  • 쉽게 이해해서 실제 건물이 복사 되는것이 아니라
  • 건물의 위치인 주소만 복사 되는 것이다.
  • 건물을 찾아갈 수 있는 방법이 하나 더 늘어나는 것

  • 간단한 기본형 예시 쉬운 내용
  • 변수의 대입은 변수에 들어있는 값을 복사 대입.

  • 참조형 예제

기본형과 참조형 3 - 메서드 호출

  • 기본형이라 그림 만

참조형 과 메서드 호출


기본형과 참조형의 메서드 호출

  • 자바에서 메서드의 매개변수(파라미터는)항상 값에 의해 전달! (중요)

  • 근대 그게 실제 값이냐 ? 참조 값이냐 따라 동작이 다름

  • 기본형 : 종이가 2장있는대 옆사람 종이에게 내가 가진 숫자를 적어 준 것. 옆종이의 값을 바꾼다고 내것이 바뀌는 건 아니지!

  • 참조형: 종이에 주소지가 있음 주소지를 적어서 옆사람에게 전달
    옆사람이 주소지 찾아가서 건물에 있는걸 변경
    내가 그 주소지를 찾아가면 변경된걸 발견

    참조형과 메서드 호출 - 활용


  • 참조값 x001 넘겨서 각 참조값들을 출력하는 기본 예제
  • 앞선 예제를 함수로 빼서 간략하게 표현하는 예제


  • 전에 배웟던 얕은 복사를 깊은 복사로 바꾸는 예제라 생각하면 편할 듯

변수와 초기화

  • 각 초기화
  • 지역변수는 수동으로 초기화 해줘야됨 .
  • 초기화 안돼있고 찾아가야되면 어떤값이 들어가있는지 모르기 때문? 초기화 안하면 사용 못해요


  • 초기화 안한 값과 초기화 한 값.

NULL


  • 이 집을 찾아갈 주소 자체가 존재하지 않으므로

NULL POINTEXCEPTION

  • 주소지 없는 택배를 발송하면?
  • 참조값 없이 객체를 찾아가면 어떤 문제가 발생?
  • 예외 발생!
  • 말 그대로 NULL 을 가리키다 (POINTER) 이때 발생하는 예외란 뜻
  • 주소가 없는 곳을 찾아갈 때 발생하는 예외


  • NULL 에다 . 을찍는다해서 NULLPOINTEXCEPTION
  • NULL 을가르킨다 해서..


  • NULL 에다 점 찍으니 에러가나지!

  • 참조값 예외가 발생하는 과정

  • 참조할걸 주면 된다.

객체지향 프로그래밍

절차지향 프로그래밍

  • 이름 그대로 절차 지향 실행 순서를 중요하게 하는 방식
  • 프로그램 흐름따라 처리하는 방식 "어떻게" 중심 프로그래밍

객체지향 프로그래밍

  • 말 그대로 객체 지향. 객체가 중요하다

  • 실제 세계의 사물이나 사건을보고 객체들간 상호작용 프로그래밍

  • 흔히 아는 개념..

차이?

  • 절차지향: 데이터와 해당 데이터 대한 처리방식 분리.
  • 객체지향 : 데이터와 그 데이터에 대한 행동((메서드) 하나 객체 안에 포함 되어 있음

  • 대표적인 절챠지향 코드

  • 점진적으로 개선

  • 메서드 추출

  • 각각의 기능이 모듈화가 되었음

  • 중복로직 제거 / 변경 영향 범위: 기능 수정시 메서드 내부만 변경

  • 메서드 이름추가: 메서드의 이름으로 코드를 좀더 쉽게 이해!

모듈화

  • 쉽게 이야기해서 레고 블럭을 생각하면 된다. 필요한 블럭을 가져다 꼽아서 사용할 수 있다. 여기서는 음
    악 플레이어의 기능이 필요하면 해당 기능을 메서드 호출 만으로 손쉽게 사용할 수 있다. 이제 음악 플레이어와 관
    련된 메서드를 조립해서 프로그램을 작성할 수 있다

한계

  • 위에 작성한 코드는 데이터와 기능이 분리되어 있음,

  • 음악 플레이어 데이터 : MusicPlayerData에 있는데

  • 그 데이터를 사용하는 기능은 MusicPlayerMain3에 있는 각각 메서드의 분리

  • 음악플레이어 관련된 데이터는 MusicPlayerData 사용

  • 음악플레이어 관련된 기능은 MusicPlayerMain3 각 메서드를 사용해야함.

  • 데이터 / 데이터 사용기능은 매우 밀접하게 연관되 있음.

  • 각각의 메서드는 MusicPlayerData의 데이터를 사용, 따라서 이후 데이터 변경시

  • MusicPlayerMain3 메서드 함께변경,

  • 이런식으로 데이터 / 기능이 분리되어있으면 유지보수관점 포인트가 2곳으로 늘어남

  • 설명을 참잘하신다..

클래스와 메서드



valueObject.add(); //1
x002.add(); //2: x002 ValueObject 인스턴스에 있는 add() 메서드를 호출한다.

  • 결론적으로 객체지향 프로그래밍을 짜는 과정
  • 데이터와 기능을 클래스 안에 둠으로서 유지보수관점에서 더 유리해 짐

객체지향 프로그래밍

  • 데이터와 기능을 묶어서 음악


  • 데이터와 기능을 클래스에 모두 담아 둠으로서 코드가 모듈화도되면서 가독성이 더 좋아짐

  • 세상의 존재하는 사물을 최대한 클레스로 표현 (멤버와 메서드로 표현)

생성자

생성자가 필요한 이유?

  • 객체 생성시점에 어떤 작업 하고싶으면? 생성자 이용하면 됨


  • 기초적인 생성자 이용 클래스

  • 메서드를 이용해 간편하게 코드를 줄임
  • MemberInit 이 자기 자신의 데이터를 변경하는 기능(메서드)을 제공하는 것이 좋다. (객체지향)

this?

  • this를 사용해 메서드 추가
  • 멤버 변수와 메서드의 매개변수의 이름이 같으면 둘을 어떻게 구분해야 할까

멤버 변수와 메서드의 매개변수의 이름이 같으면 둘을 어떻게 구분해야 할까?
이 경우 멤버 변수보다 매개변수가 코드 블럭의 더 안쪽에 있기 때문에 매개변수가 우선순위를 가진다. 따라서
initMember(String name,...) 메서드 안에서 name 이라고 적으면 매개변수에 접근하게 된다.
멤버 변수에 접근하려면 앞에 this. 이라고 해주면 된다. 여기서 this 는 인스턴스 자신의 참조값을 가리킨다


  • this 사용하지않으면 매개변수가 우선순위를 가져서 매개변수로 접근하게된다는데..
  • 그래서 멤버변수 접근하기위해 this
  • 위에 예시코드만 보더라도 매게변수를 가리키기 때문에 인텔리제이에서 this.라고 선언하라고 경고한다.


  • 파라미터가 다르면 this.를 생략해도된다 (this가 잇는대 생략되있다?)
  • 그리고 요즘은 IDE에서 색을 구분해주긴함.
  • 시간이 지나면서 멤버변수와 파라미터가 구분이 안돼서 this를 쓰는게 관습이었지만.
  • 요즘은 IDE가 쉽게 구분해주니 굳이 쓸필요가? 물론 명이 같을경우 써야되지만

생성자 - 도입


  • 생성자 도입 예제

  • 생성자는 인스턴스를 생성하고 나서 즉시 호출된다. 생성자를 호출하는 방법은 다음 코드와 같이 new 명령어 다음에
    생성자 이름과 매개변수에 맞추어 인수를 전달하면 된다.

new MemberConstruct("user1", 15, 90)
이렇게 하면 인스턴스를 생성하고 즉시 해당 생성자를 호출한다. 여기서는 Member 인스턴스를 생성하고 바로
MemberConstruct(String name, int age, int grade) 생성자를 호출한다

생성자 장점

//생성자 등장 전
MemberInit member = new MemberInit();
member.initMember("user1", 15, 90);
//생성자 등장 후
MemberConstruct member = new MemberConstruct("user1", 15, 90)

  • 중복호출 제거

생성자의 진짜 장점은 객체를 생성할 때 직접 정의한 생성자가 있다면 직접 정의한 생성자를 반드시 호출해야 한다는 점
이다. 참고로 생성자를 메서드 오버로딩 처럼 여러개 정의할 수 있는데, 이 경우에는 하나만 호출하면 된다
제약...

  • 생성자 덕분에 회원의 이름, 나이, 성적은 항상 필수로 입력하게 된다. 따라서 아무 정보가 없는 유령 회원이 시스템 내
    부에 등장할 가능성을 원천 차단한다

  • 이런식으로 컴파일 오류! 생성자를 정의했는대 안썻으니 !
  • 개발자는 객체를 생성할 때, 직접 정의한 생성자를
    필수로 호출해야 한다는 것을 바로 알 수 있다.

기본 생성자

  • 매개변수가 없는 생성자를 기본 생성자라 한다.
  • 클래스에 생성자가 하나도 없으면 자바 컴파일러는 매개변수가 없고, 작동하는 코드가 없는 기본 생성자를 자동으
    로 만들어준
  • 생성자가 하나라도 있으면 기본생성자는 만들어 주지 않음


왜 기본생성자를 자동으로?

  • 만약 자바에서 기본 생성자를 만들어주지 않는다면 생성자 기능이 필요하지 않은 경우에도 모든 클래스에 개발자가 직
    접 기본 생성자를 정의해야 한다. 생성자 기능을 사용하지 않는 경우도 많기 때문에 이런 편의 기능을 제공한다

정리
생성자는 반드시 호출되어야 한다.
생성자가 없으면 기본 생성자가 제공된다.
생성자가 하나라도 있으면 기본 생성자가 제공되지 않는다. 이 경우 개발자가 정의한 생성자를 직접 호출해야 한다

생성자 오버로딩

  • 생성자를 오버로딩 한 덕분에 성적 입력이 꼭 필요한 경우에는 grade 가 있는 생성자를 호출하면 되고, 그렇지 않은 경
    우에는 grade 가 없는 생성자를 호출하면 된다. grade 가 없는 생성자를 호출하면 성적은 50 점이 된다

  • 중복되는 부분을 this를 사용하면 간편해진다

this() 규칙

  • this() 는 생성자 코드의 첫줄에만 작성할 수 있다

  • 이렇게 컴파일 오류가남 첫번째 줄에작성하라고

패키지

  • 컴퓨터는 보통 파일을 분류하기 위해 폴더, 디렉토리라는 개념을 제공한다. 자바도 이런 개념을 제공하는데, 이것이 바
    로 패키지이다

  • 패키지(package)는 이름 그대로 물건을 운송하기 위한 포장 용기나 그 포장 묶음을 뜻한다.


패키지 규칙

  • 패키지의 이름과 위치는 폴더(디렉토리) 위치와 같아야 한다.
  • 패키지 이름은 모두 소문자 (관례)
  • 패키지 이름의 앞 부분에는 회사의 도메인 이름을 거꾸로 사용함

ex) com.company.myapp 이런식 url 도메인 거꾸로

  • 필수는 아니지만 수 많은 외부 라이브러리가 함께 사용되면
    같은 패키지에 같은 클래스 이름이 존재할 수있음
    이런식으로 거꾸로 사용하면 문제 방지

  • 내가 오픈소스나 라이브러리를 만들어서 외부에 제공하면 지키는게 좋다.

    계층 구조

  • 계층 구조를 이루더라도 서로 다른 패키지이다

  • 보이기엔 계층적으로 이루어져 있어도 서로 다른 패키지

  • 그래서 서로 다른 패키지에서 다른 패키지에있는 소스를 사용할 때 import를 사용해야 된다.

  • 코드 예시

접근제어자

  • 접근 제어자를 사용하면 클래스 외부에서 특정 필드나 메서드 접근하는 것을 허용 하거나 제한을 함

  • 스피커의 음량은 100을 넘어서는 안된다에서 출발
  • 현재 코드는 Private int volume 로 되있지만
  • pulic으로 되잇다면??
  • private 선언이안되있으니 접근해도 된다생각하고
  • 주석의 코드를 실행하게되버린다.

  • 사이드 이펙트가 일어남.

접근제어자 2

  • private 접근제어자는 모든 외부호출 막음 (클래스 내부에서만 호출 가능)

  • speaker 안에서 숨어버려서 speaker내부에서만 접근 가능

  • 좋은 프로그램은 적절한 제약을 제공하는 프로그램이다.

접근제어자 종류

  • private : 모든 외부 호출 막음

  • default(package-private) : 같은 패키지안에서 호출허용
    아무것도 적지않으면 적용됨.

  • protected 같은 패키지안에서 호출허용/ 패키지달라도 상속관계 호출 허용

  • public

package-private

  • 제어자를 명시하지않으면? default 접근제어자 적용

접근 제어자의 핵심은 속성과 기능을 외부로부터 숨기는 것이다.

  • private 은 나의 클래스 안으로 속성과 기능을 숨길 때 사용, 외부 클래스에서 해당 기능을 호출할 수 없다.
  • default 는 나의 패키지 안으로 속성과 기능을 숨길 때 사용, 외부 패키지에서 해당 기능을 호출할 수 없다.
  • protected 는 상속 관계로 속성과 기능을 숨길 때 사용, 상속 관계가 아닌 곳에서 해당 기능을 호출할 수 없다.
  • public 은 기능을 숨기지 않고 어디서든 호출할 수 있게 공개한다
  • 클래스 필드 메서드 영역에서만 쓸수 있다

접근제어자 사용 필드 메서드

  • 이런식으로 접근제어자 예제..

접근제어자 - 클래스 레벨

  • 클래스 레벨의 접근 제어자는 public , default 만 사용할 수 있다.

  • public 클래스는 반드시 파일명과 이름이 같아야 한다.

  • 하나의 자바 파일에 public 클래스는 하나만 등장할 수 있다.

  • 하나의 자바 파일에 default 접근 제어자를 사용하는 클래스는 무한정 만들 수 있다


  • 예시 코드

캡슐화

  • 캡슐화(Encapsulation)는 객체 지향 프로그래밍의 중요한 개념 중 하나다. 캡슐화는 데이터와 해당 데이터를 처리하는 메서드를 하나로 묶어서 외부에서의 접근을 제한하는 것을 말한다.

  • 쉽게 얘기하면 속성과 기능을 하나로 묶고 , 외부에 꼭 필요한 기능만 노출하고 나머지는 모두 내부로 숨기는 것이다

  • 캡슐화를 안전하게 완성해주는 것? 접근제어자

  • 어떤것을 숨기고 어떤것을 노출?

데이터를 숨겨야됨.

  • 객체는 속성 (데이터) , 기능 (메서드) 있음

  • 1번째는 속성(데이터를) 숨겨야 됨. 객체 내부의 데이터를 외부에서 함부로 접근하게 두면 클래스 안에서 데이터를 다루는 모든 로직 무시하고 데이터 변경. (캡슐화깨짐)

  • 우리가 자동차를 운전할 때 자동차 부품을 다 열어서 그 안에 있는 속도계를 직접 조절하지 않는다.
  • 단지 자동차가 제공 하는 엑셀 기능을 사용해서 엑셀을 밟으면 자동차가 나머지는 다 알아서 하는 것이다

기능을 숨겨야 됨.

  • 우리는 자동차를 운전하기 위해 자동차가 제공하는 복잡한 엔진 조절 기능, 배기 기능까지 우리가 알 필요는 없다.

  • 우리는 액셀과 핸들 정도 기능만 알면 됨

  • 가급적 필요한 기능만 오픈하기


  • 캡슐화 예시

자바 메모리 구조

  • 메서드 영역: 클래스 정보 보관 , 이 클래스 정보가 붕어빵 틀..
  • 스택 영역: 실제 프로그램이 실행되는 영역, 메서드를 실행할때마다 하나씩 쌓임
  • 힙 영역: 객체(인스턴스)가 생성되는 영역 new 명령어를 사용하면 이 영역 사용
  • 쉽게 말하면 붕어 빵 틀로부터 생성된 붕어빵이 존재하는 공간 배열도 이 영역에 생성됨

  • 메서드 영역: 프로그램을 싱행하는데 필요한 공통데이터 관리

  • 클래스 정보: 클래스 실행코드(바이트 코드), 필드 , 메서드와 생성자 코드등 모든 실행 코드가 존재함.

  • static 영역: static 변수를 보관

  • 런타임 상수풀: 프로그램 실행하는데 필요한 공통 리터럴 상수 보관.
    "hello" 라는 리터럴 문자가 있으면 이런 문자를 공통으루 묶어서 관리
    이 외에도 프로그램을 효율적으로 관리하기 위한 상수들을 관리함 (알아만두자)

  • 스택 영역: 자바 실행시 하나의 실행스택이 생성 됨.
    각 스택 프로엠은 지역 변수 , 중간연산결과 , 메서드 호출 정보등 포함

  • 스택 프레임 : 스택 영역에 쌓이는 네모 박스가 하나의 스택 프레임.
    메서드 호출할 때마다 하나의 스택프레임이 쌓이고 메소드가 종료되면 스택 프레임이 제거 됨.

  • 힙 영역 : 객체 와 배열이 생성되는 영역 , GC 가 이루어지는 영역

    참고 : 스택 영역은 더 정확히는 각 쓰레드 별로 하나의 실행 스택이 생성됨.

  • 따라서 쓰레드 수 만큼 스택영역이 생성된다, 지금은 쓰레드 1개만 사용하므로 스택 영역도 하나이다,

  • 각각 본인의 메서드와 변수를 가짐

  • 정리하면 메서드를 호출하면 메서드 영역에 있는 코드를 불러서사용
    ( 메서드 영역은 프로그램 실행하는데 필요한 공통데이터를 관리하니)

스택 큐 자료구조

  • 스택에 데이터를 쌓는 그림

  • Last In First Out (LIFO)

선입 선출 (FIFO , First In First Out)

  • 선착순 이벤트시 고객이 대기해야하면 큐 자료구조

스택 영역

  • 스택 구조 코드 실행 (main은 가장 먼저실행했지만 가장 나중에 종료된다)

정리

  • 자바는 스택영역을 사용해서 메서드 호출과 (지역변수 매개변수) 관리
  • 메서드를 계속호출하면 스택 프레임이 계쏙 쌓임
  • 지역 변수(매개변수 포함)는 스택 영역에서 관리함
  • 스택 프레임이 종료되면 지역 변수도 함께 제거 됨.
  • 스택 프레임이 모두 제거되면 프로그램도 종료 됨

스택영역과 힙 영역

  • 스택프레임이 쌓이면서 힙영역에 data인스턴스 생성 참조값은 스택프레임 변수에
  • data2 에도 참조값을 넘기니 스택프레임에도 참조값이 저장되잇는걸 볼수 있음

  • 종료 되면서 (unreachable) 상태가 된다

  • 메서드가 종료되면서 지역 변수들이 참조 값을 가지는 애가 없기 때문에 힙 영역 데이터를 가르키지 않기 때문에

  • GC(가비지 컬렉션)은 이렇게 참조가 모두 사라진 인스턴스를 찾아서 메모리에서 제거한다.

  • ++ : 힙 영역 외부가 아닌, 힙 영역 안에서만 인스턴스끼리 서로 참조하는 경우에도 GC의 대상이 된다

static 변수

  • 인스턴스는 계속 새로 만들어지기 때문에 count 변수로 새로만들어져 1 만나오지
  • 지역변수 count는 서로 공유되지않는 독립적이기때문에..


  • 인스턴스를 공통으로 사용하기 때문에 하나씩 증가한다 .

  • 그런데 여기에는 약간 불편한 점들이 있다.
    Data2 클래스와 관련된 일인데, Counter 라는 별도의 클래스를 추가로 사용해야 한다.

  • 생성자의 매개변수도 추가되고, 생성자가 복잡해진다. 생성자를 호출하는 부분도 복잡해진다

  • 스태틱 변수 (클래스변수 , 정적변수) 를 생성했다

  • static 변수는 쉽게 이야기해서 클래스인 붕어빵 틀이 특별 관리하는 변수!
  • 붕어빵 틀은 1개이므로 클래스 변수도 한개만 존재 반면에 인스턴스 변수는 붕어빵인 인스턴스 수만 큼 존재

  • 인스턴스 변수 : static이 붙지않는 멤버 변수.
    • static이 붙지 않은 멤버변수는 인스턴스를 생성해야 사용 가능하고, -- 인스턴스에 소속-- 되어있다.
    • 따라서 인스턴스 변수
    • 인스턴스 변수는 인스턴스를 만들 때 마다 새로 만들어짐
  • 클래스변수 : static이 붙은 멤버변수
    • 클래스변수 정적변수 스태틱변수등 부름
    • static이 붙은 멘버 변수는 인스턴스 와무관하게 클래스에 접근 사용 가능
    • 클래스 자체에 소속되어있어 클래스 변수라함
    • 클래스 변수는 자바 프로그램을 시작할때 딱 1개 만들어 진다.

생명 주기

  • 지역변수(매개변수 포함):

  • 지역 변수(매개변수 포함): 지역 변수는 스택 영역에 있는 스택 프레임 안에 보관된다. 메서드가 종료되면 스택 프레임도 제거 되는데 이때 해당 스택 프레임에 포함된 지역 변수도 함께 제거된다. 따라서 지역 변수는 생존 주기가짧다

  • 인스턴스 변수 : 인스턴스에 있는 멤버 변수를 인스턴스 변수라 한다. 인스턴스 변수는 힙 영역을 사용한다. 힙 영
    역은 GC(가비지 컬렉션)가 발생하기 전까지는 생존하기 때문에 보통 지역 변수보다 생존 주기가 길다

  • 클래스 변수: 클래스 변수는 메서드 영역의 static 영역에 보관되는 변수이다. 메서드 영역은 프로그램 전체에서
    사용하는 공용 공간이다. 클래스 변수는 해당 클래스가 JVM에 로딩 되는 순간 생성된다. 그리고 JVM이 종료될
    때 까지 생명주기가 어어진다. 따라서 가장 긴 생명주기를 가진다.

static이 정적인 이유?

  • 힙 영역에 생성되는 인스턴스 변수는 동적으로 생성 제거 됨
  • 반면 static인 정적변수는 거의 프로그램 실행에 만들어지고
  • 종료 시점에 제거됨/ 정적 변수는 이름 그대로 정적이다.

"정적"이라는 용어는 변하지 않는, 고정된, 또는 실행 시간 동안 변경되지 않는 것을 의미

  • 인스턴스를 통한 정적변수 접근 / 보통근대 이렇게는 사용안햇는데..

  • 권장하지 않음

  • 왜냐? count라는게 인스턴스변수인가, 멤버변수인가 헷갈릴수 있음

  • 인스턴스를 통해 접근하네? IDE도 경고를 한다.

  • 인스턴스 메서드를 사용하는 예제

  • 앞서 개발한 deco() 메서드를 호출하기 위해서는 DecoUtil1 의 인스턴스를 먼저 생성해야 한다. 그런데 deco()
    라는 기능은 멤버 변수도 없고, 단순히 기능만 제공할 뿐이다.

  • 인스턴스가 필요한 이유는 멤버 변수(인스턴스 변수)등을
    사용하는 목적이 큰데, 이 메서드는 사용하는 인스턴스 변수도 없고 단순히 기능만 제공한다

  • 중요 !!!!! 객체 생성의 의미가 크지가 않다..


  • 정적 메서드로 기능 제공 예제

  • static 이 붙은 정적 메서드는 객체 생성 없이 클래스명 + . (dot) + 메서드 명으로 바로 호출할 수 있다.
    정적 메서드 덕분에 불필요한 객체 생성 없이 편리하게 메서드를 사용했다

  • 클래스 메서드
    메서드 앞에도 static 을 붙일 수 있다. 이것을 정적 메서드 또는 클래스 메서드라 한다. 정적 메서드라는 용어는
    static 이 정적이라는 뜻이기 때문이고, 클래스 메서드라는 용어는 인스턴스 생성 없이 마치 클래스에 있는 메서드를
    바로 호출하는 것 처럼 느껴지기 때문이다.

  • 인스턴스 메서드 static 이 붙지 않은 메서드는 인스턴스를 생성해야 호출할 수 있다. 이것을 인스턴스 메서드라 한다

static 메서드 2

  • static 메서드는 static 만 사용할 수 있다
  • 반대로 모든 곳에서 static 을 호출할 수 있다


  • 정적 메서드 활용

    • 정적 메서드는 객체 생성이 필요 없이 메서드의 호출만으로 필요한 기능을 수행할 때 주로 사용한다.
    • 예를 들어 간단한 메서드 하나로 끝나는 유틸리티성 메서드에 자주 사용한다.
    • 수학의 여러가지 기능을 담은 클래스를 만
      들 수 있는데,
    • 이 경우 인스턴스 변수 없이 입력한 값을 계산하고 반환하는 것이 대부분이다.
    • 이럴 때 정적 메서드를 사용해서 유틸리티성 메서드를 만들면 좋다

final

  • 이름 그대로 끝
  • 더는 값을 변경할수 없다 (변수에 붙으면)

![]ㄴ(https://velog.velcdn.com/images/superkkj/post/2df06055-2e5d-4602-ab0a-c045b060f28b/image.png)

  • 기본적인 예제

  • 초기값이 있으면 변경 불가

  • 생성자로 초기화가가능 하다

  • 각 선언에따른 그림

  • 메모리 낭비(중복) 은 좋지않음 -> static으로 해결

  • static final -> 붙여서 해결 공유하면서 불변의 값

  • 중복 메모리 문제 해결

상수

  • 변하지않고 일정한 값을 갖는 수를 말함,
  • 단 하나만 존재하는 변하지 않는 고정된 값
  • static final

특징

  • static final
  • 대문자를 사용하고 구분은 _ (관례)
  • 일반적 변수와 상수를 구분하기 위해함
  • 기능이아니라 고정된 값 자체를 사용하는 목적
  • 상수 변경 x 당연한 소리

  • 특정위치에 사용시 private 공공으로 사용시 public
  • 코드처럼 중앙에서 값 하나로 관리할 수 있음

  • Constant.MAX_USERS 상수를 사용했다. 만약 프로그램 최대 참여자 수를 변경해야 하면
  • Constant.MAX_USERS 의 상수 값만 변경하면 된다

final 변수와 참조

  • 기본형은 10 , 20

  • 참조형은 참조값

  • final은 값을 변경할수 없기에 기본형은 값 변경 X

  • 참조형은 참조값 변경 x

  • 두둥 ..!

  • 참조값 변경은 안된다
  • 하지만 참조 대상의 값은 변경 가능하다.

  • 궁금해서 적는 그림

상속

  • 기본적인 코드

상속 관계

  • 객체지향 프로그래밍의 핵심 요소 중 하나

  • 기존 클래스의 필드와 메서드를 새로운 클래스에서 재사용 하게함

  • 이름 그대로 부모 클래스의 속성과 기능을 그대로 물여 받음

  • 기본적인 상속 예제
  • 부모는 자식에대한 정보가(코드참조) 하나도 없기때문에 자식클래스에 접근 불가능

단일 상속

  • 비행기와 자동차를 상속받아 하늘을 나는 자동차를 만든다?

  • 그런대 AirplaneCar 입장에서 move()를 호출할때 어떤 move() 사용할지 애매함

  • 이것이 다이아몬드 문제...

  • 이래서 다중상속을 사용하면 계층구조가 매우 복잡해 질수 있다

  • 그러므로 자바는 다중 클래스 상속 허용 x 대신 인터페이스로 해결가능

  • 부모가 또다른 부모를 가지는것 은 괜찬음

상속과 메모리 구조

  • 제일 중요한 부분

  • 위코드에서 상속받은 코드

  • 처음 보는 메모리구조인대 신기함.

  • 상속 관계를 사용하면 부모 클래스를 포함해서 생성

  • 인스턴스는 하나같지만 내부에서는 부모와 자식이 모두 생성되고 공간도 구분 됨.

  • 상속관계의 경우 내부에 부모 자식 모두 존재.
  • 이 때 부모인 car를 통해 charge()를 찾을지 ElectricCar를 통해서 charge() 찾을지 선택 해야함
  • 이 때 ! 호출하는 변수의 타입(클래스)기준으로 선택함
  • electricCar 변수의 타입이 ElectriCar이므로 인스턴스 내부에 같은 타입인 ElectricCar를 통해서 charge() 를 호출함

  • 중요 포인트!

상속과 기능 추가

  • 문열기 기능추가로 자식들은 모두 이 기능을 사용 가능하다.

  • 부모의 기능을 물려받아 좀 더 기능을 추가해서 새로운 기능을 부모에서 좀 더
  • 확장해서 만드는거 기능을 좀더 추가하는 거?
  • 그래서 새로운 수소차는 편리하게 확장한거라 볼수 있다
  • 그래서 EXTANDS..
  • 자동차의 기능을 확장해서 뭔가 새로운것을 더 만든다
  • 자식입장에선 새로운개념을 만든다 그래서 확장이다 흐음

상속 메서드 오버라이딩

  • 부모 타입의 기능을 자식에서는 다르게 재정의 하고 싶을 수 있음

  • ElectricCar 는 부모인 Car 의 move() 기능을 그대로 사용하고 싶지 않다. 메서드 이름은 같지만 새로운 기능을사용하고 싶다.
  • 그래서 ElectricCar 의 move() 메서드를 새로 만들었다.
  • 이렇게 부모의 기능을 자식이 새로 재정의하는 것을 메서드 오버라이딩이라 한다.

@Overide

  • 애노테이션이라고하고 주석과 비슷
  • 프로그램이 읽을 수 있는 특별한 주석
  • 이 애노테이션은 상위 클래스의 메서드를 오버라이드하는 것임을 나타낸다

  • 주석처리해도 동작한다.

  • 애노테이션 없이 실수가 일어 났따?

  • 부모 메서드를 이용하게 됨

  • 이 애노테이션 기능은? 부모의 기능일 이용하게다는 명시적 의미

  • 이름 그대로 오버라이딩한 메서드 위에 이 애노테이션을 붙여야 한다.
    컴파일러는 이 애노테이션을 보고 메서드가 정확히 오버라이드 되었는지 확인한다.
  • 오버라이딩 조건을 만족시키지 않으면 컴파일 에러를 발생시킨다.
    따라서 실수로 오버라이딩을 못하는 경우를 방지해준다.
  • 예를 들어서 이 경우에 만약 부모에 move() 메서드가 없다면 컴파일 오류가 발생한다.
    참고로 이 기능은 필수는 아니지만 코드의 명확성을 위해 붙여주는 것이 좋다.

  • 위에 메모리 구조설명처럼 ElectricCar 부터 시작해서 메서드를 찾음
  • 있으면 해당 메서드 move를 실행한다.
  • 본인에게있으면 본인꺼 사용

오버로딩(Overloading)과 오버라이딩(Overriding)

  • 메서드 오버로딩: 메서드 이름이 같고 매개변수(파라미터)가 다른 메서드를 여러개 정의하는 것을 메서드 오버딩(Overloading)이라 한다.
  1. 오버로딩은 번역하면 과적인데, 과하게 물건을 담았다는 뜻이다.
  2. 따라서 같은 이름 의 메서드를 여러개 정의했다고 이해하면 된다.

메서드 오버라이딩: 메서드 오버라이딩은 하위 클래스에서 상위 클래스의 메서드를 재정의하는 과정을 의미한다.
1. 따라서 상속 관계에서 사용한다.
2. 부모의 기능을 자식이 다시 정의하는 것이다. 오버라이딩을 단순히 해석하면 무
언가를 넘어서 타는 것을 말한다.
3. 자식의 새로운 기능이 부모의 기존 기능을 넘어 타서 기존 기능을 새로운 기능으
로 덮어버린다고 이해하면 된다.
4. 오버라이딩을 우리말로 번역하면 무언가를 다시 정의한다고 해서 재정의라 한다.
5. 상속 관계에서는 기존 기능을 다시 정의한다고 이해하면 된다.
6. 실무에서는 메서드 오버라이딩, 메서드 재정의 둘다 사용한다.

메서드 오버라이딩 조건

  • 참고만 하는 정도
  • 인텔리제이에서 걸러준다.

상속과 접근 제어


  • 그리고 복습 접근제어자

  • protected 까지 상속이기 때문에 불러올수 있따

접근 제어와 메모리 구조

  • 본인타입에 없으면 부모타입에 기능을 찾는데 접근 제어자 영향을 줌
  • 왜? 객체 내부에서는 자식과 부모가 구분되어 있기 때문
  • 자식타입에서 부모타입 기능을 호출할때 부모 입장에선 외부호출이기 때문
  • 공간적으로 나눠져 있따 생각 하자

super - 부모 참조

  • 부모와 자식 필드명이 같거나/ 메서드 오버라이딩 되어있으면
  • 자식에서 부모의 필드나 메서드 호출 가능
  • super 예약어를 사용해 부모 참조가능

  • 그림 으로 파악하면 더 쉽다

super- 생성자

  • 상속관계 인스턴스 생성시 자식 부모 클래스 각각 만들어짐
  • 따라서 각각 생성자도 모두호출해야됨

상속 관계를 사용하면서 자식클래스의 생성자에서 부모클래스의 생성자 바로 호출해야됨(규칙)

  • super를 사용하자

  • 몰랐던 부분인데 메모리 구조랑 보니 이해가 된다.
  • 기본생성자말고 생성자를 따로 정의하면 저렇게 super를 써서 정의해줘야된다
  • 따로 부모의 생성자를 정의하지않으면 super는 생략이 가능하다.
  • 생성자 첫줄에 this를 사용할수있지만 생성자안에서 super는 언젠가는 호출해야된다.
  • 반드시.
  • 여기서 this는 나말고 다른생성자 호출해줘 라고 기억하자

  • 실행 됨

  • 생성자의 호출 순위는 최상위 부모로 부터 실행되어서 하나씩 내려옴
  • 초기화는 최상위 부모부터
  • 왜 ? 자식의 생성자의 첫줄에서 부모의 생성자를 호출하기 때문

다형성

  • 객체지향 캡슐화 , 상속 , 다형성

  • 다형성 이해는 어렵지만 이해가 필수

  • 다형성은 말그대로 다양한 형태 / 여러 형태를 뜻함

  • 프래그래밍에서 다형성은 한 객체가 여러 타입의 객체로 취급될 수 있는 능력을 뜻함

  • 보통 하나의 객체는 하나의 타입으로 고정 되어있지만

  • 다형성을 사용하면 하나의 객체가 다른 타입으로 사용가능!

핵심이론

  • 다형성 참조
  • 메서드 오버라이딩

다형성 참조

  • 부모타입을 자식타입으로 가능.
  • 그런대 자식꺼를 못쓰네...
  • 자식은 또 부모를 담지못함

  • 여기는 위에 내용 알고있따

  • 자식은 부모를 담을수없다.
  • 참조값은 Parent poly에 담음

지금까지 학습한 내용은 같은 타입에 참조를 대입 보통은 한가지 형태만 참조가능

  • Parent parent = new Parent() 이런식

  • 근대 Parent타입의 변수는 자신 뿐만아니라 자식 타입 참조가능.
  • poly 의 타입은 parent라 타입에 따라 호출을 선택하기때문에 Parent() 부터 시작함
  • 이런것은 다양한 형태를 참조할수 있다고해서 다형적 참조

다형적 참조의 한계

  • Parent parent = new Child()
  • 이 상태에서 자식 메서드(특별한 기능) 호출할경우?
  • poly.childMehthod 를 실행하면 먼저 참조값을 통해 인스턴스 찾음
  • 그 다음으로 인스턴스안에 실행할 타입을 찾아야됨
  • poly는 Parent 타입이라 Parent 클래스부터 시작해 찾음
  • 그런대..! 상속관계는 부모 방향으로 올라가 찾아갈수 있지만
  • 자식방향으로 찾아 못내려감 , Parent는 부모타입이고 사상위에 부모가없다
  • 따라서 childMethod를 찾을수 없어서 컴파일 오류
  • 만약 실행하고싶으면? 캐스팅

다형적 참조의 핵심은 부모는 자식을 품을 수 있따는것

  • 근대 다형적 참조 왜 필요하지? 다음에 알아보자..? 아직은 이르다

다형성과 캐스팅

  • 전에 강의에선 부모타입으로 자식을 참조받으면
  • 자식메서드에 접근을 할 수 없지만
  • 캐스팅을 통해 접근을 가능하다 (다운 캐스팅)
  • 타입을 자식으로 바꾸는거다.

  • poly는 parent type
  • 전에 강의에서 내려갈수 없다고 한다.

Child child = (Child) poly
(타입)처럼 괄호와 그 사이에 타입지정시 참조 대상을 특정 타입으로 변환 가능

  • 실행 순서
  • 업캐스팅 : 부모 타입으로 변경 / 다운 캐스팅 : 자식 타입으로 변경

캐스팅 용어

  • 캐스팅은 영어단어 CAST에서 유래함 CAST는 금속이나 다른 물질을
  • 녹여서 특정한 형태나 모양을 만드는 과정 의미.

캐스팅 종류

일시적 다운 캐스팅

  • 번거로운...

  • 자바는 항상 뭘하면 변수에서 값을 꺼낸다.
  • 캐스팅한다고 타입이 변하는 건 아니고
  • 참조값을 잠시 꺼내 참조값이 Child 타입이 된다.
  • poly는 그대로 Parent 그대로 유지됨.
  • 일시적 다운 캐스팅은 별도의 변수없이 인스턴스의 자식타입 기능 사용가능

  • 업캐스팅 예제
  • 업캐스팅은 자주사용하기 때문에 생략 권장

다운캐스팅 주의

  • 다운 캐스팅 잘못하면 런타임 오류 발생

  • 왜??

  • 그림을 보면알수 있따
  • child 인스턴스는 생성이 안됐어!
  • 보통 객체 생성시 본인 및 부모 가생성 되거나 부모만 생성됨

  • Child 자체가 존재하지 않음.
  • 사용할수 없는 타입으로 다운캐스팅시 예외 발생

업캐스팅 안전 / 다운 캐스팅이 위험한 이유

  • 업캐스팅 경우 문제발생 x 객체를 생성하면 해당 타입의 상위 부모타입이 함께 생성되기 때문

  • 반면 다운캐스팅은 인스턴스에 존재하지않는 하위 타입으로 캐스팅 문제 발생

  • 부모타입은 모두생성되지만 자식 타입은 생성되지 않아서

instanceof

  • 다형성에서 참조형 변수는 이름 그대로 다양한 자식 참조가능

  • 하지만 어떤 자식을 참조 하는 알수있는 방법을 아는 방법을 알아보자

  • 인스턴스가 child면 밑에 로직 실행해줘!

  • 어떤 인스턴스를 참조하느냐 구분해준다.

  • 오른쪽 대상의 자식 타입을 왼쪽에서 참조하는 경우 true

  • 대입이 가능하면 true 못하면 false

  • x 자로 대입이 가능하면 true!

  • x 자 X자가 중요하다

  • 실제 인스턴스가 뭔지 확인하고

  • 그 인스턴스에 따라서 확인해보고 다운캐스팅을 내려서하면 안전하니까

자바 16 - Pattern Matching for instanceof

  • 캐스팅을 instanceof 에서 해준다.
  • 코드가 좀더 간결해져서 좋다

다형성과 메서드 오버라이딩

  • 오버라이딩 된 메서드는 항상 우선권을 가진다는것 ! 중요 !!

  • 이름도 기존 기능을 덮어 새로운 기능을 재정의한 다는 뜻의 오버라이딩이다.



그림 설명


  • poly는 부모타입이기 때문에 부모 메서드를 쓸줄 알았으나
  • 오버라이딩 메서드가 우선권을 가지기때문에 자식 함수가 써짐

다형적 참조: 하나의 변수 타입으로 다양한 자식 인스턴스를 참조할 수 있는 기능
메서드 오버라이딩: 기존 기능을 하위 타입에서 새로운 기능으로 재정의

다형성 활용



  • 만약에 소가 없으면?
  • 소가 없으면 소에대한 걸 추가
  • 중복이 계속나네 ?

  • 이렇게 함수를 추가해도 클래스 타입이 다다르기 때문에 중복 제거가 안돼

다형성 활용 2






![]

  • 부모는 자식을 담을수 있으니 다 가능하다.

  • 각 자식의 오버라이딩된 메서드를 호출 한다.
  • 위에서 배운대로 오버라이딩 메서드가 우선권을 가지니까

  • 하나의 Animal 이지만 다형성 참조 때문에 다양한 모습을 가지게 된다.

다형성 활용 3

  • 배열과 포문을 이용해 최적화

  • 계속해서 개선

  • 새로운 동물이 추가되도 soundAnimal 메서드는 코드 변경없이 유지 가능..

  • Aninamal 이라는 추상저긴 부모를 참조하기 때문 .

  • 변하는 부분이 최소화. 하는 것이 잘 작성된 코드.

  • 2가지 문제

Animal 클래스를 상속

  • Animal 클래스는 동물이라는 클래스이다. 이 클래스를 다음과 같이 직접 생성해서 사용할 일이 있을까?

Animal animal = new Animal()

  • 개 , 고양이, 소가 실제 존재하는것 당연함

  • 동물이라는 추상적인 개념이 실제로 존재하는건 이상함.

  • 이 클래스는 다형성을 위해 필요한거지 직접 인스턴스를 생성해서 사용할 일 없음

  • 하지만 Animal도 클래스기 때문에 인스턴스 생성하고 사용하는데 제약 없음

  • 누군가 실수로 Anamal 사용해서 인스턴스 생성할수 있지만

  • 제대로된 기능을 수행하지 않을듯.

Animal 클래스를 상속 받는 곳에서 sound() 메서드 오버라이딩을 하지 않을 가능성

  • 만약 개발자가 깜빡하고 구현하지않으면?
  • 컴파일 오류는 없지만...
  • 이렇게하면 부모의 함수가 호출됨..? 문제가있지
  • 좋은 프로그램은 제약있는 프로그램 제약이 없으니 이러면 안되지..

추상클래스

  • 동물(Animal) 과 같이 부모 클래스를 제공하지만

  • 실제 생성되면 안되는 클래스를 추상 클래스라 함

  • 말그대로 추상적인 개념을 제공하는 클래스 (인스턴스 존재 X)

  • 상속을 목적으로 사용되고 부모클래스 역할 담당

abstact class AbstractAnimal

  • 추상 클래스는 클래스를 선언할때 abstract 키워드 붙여줌.

추상 메서드

  • 부모 클래스를 상속받는 자식 클래스가 반드시 오버라이딩 해야 하는 메서드를 부모 클래스에 정의 가능. 이것을 추상 메서드라 함

  • 추상 클래스 는 말그대로 추상적인 개념 제공 메서드, 따라서 실체가 존재하지 않아 메서드 바디가 없다

public abstract void sound();



  • 테스트 코드
  • 클래스는 move() 라는 메서드를 가지고 있는데, 이 메서드는 추상 메서드가 아니다. 따라서 자식 클래스가 오버라
    이딩 하지 않아도 된다.


  • 컴파일오류 발생
  • 추상 메서드 앞에 abstract 키워 드 붙여주면됨
  • 추상메서드가 하나라도 선언되어 있으면 추상클래스로 선언해야됨.
  • 왜? 컴파일 오류 발생


추상 메서드는 상속받은 자식 클래스 반드시 오버라이딩해야 함.
그렇지 않으면 컴파일 오류가 발생한다.

  • 추상 메서드는 자식 클래스가 반드시 오버라이딩 해야 하기 때문에 메서드 바디 부분이 없다. 바디 부분을
    만들면 컴파일 오류가 발생한다.

  • 오버라이딩 하지 않으면 자식도 추상 클래스가 되어야 한다.

  • 추상 메서드는 기존 메서드와 완전히 같다. 다만 메서드 바디가 없고, 자식 클래스가 해당 메서드를 반드시 오버라이딩 해야 한다는 제약이 추가된 것이다.

  • 추상 클래스 덕분에 실수로 Animal 인스턴스를 생성할 문제를 근본적으로 방지해준다
  • 추상 메서드 덕분에 새로운 동물의 자식 클래스를 만들때 실수로 sound() 를 오버라이딩 하지 않을 문제를 근본
    적으로 방지해준다

추상클래스 2

순수 추상 클래스: 모든 메서드가 추상 메서드인 추상 클래스

  • 순수 추상 클래스는 실행 로직을 전혀 가지고 있지 않다. 단지 다형성을 위한 부모 타입으로써 껍데기 역할만 제
    공할 뿐이다.

순수 추상 클래스는 다음과 같은 특징을 가진다.
인스턴스를 생성할 수 없다.
상속시 자식은 모든 메서드를 오버라이딩 해야 한다.
주로 다형성을 위해 사용된다

상속하는 클래스는 모든 메서드 구현해야됨

  • 상속시 자식은 모든 메서드를 오버라이딩ㅎ해야 함

  • 특징은 상속 받은 클래스 입장에서 보면 부모의 모든 메서드를 구현해야함

  • 이런 특징은 순수 추상클래스는 마치 어떤 규격!을 지켜서 구현해야 하는 것 처럼 느낌

  • 인터페이스와 비슷한대?

  • 순수 추상클래스의 개념은 자바에서 더 편리하게 사용할수 있또록 인터페이스 라는 개념을 제공

  • 자바에선 순수 추상클래스라는 이름이없다 인터페이스가 있기 때문

인터페이스

  • 순수 추상클래스를 편리하게 사용가능한 인터페이스 기능 제공


  • 비슷한 두개념

  • 그냥 똑같다
  • 인터페이스는 구현이란 말을씀
  • 내가 부모의 코드를 다 만든다해서 구현이라 한다.
  • 위에 그림 점선은 관계를 표현

클래스 = 추상클래스 , 인터페이스 모두 똑같다

  • 메모리 구조상 모두 똑같다 .class로 다루어짐
  • 인터페이스를 작성할때도 .java에 인터페이스 정의함
  • 인터페이스는 순수 추상 클래스와 비슷하다고 생각하면 된다.
  • 굳이 순수추상클래스 만들필요없이 인터페이스를 사용하라고 만듬

상속 vs 구현

  • 부모 클래스 기능을 자식 클래스가 상속 받을땐 상속이라 표현

  • 부모 인터페이스의 기능을 자식이 상속받을때는 구현이라 함

  • 왜?

  • 상속은 이름 그대로 부모의 기능을 물려받는게 목적(오버라이드안된 메서드? 공통메서드?)

  • 하지만 인터페이스는 모든 메서드가 추상 메서드.

  • 따라서 구현한다고 표현.

  • 인터페이스는 메서드 이름만 있는 설계도 / 이 설계도가 어떻게 동작하는지 하위클래스에서 모두구현해야함. 그래서 구현이라함

  • 상속 구현은 사람마다 표현하는 단어만 다를 뿐이지 자바 입자ㅏㅇ에선 똑같다 일반 상속 구조와 동일하게 작동함

인터페이스 사용해야하는경우

  • 모든 메서드가 추상 메서드인 경우 순수 추상 클래스를 만들어도 되고, 인터페이스를 만들어도 된다. 그런대 왜 인터페
    이스를 사용해야 할까? 단순히 편리하다는 이유를 넘어서 다음과 같은 이유가 있다

제약

  • 인터페이스를 만드는 이유?

    • 인터페이스의 메서드를 반드시 구현해라하는 규약(제약)을 줌
    • 그런데 순수 추상클래스의 경우 미래에 누군가 그곳에 실행 가능한
    • 메서드를 끼워 넣을수 있음
    • 이렇게 되면 추가된 기능을 자식클래스에서 구현하지 않을수도 있고 또 더는 순수한 추상 클래스가 아니게 됨 인터페이스는 모든 메서드가 추상 메서드이다 이런문제 원천 차단
  • 다중 구현

    • 자바에서 클래스 상속은 부모를 하나만 지정할 수 있다. 반면에 인터페이스는 부모를 여러명 두는 다중
      구현(다중 상속)이 가능하다
  • 인터페이스는 완전한 약속 완전히 구현해야되

  • 추상클래스는 일부는 구현이 되어있어도 괜찮고 일부코드는 구현해야됨

  • 불안전함.

  • 추상클래스는 내가 기능을 넣어도 되니까 기능을 넣을까말까

  • 인터페이스는 이런관점에서 다막아버린다.

  • 인터페이스에서도 자바8 부터 메서드 작성가능
  • 하나 특별한 하위 호환성을 맞춰야 되거나

인터페이스 다중 구현

  • 인터페이스 다중 구현 허용한 이유는 뭘까?
  • 모두 추상 메서드로 이루어져 있기 때문

  • 어짜피구현은 자식이 그래서 부모에서 고르는게 아니라
  • 자식에서 실행되기 때문에 (추상메서드 -> 구현)


  • 소스코드 예제

  • 그림 예제

클래스 인터페이스 활용

  • 그림 설명



  • 두개를 활용한 코드 예제
  • 실무에서 에서 언제 쓸수 잇을까

다형성과 설꼐

좋은 객체 지향 프로그래밍

객체지향 프로그래밍

  • 여러개의 독립된단위 객체들의 모임으로 파악하고자 하는것
  • 각각 객체는 메시지를 주고받고 데이터 처리함 (협력)
  • 객체지향 프로그래밍은 프로그램을 유연하고 변경이 용이하게 만들기 때문에 대규모 소프트 웨어 개발에 많이 사용함

유연하고 변경 용이?

  • 레고 블럭 조립하듯이..
  • 그럼 설계 방법이?
  • 객체지향의 핵심인!

다형성

  • 실세계 객체지향을 1:1로 매칭은 X
  • 그래도 실세계의 비유로 이해하기 좋음
  • 역할과 구현으로 세상을 구분

  • K3 타다 테슬라 모델3로 ?

  • 바로 운전 가능

  • 운전자라는 역할 입장에서 보면 자동차를 바꿔도 영향을 안줌

  • 자동차라는 역할과 구현으로 분리된 이유?

  • 내가 운전자라는 역할 입장에서 자동차가 바뀌더라도

  • 운전자의 역할은 바뀌지않음

  • 무슨말? 자동차의 역할을 부여한것은 운전자인 나를 위해서

  • 자동차의 내부구조 다 알필요 있어?

  • 차를 바꾼다해서 세세하게 알필요없다

  • 엑셀 밟으면가고 브레이크 밟으면 선다.

    이런식으로 역할과 구현을 구분해놓으면 무한대로 자동차를 늘릴 수 있음

  • 클라이언트인 운전자 역할에 영향을 안미치고.

  • 왜 ? 역할과 구현으로 세상을 구분

  • 비슷한 예제

  • 운전자 역할 로미오 줄리엣 역할 입장에선 참좋다.

  • 대상의 역할 인터페이스만 알면 된다.

  • 이런식으로 설계 할 수 있다
  • 객체 설계할때 인터페이스 먼저 설계..
  • 역할 인터페이스가 항상 먼저다

  • 다형성의 본질은
  • 클라이언트랑 서버라는 단어부터.
  • 요청하는걸 모두 클라이언트
  • 응답하는걸 모두 서버 (뭔가를해서 응답을 하는것)

  • 그림 이해가 참 쉽게 되있다.



  • 클라이언트는 전혀 변경되지 않지만 서버는 변경가능

  • 하지만 역할인 인터페이스가 변하면 다 영향을 미친다..

  • 차가 비행기로 바뀌면..

OCP

  • 앞선 코드 예제에서 (생략했지만)

  • 우리는 new 카를 추가해도

  • driver에 코드를 손댈 필요가 없다

확장에 여려있다는 의미

  • car는 인터페이스 사용해서 새로운 차량 자유롭게추가.
  • Car 인터페이스를 구현해서 기능을 추가할수있는 의미!
  • Car 인터페이스를 사용하는 클라이언트 코드인 Driver도 car 인터페이스를 통해 새롭게 추가된 차량 자유롭게 호출 -> 확장에 열려있따

코드 수정으 ㄴ닫혀있다는 의미

  • 새로운 차 추가시 기능 추가기 때문에 기존 코드의 수정은 불가피.
  • 당연히 어딘가의 코드는 수정?

변하지 않는 부분

  • 자동차 추가시 가장 영향을 받는 중요한 클라이언트는 Car기능을 사용하는 Driver
  • 핵심은 Car 인터페이슬 사용하는 클라이언트인 Driver의 코드를 수정하지 않아도 됨

변하는 부분

  • main() 과 같이 새로운 차를 생성하고 Driver에게 필요한 차를 전달해주는 역할은 당연히 코드 수정 발생 main()은 전체프로그램을 설정하고 조률하는 역할
  • 이런 부분은 OCP 지켜도 변경이 필요함

  • 전략 패턴 위에 코드 예제가 전략패턴 코드
profile
어제의 나보다 한걸음 더

0개의 댓글