교육/[온라인] KOSTA EDU

[KOSTA] Java 기반의 객체지향 프로그래밍 1주차

코드몬스터 2024. 6. 22. 09:12
728x90
Write Once, Run Anywhere(작성은 한 번만, 동작은 어디든)

 

수업

수업제목: JAVA 기반의 객체지향 프로그래밍

수업기간: 06/22(토), 06/29(토)

수업 시간: 09:00 ~ 18:00

 

객체와 클래스

  • 객체 지향 프로그래밍(Object-Oriented Programming)
    → 반복적으로 하는 작업을 줄이기 위해서 나온 방법이다.
    OOP is A P.I.E
    • 추상화(Abstraction): 현실의 객체를 추상화 해서 클래스를 구성
    • 다형성(Polymorphism): 하나의 객체를 여러 가지 타입으로 참조
    • 상속(Inheritance): 부모의 클래스의  자산을 물려받은 자식을 정의하여 코드 재사용이 가능
    • 은닉화(Encapsulation): 데이터를 외부에 직접 노출하지 않고 메서드를 이용해 보호
  • 현실의 객체의 속성과 기능을 추상화(abstract)하여 클래스를 정의한다.
  • 클래스는 구체화 되어 프로그램의 객체(instance, object)가 된다.
    • Object들의 집합이 Instance 이다.

현실세계
프로그래밍

 

  • 추상화로 클래스 만들고 구체화로 객체 사용하기
public class Person {

    void eat() {
        System.out.println("냠냠");
        isHungry = false;
    }

    void work() {
        System.out.println("열심히");
        isHungry = true;
    }

}
public class PersonTest {

    public static void main(String[] args) {
        Person person1 = new Person();
        person1.name = "홍길동";
        person1.isHungry = true;
        System.out.printf("name: %s, isHungry: %b%n", person1.name, person1.isHungry);
        person1.eat();
        System.out.printf("name: %s, isHungry: %b%n", person1.name, person1.isHungry);

        Person person2 = new Person();
        person2.name = "임꺽정";
        person2.isHungry = true;
        System.out.printf("name: %s, isHungry: %b%n", person2.name, person2.isHungry);
        System.out.printf("name: %s, isHungry: %b%n", person1.name, person1.isHungry);
    }
}

 

  • 객체의 생성과 메모리 할당
    • metaspace = classArea
    • stack은 call

 

 

 

1. call stack에서 main 메서드의 지역 변수를 값이 없이 생성

2. 클래스 정보 로딩

   - static 변수 (공통 변수)

3. Heap

    - 인스턴스 변수 - 객체 생성 정보

 

변수

멤버 변수

  • 클래스 영역
    • 클래스 멤버 변수 (static keyword)
      • 변수의 생성: 클래스 로더에 의해 클래스가 로딩 될 때 클래스 별로 생성
        개별 객체의 생성과 무관하게 모든 객체가 공유 됨
      • 변수의 초기화: 타입별로 default 초리과
      • 변수의 접근: 객체 생성과 무관하게 클래스 이름으로 접근
        • 객체를 생성하고 객체 이름으로 접근도 가능하나 static에 부한한 표현은 아님 
        • Person p = new Person();
          p.scientificName = "객체를 통한 변경"
          Person.scientificName = "클래스를 통한 변경";
    • 인스턴스 멤버 변수
      • 변수의 생성: 객체가 만들어질 때 heap에 객체별로 생성됨
      • 변수의 초기화: 타입 별로 default 초기화
      • 변수의 접근
        - 객체 생성 후(메모리에 올린 후) 객체 이름으로 접근
        - 객체를 만들 때마다 객체 별로 생성(객체마다 고유한 상태 유지)
      • Garbage Collector에 의해 객체가 없어질 때

 

지역 변수

  • 변수의 생성: 선언된 라인이 실행될 때
  • 변수의 초기화: 사용하기 전 명시적 초기화 필요
  • 변수의 접근: 외부에서는 접근이 불가능
  • 소멸 시점: 선언된 영역({})을 벗어날 
public class VariableTypes{
	int instanceVariable;      // 인스턴스 멤버 변수
    static int classVariable;  // 클래스 멤버 변수
}

 

메서드

메서드 정의와 필요성

  • 메서드란?
    • 현실의 객체가 하는 동작을 프로그래밍화
    • 어떤 작업을 수행하는 명령문의 집합
  • 메서드를 작성하는 이유
    • 반복적으로 사용되는 코드의 중복 방지
    • 코드의 양을 줄이고 유지 보수가 용이

 

선언부

  • 리턴타입
    • 메서드를 호출한 곳으로 반환되는 값의 타입으로 아무것도 리턴하지 않을 경우 void
    • 결과를 받을 때 묵시적 형 변환 적용
  • 메서드 이름은 수행하는 작업을 쉽게 파악하도록 의미 있는 이름을 사용
  • 파리미터 목록
    • 메서드 호출 시점에 넘겨줘야 하는 파라미터들로 넘겨줄 정보가 없는 경우 생략 가능
    • 파라미터 전달 시, 묵싲거 형변환 적용
public log add(long a, long b) {
	return a + b;
}

add(10L, 20L);      // (O)
add(100, 200);      // (O)
add(1.1, 1.2);      // (X)
add(100, 200, 300); // (X)
add(100);           // (X)

 

Variable arguments

  • 메서드 선언 시, 동일 타입의 인자가 몇 개 들어올지 예상할 수 없는 경우
public static void main(String[] args) {
	VariableTest vt = new VariableTest();
    
    vt.addAll(1, 2, 3);
    vt.addAll(1, 2, 3, 5);
    vt.addAll(1, 2);
}


public void addAll(int... params) {
	int sum = 0;
    for (int i: params) {
    	sum += i;
    }
    
    System.out.println(sum);
}

 

  • class 멤버와 instance 멤버 간의 참조와 호출
    • 가장 중요한 것은 호출하려는 멤버가 메모리에 이쓴ㄴ가?
      • 메모리에 있으면 호출 가능
      • 메모리에 없으면 호출 불가
    • static member
      • 언제나 메모리에 있음
      • 클래스 로딩 시 자동 등록
    • instance member
      • 객체 생성 전에는 메모리에 없음
      • 객체 생성 시, 모든 일반 멤버들은 메모리에 생성
      • 객체 즉, 레퍼런스를 통해 접근

 

오버로딩

메서드 오버로딩

  • 동일한 기능을 여러 형태로 정의해야 한다면?
  • 동일한 기능을 수행하는 메서드의 추가 작성

prinlt 메서드 고찰

  • 메서드 오버로딩의 장점
    • 기억해야 할 메서드가 감소하고 중복 코드에 대한 효율적 관리 가능

메서드 오버로딩 방법

  • 메서드 이름은 동일
  • 파라미터의 개수 또는 순서, 타입이 달라야할 것
    • 파라미터가 같으면 중복 선언 오류
  • 리턴 타입 의미 없음

오버로딩

 

생성자

생성자

  • 객체를 생성할 떄 호출하는 메서드 비슷한거
    • new 키워드와 함께 호출하는 것
      • Person person1 = new Person();
    • 일반 멤버 변수의 초기화나 객체 생성 시 실행돼야 하는 작업 정리
  • 작성 규칙
    • 메서드와 비슷하나 리턴 타입이 없고 이름은 클래스 이름과 동일

생성자의 종류

  • 기본 생성자(default constructor)
    • 파라미터가 없고 구현부가 비어있는 형태
    • 생성자 코드가 없으면 컴파일러가 기본 생성자 제공
public class DefaultPerson {

    String name;
    int age;
    boolean isHungry;
    
    // public DefaultPerson() {} -- 생략된 기본 생성자
    
    public static void main(String[] args) {
    	DefaultPerson person = new DefaultPerson();
		person.name = "홍길동";
        person.age = 10;
        person.isHungry = false;
    }
}

 

  • 파라미터가 있는 생성자
    • 생서자의 목적이 일반 멤버 변수의 초기화
      → 생성자 호출 시, 값을 넘겨줫 초기화
public class DefaultPerson {

    String name;
    int age;
    boolean isHungry;
    
    public DefaultPerson(String n, int a, boolean i) {
    	name = n;
        age = a;
        isHungry = i;
    }
    
    public static void main(String[] args) {
    	DefaultPerson person = new DefaultPerson("홍길동" , 10, true);
    }
}

 

this, this()

this

  • 참조 변수로써 객체 자신을 가리킨다.
    • 참조변수를 통해 객체의 멤버에 접근했던 것처럼 this를 이용해 자신의 멤버에 접근 가능
  • 용도
    • 로컬 변수와 멤버 변수의 이름이 동일할 경우 멤버 변수임을 명시적으로 나타냄
    • 명시적으로 멤버임을 나타낼 경우 사용
public class DefaultPerson {

    String name;
    int age;
    boolean isHungry;
    
    // 생성자를 하나도 만들지 않는 경우, 컴파일러가 추가해준다.
    public DefaultPerson() { // 기본 생성자
    }
    
    // 생성자 오버로드
    // 참조의 기본원칙: 참조 위치에서 가까운 곳에 선언된 것을 우선참조
    public DefaultPerson(String name, int age, boolean isHungry) {
    	this.name = name;
        this.age = age;
        this.isHungry = isHungry;
    }
    
    void walk() {
    	this.isHungry = true;
        System.out.println("뚜벅 뚜벅");
    }
}

 

 

this()

  • 메서드와 마찬가지로 생성자도 오버로딩 가능
    • 한 생성자에서 다른 생성자를 호출할 때 사용
  • 첫 줄에서만 호출이 가능

 

 

초기화 블록

 

상속(inheritance)

상속

  • 기존 클래스의 자산(멤버)을 자식(하위) 클래스에서 재사용하기 위한 것
    • 상위 클래스의 생성자와 초기화 블록은 상속하지 않는다.
  • 상위 클래스의 멤버를 물려 받기 때문에 코드의 절감
    • 상위 클래스의 코드를 변경하면 모든 하위 클래스에게도 적용
  • 상속의 적용
    • extends 키워드 사용

 

Object 클래스

  • 모든 클래스의 조상 클래스
    • 클래스들은 extends Object가 생략됨
    • 모든 클래스에는 Object 클래스에 정의된 메서드가 있다.

Object 클래스

 

단일 상속(Single Inheritance)

  • 자바는 단일 상속만 지원
    • 대신 interface와 포함 관계로 단점 극복
  • 다중 상속의 경우 여러 클래스의 기능을 물려받을 수 있으나 관계가 매우 복잡(ambiguous)해짐
    • 동일한 이름의 메서드가 두 상위 클래스에게 모두 있다면 하위 클래스는 어떤 메서드를 사용할 것인가?

 

포함 관계

  • 상속 이외에 클래스를 재활용 하는 방법
    • 2개 이상의 클래스에서 특성을 가져올 때 하나는 상속, 나머지는 멤버 변수로 처리
  • 상속이냐 포함이냐 그것이 문제로다.
  • 어떤 클래스를 상속받고 어떤 클래스를 포함해야할까?
    • 문법적인 문제는 아니며 프로젝트의 관점 문제
    • 상속: is a 관계가 성립하는가?  → Spiderman is a Person.
    • 포함: has a 관계가 성립하는가? → Spiderman has a Spider.

 

포함관계 다이어그램

 

오버라이딩

메서드 오버라이딩(overriding)

  • 조상 클래스에 정의된 메서드를 자식 클래스에서 적합하게 수정하는 것

오버라이딩 조건

  • 메서드 이름이 같아야한다.
  • 매개 변수의 개수, 타입, 순서가 같아야한다.
  • 리턴 타입이 같아야한다.
  • 접근 제한자는 부모 보다 범위가 넓거나 같아야 한다.
  • 조상보다 더 큰 예외를 던질 수 없다.

 

super

super 키워드

  • this 통해 멤버에 접근했듯이 super를 통해 조상 클래스 멤버 접근
  • 조상의 메서드 호출로 조상의 코드 재사용

변수의  scope

class Parent {
	String x = "parent";
}

class Child extends Parent {
	String x = "child";
    
    void method() {
    	String x = "method";
    	System.out.println("x : " + x );			// method
        System.out.println("this.x :" + this.x);	// child
        System.out.println("super.x :" + super.x);  // parent
    }
}


public class ScopeTest {

	public static void main(Stringp[] args) {
    	Child child = new Child();
        child.method();
	}    
}

 

 

super()

  • this()가 해당 클래스의 다른 생성자를 호출하듯  super()는 조상 클래스의 생성자 호출
    • 조상클래스에 선언된 멤버들은 조상 클래스의 생성자에서 초기화가 이뤄지므로 이를 재활용
    • 자식 클래스에 선언된 멤버들만 자식 클래스 생성자에서 초기화
  • super()는 자식 클래스 생성자의 맨 첫 줄에서만 호출 가능
    • 즉, 생성자의 첫 줄엠나 this() 또는 super()가 올 수 있다.
  • 명시적으로 this() 또는 super()를 호출하지 않는 경우, 컴파일러가 super() 삽입
    • 결론적으로 맨 상위의 Object까지 객체가 다 만들어지는 구조

 

 

 

 

class ParCup {

    int money;
    public ParCup() {
    
    }
    
    public ParCup(int money) {
    	super();
        this.money = money;
    }
    
}


class ChipCup extends ParCup {
    int age;
    String name;
    
    public ChipCup() {
    	this(3, "홍길동");
        
    }
    
    public ChipCup(int age) {
    	this(age, "홍길동");
    }
    
    public ChiCup(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }
    
    public ChipCup(int age, String name, int money) {
        super(money);
        this.age = age;
        this.name = name;
    }

}

 

 

pacakge

 

 

자바는 동적 코딩

import java.util.*를 해도 전부 메모리에 올라가지 않는다.

사용 되지 않는 클래스는 제거 된다.

 

 

제한자(Modifier)

제한자(Modifier)

  • 클래스, 변수, 메서드, 선언부에 함게 사용되어 부가적인 의미 부여
  • 종류
    • 접근 제한자: public, portected, default = package, private
    • 그 외 제한자
      • static
      • final
      • abstract
      • synchronized
  • 하나의 대상에 여러 제한자를 조합 가능하나 접근 제한자는 하나만 사용가능
  • 순서는 무관
    • 일반적으로 접근 제한자를 맨 앞으로

final

  • 마지막, 더 이상 바뀔 수 없다.
  • final class - 더 이상 확장할 수 없음: 상속금지 → 오버라이드 방지
  • final method - 더 이상 재정의할 수 없음: 오버라이딩 금지
  • final variable - 더 이상 값을 바꿀 수 없음(상수)