JAVA 문법종합반 3주차

SJ.CHO·2024년 9월 4일

객체지향

  • 현실세계의 제품이 하나하나의 모듈이 있듯이 프로그램 또한 기능,속성별 모듈화를 통해 부품을 조립해 만드는 방법.

객체

  • 세상에 존재하는 물체이며 식별가능한것.
  • 속성=필드, 행위=메서드 구성됌.

  • 실제로 존재하는것을 SW상의 객체로 만드는것을 '객체 모델링' 추상화 라고함

  • 객체들은 서로 메서드와 파라미터값을 통해 유기적으로 상호작용함.

특징

  • 캡슐화
    • 필드와 메서드를 하나로 묶어 객체화 후 내부구현내용을 감춤.
    • 외부객체는 내부의 내용을 모르기 때문에 공개한 내용으로만 접근가능.
    • 외적인 요인으로 인해 변화하지않음.
  • 상속
    • 부모객체가 가진 내용을 자식이 사용할 수 있도록 제공
    • 객체간의 구조파악이 쉬움, 일관성이 높음, 중복↓, 재사용성↑
  • 다형성
    • 하나의 메서드에 대해 호출자에 대하여 구현을 다르게 재정의하여 사용할 수 있다.
  • 추상화
    • 객체를 모델링하기 위해 객체의 공통부분을 모아 상위 개념으로 선언

Class

  • 객체를 만기위한 일종의 설계도.
  1. 클래스 선언.
  2. 객체가 가질 필드 정의.
  3. 객체를 생성하는 방식. (생성자)
  4. 객체가 가질 메서드를 정의.

생성자

  • Class 와 동일한 이름을 가짐.
  • 객체가 생성될 때 어떤 로직을수행하고 어떤값을 가지게 되는지 정의.
  • 객체마다 기초값(초기값)을 다르게 하고싶을때 사용.
  • 주로 생성자 오버로딩을 활용한다.

this

  • 자기자신의 속성을 가르킬때 주로 사용.
public Car(String model, String color, double price) {
    this.model = model;
    this.color = color;
    this.price = price;
}
  • 또한 리턴타입의 자신의 클래스 타입이라면 객체 자신의 주소 반환 또한 가능.

this()

  • 자신의 생성자를 호출하는 명령어.
  • 생성자 오버로딩의 상황에서 코드의 중복을 줄일 수 있음.
  • this() 키워드는 무조건 첫줄에 존재해야함.
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;
}

객체

객체 생성

  • new() 키워드를 활용하여 참조형 변수로 생성 가능.
Car car1 = new Car(); // Car클래스의 객체인 car1 인스턴스 생성
Car car2 = new Car(); // Car클래스의 객체인 car2 인스턴스 생성
public class Main {
    public static void main(String[] args) {
        Car[] carArray = new Car[3];
        Car car1 = new Car();
        car1.changeGear('P');
        carArray[0] = car1;
        
        Car car2 = new Car();
        car2.changeGear('N');
        carArray[1] = car2;
        
        Car car3 = new Car();
        car3.changeGear('D');
        carArray[2] = car3;

        for (Car car : carArray) {
            System.out.println("car.gear = " + car.gear);
        }
    }
}

// 출력
//car.gear = P
//car.gear = N
//car.gear = D

필드 : 객체의 데이터를 저장하는 역할

  • 고유데이터(불변 값), 상태 데이터(변하는 값),객체데이터
  • 객체를 생성할 때 초기값을 주지않으면 기본값이 들어감
  • 필드에 대해서 외부직접접근과 내부메소드를 이용한 접근이 있음./ 캡슐화 관점으론 후자가 좋다.(Getter/Setter)

메서드 : 객체의 행위, 협력을 위한 도구

  • 리턴타입, 매개변수, 반환값을 지님.
double gasPedal(double kmh, char type) {
    speed = kmh;
    return speed;
}
  • 매개변수는 호출시 type,순서를 맞춰서 호출해야함.
  • 가변길이를 매개변수로 전달이 가능하다.
void carSpeeds(double ... speeds) {
    for (double v : speeds) {
        System.out.println("v = " + v);
    }
}
  • 외부접근방법은 필드와 동일. 내부에선 같은 객체내부에서의 호출이 된다.

메소드 오버로딩

  • 동일한 이름의 메소드의 이름으로 매개변수의 차이로 동일한 행동을 할 수 있음.
  • 이름이 동일하며, 매개변수의 개수, 타입, 순서가 달라야함.
  • 기본형 매개변수 : 값을 복사해서 전달하기에 원본값이 변경되지않음.
  • 참조형 매개변수 : 매개값의 주소를 전달하기에 변경시 원본값이 변경됌.

멤버

  • 멤버 : 필드 + 메서드

    • 인스턴스 멤버 = 인스턴스 필드 + 인스턴스 메서드
    • 클래스 멤버 = 클래스 필드 + 클래스 메서드
  • 인스턴스 멤버

    • 객체를 생성해야 사용 가능.
    • 인스턴스 필드는 각각의 고유값으로 보유.
    • 메서드는 객체의 동일값이기에 메서드영역에서 따로 공유한다.
  • 클래스 멤버

    • 클래스로더에 의해 메서드 영영에 저장됨.
    • 고정된주소의 위치에 존재하기에 객체없이 사용가능.
    • 공용적으로 사용할 데이터필드를 선언.
    • static 키워드를 사용하여 선언.
  • 인스턴스 멤버는 클래스멤버 사용이가능하지만 반대는 불가. (객체가 없기 때문에)

  • 지역변수

    • 메서드 내부에서 사용하는 변수, 메서드마다 독립값을 사용.
    • 메서드가 생성되고 종료될때까지만 유지된다.
  • 상수

    • Final 키워드를 통해 선언, 프로그램이 실행중엔 수정됄 수 없음.
    • 초기값이 필수임.
    • static final을 추가하여 사용한다.
    • final class : 상속불가
    • final method : 오버라이딩 불가
    • final 변수 : 새로운 값 할당불가

접근제어자

  • 캡슐화를 위해 사용하며 내부의 데이터를 보호할 수 있도록 사용.
  • 생성자의 접근제어자는 클래스와 일치함.

Getter 와 Setter

  • private 접근제어자를 통해 필드를 보호할경우 사용하는 기법.
  • 객체를 통해 필드에 직접 접근하는것이 아닌 값의 검증, 가공등이 가능해짐.

Packge , import

  • 패키지
    • 파일시스템의 폴더 개념
    • 동일한 이름의 클래스를 사용할때 Java는 패키지의 경로를 통해 이를 구분.
  • import
    • 다른 패키지에 있는 클래스를 사용하기 위한 키워드
    • 다른패키지의 같은이름의 클래스를 사용하려면 경로를 전부 명시해야함.
package oop.main;

import oop.pk1.Car;

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

        oop.pk2.Car car2 = new oop.pk2.Car();
        car2.horn(); // pk2 빵빵
    }
}

상속

  • 부모클래스의 필드, 메서드를 자식클래스에게 물려주는것.
  • 코드의 중복을 제거하고, 재사용성증가, 생산성, 유비보수성 증가.
  • extends 키워드를 사용한다.
public class 자식클래스 extends 부모클래스 {

}

다중상속

  • Java는 기본적으로 다중상속을 허용하지않음.
  • 클래스간의 복잡도가 높아지고 같은 이름의 멤버를 받았을때 부모클래스가 여러개면 해당 멤버 식별이 불가능함.

오버라이딩

  • 상속받은 메서드의 내용을 자식클래스의 상황에 맞춰 재정의 하는 것.
  • 선언부가 부모클래스와 일치.
  • 접근제어자를 부모클래스의 메서드보다 좁은범위로 변경할 수 없음
  • 예외는 부모클래스의 메서드보다 많이 선언할 수 없음.

super, super()

  • super
    • 부모클래스의 멤버를 참조할수 있는 키워드
public void setCarInfo(String model, String color, double price) {
    super.model = model; // model은 부모 필드에 set
    super.color = color; // color는 부모 필드에 set
    this.price = price; // price는 자식 필드에 set
}
  • super()
    • 부모클래스의 생성자를 호출하는 키워드
    • 부모클래스의 생성자가 최우선으로 호출되기에 부모클래스의 멤버 초기화작업이 우선적으로 필요.
    • 상속시 암묵적으로 부모클래스의 생성자가 오버로딩되어져있음.

오버로딩 vs 오버라이딩

  • 오버로딩은 동일한 행동을 다른 매개변수를 통해 진행.
  • 오버라이딩은 같은 매개변수를 통해 다른 행동을 진행.

다형성

  • 여러가지 형태를 가질 수 있는 능력.
  • 구성하는 객체를 변환하였을 때 과정은 같지만 결과가 다름.

참조변수의 타입 변환

  • 부모타입변수 = 자식타입객체 는 자동으로 부모타입으로 변환.
  • 자식객체는 부모클래스의 요소를 전부 가지고있기에 동일취급이 가능.
  • 다만 해당변수로 자식객체의 새로작성된멤버는 접근불가.
    (정보가 없기 때문)

강제 타입변환

  • 자식타입변수 = (자식타입) 부모타입객체
// 자식타입객체가 자동 타입변환된 부모타입의 변수
Mammal mammal = new Whale();
mammal.feeding();

// 자식객체 고래의 수영 기능을 사용하고 싶다면
// 다시 자식타입으로 강제 타입변환을 하면된다.
Whale whale = (Whale) mammal;
whale.swimming();
  • 자식타입이 부모타입으로 변환 된 후, 다시 자식으로 돌아올때만 가능.
  • 자식클래스에서 선언된 기능이 필요할 경우가 생겼을때만 사용.

추상클래스

  • 미완성된 설계도 abstract 키워드로 선언
public abstract class 추상클래스명 {
}
  • 추상클래스는 추상메서드를 가지고있음(없어도 됌)
  • 자식 클래스에 상속되어 자속클래스에 의해 완성됌.
  • 상속과의 방향성이 반대로 자식클래스에 의해 만들어짐.(매뉴얼 개념)
  • 독립적인 필드, 메서드, 생성자를 가질순 있지만 생성자를 직접 호출생성은 불가능.
  • 하지만 자식객체에서 super()를 활용해 생성하기때문에 존재는 해야함.

추상메서드

public abstract class 추상클래스명 {
		abstract 리턴타입 메서드이름(매개변수, ...);
}
  • 구현부분이 없고 정의만 따로 함.
  • 상속받은 클래스는 추상메서드를 반드시 구현해야함 (오버라이딩)

인터페이스

  • 두 객체를 연결하는 다리 역할.
  • 상속관계가 없는 다른 클래스들이 서로 동일한 메서드가 필요할때 구현클래스들이 동일한 행동을 한다고 보장 한다
public interface 인터페이스명 { 
	public static final char A = 'A';
    static char B = 'B';
    final char C = 'C';
    char D = 'D';

    void turnOn(); // public abstract void turnOn();
}
  • 모든 변수는 상수 이며, 모든 메서드는 추상클래스이다.

  • implements 키워드를 통해 수현이 가능하다.

  • 추상메서드는 반드시 구현해야한다. 일부만 구현을 하고 싶을시 구현클래스를 추상클래스로 변경후 추상클래스를 구현하면됌.

  • 인터페이스간의 상속을 지원. extends 키워드를 사용. /
    다중상속이 가능하다.

public class Main implements C {

    @Override
    public void a() {
        System.out.println("A");
    }

    @Override
    public void b() {
		System.out.println("B");
    }
}

interface A {
    void a();
}
interface B {
    void b();
}
interface C extends A, B { }

디폴트 메서드

  • 추상메서드의 기본적인구현을 제공하는 메서드
  • default 키워드를 붙혀서 구현
  • 추상메서드가 아니기 때문에 구현체들이 필수적으로 구현할 필요가 없음.
public class Main implements A {

    @Override
    public void a() {
        System.out.println("A");
    }


    public static void main(String[] args) {
        Main main = new Main();
        main.a();

        // 디폴트 메서드 재정의 없이 바로 사용가능합니다.
        main.aa();
    }
}

interface A {
    void a();
    default void aa() {
        System.out.println("AA");
    }
}

static 메서드

  • 인터페이스 내에서도 static을 선언가능
  • 기존의 특성과 동일하게 객체없이 호출이 가능하다.
interface A {
    void a();
    default void aa() {
        System.out.println("AA");
    }
    static void aaa() {
        System.out.println("static method");
    }
}

형변환은 상속과 동일함.

추상클래스 VS 인터페이스

  • 추상클래스 : 기존의 클래스에서 공통된 부분을 추상화하여 자식클래스에게 구현을 강제. / 공유의목적
  • 인터페이스 : 인터페이스를 구현하는 객체들의 같은 동작을 보장하기위해 사용

숙제

  • 문제가 총 4 step 이었는데 진행과정을 따로 기록하지못하였다..

답안 :

  • Calculator
package Cal;

public class Calculator {
    //오퍼레이션을 받기 위한 private 필드 추가
    private AbstractOperation operation;
    // 생성자를 통해서도 오퍼레이션을 받을수 있다.
    Calculator(AbstractOperation operation) {
        this.operation = operation;
    }
    // 계산기의 오퍼레이션을 바꾸고 싶을시
    public void setOperation(AbstractOperation operation) {
        this.operation = operation;
    }
    //실질적 계산 호출부분
    public double Calculate(int firstNumber, int secondNumber) {
        double result = operation.operate(firstNumber, secondNumber);
        return result;
    }
}
  • AbstractOperation
package Cal;

public abstract class AbstractOperation {
    // 상속시 계산부분구현을 명시
    public abstract double operate(int a, int b);
}
  • AddOperation
package Cal;
// 추상클래스 상속
public class AddOperation extends AbstractOperation {
    //추상클래스 추상메소드 구현 (오버라이딩 하여 메서드 구현내부변경)
    @Override
    public double operate(int a, int b) {
        double result = a + b;
        return result;
    }
}
  • SubstractOperation
package Cal;

// 추상클래스 상속
public class SubstractOperation extends AbstractOperation {
    //추상클래스 추상메소드 구현 (오버라이딩 하여 메서드 구현내부변경)
    @Override
    public double operate(int a, int b) {
        double result = a - b;
        return result;
    }
}
  • MultiplyOperation
package Cal;
// 추상클래스 상속
public class MultiplyOperation extends AbstractOperation {
    //추상클래스 추상메소드 구현 (오버라이딩 하여 메서드 구현내부변경)
    @Override
    public double operate(int a, int b) {
        double result = a * b;
        return result;
    }
}
  • DivideOperation
package Cal;
// 추상클래스 상속
public class MultiplyOperation extends AbstractOperation {
    //추상클래스 추상메소드 구현 (오버라이딩 하여 메서드 구현내부변경)
    @Override
    public double operate(int a, int b) {
        double result = a / b;
        return result;
    }
}
  • Main
package Cal;

public class Main {
    public static void main(String[] args) {
        // 계산기 객체 생성 및 생성자를 통해 더하기 오퍼레이션 전달
        Calculator calc = new Calculator(new AddOperation());
        double add = calc.Calculate(10, 20);
        System.out.println("add : " + add);

        // 동일 객체를 활용해 빼기연산
        calc.setOperation(new SubstractOperation());
        double sub = calc.Calculate(10, 20);
        System.out.println("sub : " + sub);

        // 동일 객체를 활용해 곱셈연산
        calc.setOperation(new MultiplyOperation());
        double mult = calc.Calculate(10, 20);
        System.out.println("mult : " + mult);

        // 동일 객체를 활용해 나눗셈연산
        calc.setOperation(new DivideOperation());
        double div = calc.Calculate(20, 10);
        System.out.println("div : " + div);
    }
}

실행화면

profile
70살까지 개발하고싶은 개발자

0개의 댓글