본 캠프_9일차

졸용·2025년 2월 27일

TIL

목록 보기
10/144

⭐ Java 강의

강의자료_2주차

Java 입문 과정에서 강의 들으며 빠른 학습 진도를 위해 추후에 집중해서 복습할 부분 ➡️메모하기

⭐ 객체지향 PART1 - 캡슐화 (접근제어자)

  • 캡슐화(Encapsulation)란?

    • 객체의 정보를 외부에서 직접 접근하지 못하게 보호하는 개념

    • 클래스 혹은 객체의 캡슐화는 접근제어자 를 통해서 구현할 수 있다

    • 캡슐화를 통해 정보를 보호하고 필요한 경우에만 안전하게 접근할 수 있도록 한다

  • 접근제어자(Access Modifier)

package chapter2.capsulation;

public class Person {

    // 속성
    private String name;
    private String secret;

    // 생성자
    public Person(String name) {
        this.name = name;
    }

    // 기능
    public void methodA() {}
    private void methodB() {}

    // 게터
    public String getName() {
        return name;
    }

    // 세터
    public void setName(String name) {
        this.name = name;
    }
}
package chapter2.capsulation;

public class Main {
    public static void main(String[] args) {

        // 생성자 호출
        Person person = new Person("gygim");

        // 인스턴스 변수 접근
//        person.name = "gygim";
//         person.secret = "??";

        // 인스턴스 메서드 접근
//        person.methodA();
//        person.methodB();

        // 게터
        String name = person.getName();
        System.out.println("이름: " + name);

        // 세터
        person.setName("Steve");
        String name2 = person.getName();
        System.out.println("이름: " + name2);
    }
}
  • 데이터 접근 - 게터(Getter)와 세터(Setter)

    • 캡슐화가 잘 적용된 클래스는 내부 데이터를 private 으로 보호하고 있다

    • 데이터 조회나 변경이 필요한 경우 안전한 접근방법이 필요하다
      → 그 역할을 수행하는 메서드가 바로 게터(Getter)와 세터(Setter)

package chapter2.capsulation.v1;

// 핵시설 관리하는 개발자
public class DataStore {
    private String store;

    public void setStore(String store) {
        if (store.equals("B")) {
            System.out.println("B 가 입력되면 안됩니다.");
        } else {
            this.store = store;
        }
    }
}
package chapter2.capsulation.v1;

public class Main {
    public static void main(String[] args) {

        DataStore dataStore = new DataStore();
//        dataStore.store = "B";
        dataStore.setStore("B");
    }
}
package chapter2.capsulation.v2;

// 로보트를 걷게 만들자
public class Robot {

    private boolean leftLeg;
    private boolean rightLeg;
    private boolean leftArm;
    private boolean rightArm;

    // ...

//    public void setLeftLeg(boolean leftLeg) {
//        this.leftLeg = leftLeg;
//    }
//
//    public void setrightLeg(boolean rightLeg) {
//        this.rightLeg = rightLeg;
//    }
//
//    public void setLeftArm(boolean leftArm) {
//        this.leftArm = leftArm;
//    }
//
//    public void setRightArm(boolean rightArm) {
//        this.rightArm = rightArm;
//    }

    // 의미있는 세터
    public void walk(boolean power) {
        this.leftLeg = power;
        this.rightLeg = power;
        this.leftArm = power;
        this.rightArm = power;
    }
}
package chapter2.capsulation.v2;

public class Main {
    public static void main(String[] args) {

      Robot robot = new Robot();

      // 무분별한 세터 예시
//      robot.setLeftLeg(true);
//      robot.setRightLeg(true);
//      robot.setRightArm(true);
//      robot.setRightArm(true);

      // 의미있는 세터
      robot.walk(true);

    }
}

⭐ 객체지향 PART2 - 상속

  • 상속(Inheritance) 이란?

    • 클래스간의 관계를 부모(상위), 자식(하위) 로 바라보는 개념

    • 이 구조를 통해 재사용성, 확장이 가능
      → 물려받은 속성과 기능은 자식 클래스에서 재사용할 수도 있고, 확장할 수도 있다

    • extends 키워드를 사용해서 상속관계를 구현한다

    • 코드 중복을 줄이고 유지보수성을 높일 수 있다

    • 추상화, 다형성을 구현하는데 잘 활용된다

  • 재사용성

부모 클래스의 내용을 물려받아 그대로 재사용할 수 있다

  • super - 부모 인스턴스

    • 부모클래스의 멤버(변수, 메서드)에 접근할 때 사용하는 키워드
      → 자식 클래스에서 부모의 변수나 메서드를 명확하게 호출할 때 사용

    • 부모가 먼저 생성되어야 하므로 super() 는 항상 생성자의 첫 줄에 위치해야 한다

  • 확장

    • 부모클래스의 기능을 유지하면서 자식클래스에서 기능을 확장할 수 있다

    • 자식클래스에서 새로운 메서드를 추가하면 된다

  • 재정의 - 메서드 오버라이딩(overriding)

    • 부모 메서드를 자식 클래스에서 변경하여 재정의하는 것을 의미

    • 오버라이드된 메서드에는 @Override 키워드를 붙이는 것을 권장 (없어도 동작)

    • @Override 를 붙이면 컴파일러가 부모 클래스에 동일한 메서드가 없다고 경고를 줘서 실수를 방지할 수 있다

    • 메서드 이름, 매개변수, 반환타입이 완전히 동일해야 한다

    • 접근 제어자는 부모보다 더 강한 수준으로만 변경 가능하다

package chapter2.inheritance;

public class Parent {

    public String familyName = "스파르탄";
    public int honor = 10;

    public Parent() {
        System.out.println("부모 생성자");
    }

    public void introduceFamily() {
        System.out.println("우리 " + this.familyName + "가문은 대대로 ...");
    }

}
package chapter2.inheritance;

public class Child extends Parent {

    public String familyName = "gygim";

    public Child() {
        super();
        System.out.println("자식 생성자");
    }

    public void superTest() {
        System.out.println(super.familyName);
    }

    // 부모에는 없지만 자식에만 있는 기능
    public void showSocialMedia() {
        System.out.println("SNS에서 우리 가문을 소개드립니다.");
    }

    @Override
    public void introduceFamily() {
        System.out.println("오버라이드");
    }

}
package chapter2.inheritance;

public class Main {
    public static void main(String[] args) {

        Child child = new Child();
        System.out.println("가문이름: " + child.familyName);
        System.out.println("명예: " + child.honor);
        child.introduceFamily();
        child.superTest();
        child.showSocialMedia(); // 부모에는 없지만 자식에만 있는 기능
    }
}

  • 추상클래스

    • 공통 기능을 제공하면서 하위 클래스에 특정 메서드 구현을 강제하기 위해 사용

    • 객체를 생성할 목적이 아니라 “설계도” 역할을 할때 적합

    • abstract 키워드로 클래스를 선언하면 추상클래스이다

    • abstract 키워드로 메서드를 선언하면 자식클래스에서 강제로 구현해야한다

    • 추상클래스로 객체를 생성할 수 없다

    • 일반 클래스처럼 변수와 메서드를 가질 수 있다

package chapter2.inheritance.abstractexample;

// 추상클래스 선언
abstract class Animal {

    public String name;

    abstract void eat();

    public void sleep() {
        System.out.println("쿨쿨..");
    }
}
package chapter2.inheritance.abstractexample;

public class Cat extends Animal {

    @Override
    void eat() {
        System.out.println("냠냠..!");
    }
}
package chapter2.inheritance.abstractexample;

public class Main {
    public static void main(String[] args) {

        // 추상클래스는 인스턴스화 할 수 없다.
//        Animal animal = new Animal();
        Cat cat = new Cat();
        cat.name = "cat";
        cat.sleep();

        // 자식에서 강제 구현된 메서드
        cat.eat();

    }
}

⭐ 객체지향 PART3 - 추상화

  • 추상화란?

    • 불필요한 정보를 제거하고 본질적인 특징만 남기는 것을 의미
      → 고양이 → 동물 → 생명체

    • 객체지향 프로그래밍에서는 추상화의 계층적 특징을 활용해서 유지보수성이 좋은 프로그램을 만들 수 있다

    • 추상화의 특징은 다형성에서 활용된다

  • 인터페이스 상속를 활용한 추상 계층 표현
package chapter2.abstraction.v1;

public interface LifeForm {
    void exist(); // 공통: 모든 생명체는 존재한다.
}
package chapter2.abstraction.v1;

public interface Animal extends LifeForm {

    void makeSound(); // 공통: 모든 동물은 소리를 낸다.
}
package chapter2.abstraction.v1;

public class Cat implements Animal {

    @Override
    public void exist() {
        System.out.println("고양이가 존재합니다.");
    }

    @Override
    public void makeSound() {
        System.out.println("야옹");

    }

    public void scratch() {
        System.out.println("스크래치");
    }

}
package chapter2.abstraction.v1;

public class Main {
    public static void main(String[] args) {

        Cat cat = new Cat();
        cat.exist();
        cat.makeSound();
        cat.scratch();
    }
}

  • 클래스 상속을 활용한 추상 계층 표현
package chapter2.abstraction.v2;

public class LifeForm {

    public void exist() {
        System.out.println("생명체는 존재합니다.");
    }
}
package chapter2.abstraction.v2;

public class Animal extends LifeForm {

    public void makeSound() {
        System.out.println("동물은 소리를 냅니다.");
    }
}
package chapter2.abstraction.v2;

public class Cat extends Animal {

    @Override
    public void makeSound() {
        System.out.println("야옹!");
    }

    public void scratch() {
        System.out.println("스크래치");
    }
}
package chapter2.abstraction.v2;

public class Main {
    public static void main(String[] args) {

        Cat cat = new Cat();
        cat.exist();
        cat.makeSound();
        cat.scratch();
    }
}

⭐ 객체지향 PART4 - 다형성

  • 다형성(Polymorphism)이란?

    • 하나의 타입으로 여러 객체를 다룰 수 있는 객체지향의 4번째 특징

    • 추상 계층이라는 특징을 활용해서 다형성을 구현할 수 있다

    • 추상화의 특징은 다형성에서 활용된다

  • 형변환(Casting)

    • 부모타입으로 자식타입을 다룰 수 있는 이유는 자동으로 형변환(Casting) 이 발생했기 때문

    • 자식타입 → 부모타입: 업캐스팅(UpCasting)
      ⚠️ 주의사항 : 업캐스팅은 부모의 타입으로 데이터를 다룰 수 있지만 자식 클래스의 고유기능을 활용할 수 없다 → 자식 클래스의 고유 기능을 사용하려면 다운캐스팅이 필요

    • 부모타입 → 자식타입: 다운캐스팅(DownCasting)
      ⚠️ 주의사항 : 잘못된 다운캐스팅은 컴파일단계에서 감지할 수 없다
      → 그래서 다운캐스팅을 사용할때 항상 instanceof 를 활용해야 한다

package chapter2.polymorphism;

public interface LifeForm {

    public void exist();
}
package chapter2.polymorphism;

public interface Animal extends LifeForm {

    void makeSound();
}
package chapter2.polymorphism;

public class Cat implements Animal {

    @Override
    public void exist() {
        System.out.println("고양이가 존재합니다.");
    }

    @Override
    public void makeSound() {
        System.out.println("야옹");
    }

    public void scratch() {
        System.out.println("스크래치");
    }

}
package chapter2.polymorphism;

public class Dog implements Animal {

    @Override
    public void exist() {
        System.out.println("강아지가 존재합니다.");
    }

    @Override
    public void makeSound() {
        System.out.println("멍멍");

    }

    public void wag() {
        System.out.println("흔들흔들");
    }
}
package chapter2.polymorphism;

public class Main {
    public static void main(String[] args) {

        // 다형성 활용
        Animal animal1 = new Cat();
        Animal animal2 = new Dog();

        animal1.exist();
        animal1.makeSound();

        animal2.exist();
        animal2.makeSound();

        // 업캐스팅 주의사항
//        animal.scratch();
//        animal.wag();

        // 다운캐스팅
        Cat cat = (Cat) animal1;
        cat.scratch();

        Dog dog = (Dog) animal2;
        dog.wag();

        // 잘못된 다운캐스팅 문제
//        Cat cat2 = (Cat) animal2; // animal2 = Dog;
//        cat2.scratch();

        // 다운캐스팅 instanceof 활용 방법 -> 의도치 않은 예외 입력시 문구 출력
        if (animal2 instanceof Cat) {
            Cat cat2 = (Cat) animal2;
            cat2.scratch();
        } else {
            System.out.println("객체가 고양이가 아닙니다.");
        }

        System.out.println("::::");

        Animal[] animals = {new Cat(), new Dog(), new Cat()};
        for (Animal animal : animals) {
            animal.makeSound();
        }
    }
}

profile
꾸준한 공부만이 답이다

0개의 댓글