Java_문법뽀개기 03

5w31892p·2022년 11월 15일
0

Java

목록 보기
4/17

📜 Java

:: ✍ 객체지향언어

:: 접근제어자 (Access Modifier)

  • 멤버 변수, 함수 또는 클래스에 사용
  • 외부에서의 접근을 제한하는 역할
  • 캡슐화 달성하기 위한 도구로 사용

private < default(nothing) < protected < public


private

  • 같은 클래스 내에서만 접근 가능

default(nothing)

  • 같은 패키지 내에서만 접근 가능

protected

  • 같은 패키지 내에 있거나, 다른 패키지의 자식 클래스에서 접근 가능

public

  • 접근 제한 없음
new -> package -> ModifierTest class 생성

1. pkg.ModifierTest class

  • private은 같은 클래스 내에서 접근

∴ 같은 클래스 내에 있는 public에서 접근 가능

package pkg;

public class ModifierTest {
    private void messageInside() {
        System.out.println("This is private modifier");
    }

    public void messageOutside() {
        System.out.println("This is public modifier");
        messageInside(); // private은 같은 클래스 안에서 접근 하능하다고 하였으니 OK
    }

    protected void messageProtected() {
        System.out.println("This is protected modifier");
    }
    void messagePackagePrivate() {
        System.out.println("This is package private modifier");
    }
}

2. Main class

  • super()
    • 내가 상속 받은 부모 클래스 가르키는 키워드
  • super.messageProtected();
    • 같은 패키지 내 또는 다른 패키지 자식 클래스에서 접근 가능
    • 상속받은 Child 내에 쓰였으니 가능
  • modifierTest.messageInside();
    • private은 같은 클래스 내에서만 접근 가능하므로 당연히 error
  • modifierTest.messageProtected();
    • protected는 같은 패키지 또는 다른패키지내 상속 받은 자식만 접근 가능
    • Mine에서 상속 받은게 아니므로 error
  • modifierTest.messagePackagePrivate();
import pkg.ModifierTest;

class Child extends ModifierTest { // 같은 패키지 안 아무것도 없는 자바 밑에 있는 것이기 때문에 호출
    void callParentProtected() { // 아무것도 안붙었기 때문에 package private
        System.out.println("Call my parent's protected method");
        super.messageProtected();
        // super() : 내가 상속 받은 부모 클래스 가르키는 키워드
        // protected는 같은 패키지 내 또는 다른 패키지 자식 클래스에서 접근 가능하다 하였으니 OK
    }
}

public class Main { // 같은 패키지 안 아무것도 없는 자바 밑에 있는 것이기 때문에 호출
    public static void main(String[] args) {
        ModifierTest modifierTest = new ModifierTest();

        modifierTest.messageOutside();
//        modifierTest.messageInside();
            // compile error
//        modifierTest.messageProtected();
            // compile error
//        modifierTest.messagePackagePrivate();
            // public이 아니라 패키지 바깥에서 access할 수 없음
        Child child = new Child();
        child.callParentProtected();
    }
}

package private

  • 아무것도 선언 안하는 것
  • 아무것도 선언되지 않았기 때문에 패키지 내에서만 접근 가능

  • void callParentProtected()
    • 아무것도 안붙었기 때문에 package private
  • modifierTest.messagePackagePrivate();
    • public이 아니라 패키지 바깥에서 access할 수 없음

패키지를 만들고 그 안에 새로운 클래스를 만들게 되면 맨 위 package 선언부가 추가됨

:: Java에서 정확한 클래스 이름이란?

  • 자바가 클래스 인식할 때 패키지이름까지 포함해서 한덩어리로 패키지이름.클래스이름 으로 인식함
    • 즉, package 이름까지 포함한 것이 자바 시스템이 인식하는 클래스의 이름
    • 위와 같은 경우는 pkg.ModifierTest 이 클래스 이름

:: 클래스 이름의 중요성

  • 패키지 이름까지 전부 같은 클래스 이름은 오직 하나
    • pkg.ModifierTest 와 pkg2.ModifierTest 이 있을 때
    • 이 둘은 클래스 이름은 같지만 다른 클래스

  • Scanner를 alt+Enter를 통해서 import 할때 IDE가 추천해주는 선택지 많음
    • 이때 자세히 보면 패키지 이름이 모두 다른 것 확인
      ∴ import할 때 package 이름까지 정확하게 확인해야 함

- 같은 패키지가 아닌 다른 패키지에 있는 클래스를 참조할 때에는 import 구문이 따라옴 - import pkg.ModifierTest;

:: 접근제어자 사용하는 이유

  • 객체지향프로그래밍이란
    • 객체들 간 상호작용을 코드로 표현하는 것
  • 객체간의 관계에 따라 접근 가능한 것과 아닌것의 구분이 필요
  • 클래스 내부에 선언된 데이터의 부적절한 사용으로부터 보호하기 위해
    • 이것을 캡슐화라고함

접근제어자는 캡슐화가 가능할 수 있도록 접는 도구이다.

:: 추상클래스 (Acstract Class)

  • 추상메소드를 선언할 수 있는 클래스
  • 일반 클래스와는 다르게 상속받는 자식클래스 없이 그 자체로 인스턴스를 생성할 수는 없음
    • 이전 Animal Class를 보면 new dog와 new animal 다 가능했음
    • Animal이 추상클래스라면 new dog만 가능하고 new animal은 불가능함

추상메소드

  • 설계만 되어있으며 수행되는 코드에 대해서는 작성이 안된 메소드
  • return type, 함수이름, parameter는 뭘 받을지는 선언하지만 중괄호 안의 구현체는 없음
    • 이 구현은 자식클래스에서 모두 구현해야함

  • 설계만하고 미완성으로 두는 이유는
    • 상속받는 클래스 마다 동작이 달라지는 경우에 상속받는 클래스 작성자가 작성하도록하기 위해

  • 형식
    • abstract 리턴타입 메소드이름();

예제

x : 가로 | y : 세로 | z : 높이
  1. abstract class Bird 내용 채우고, 날 수 없는 새가 있을 때도 if문으로 설정
  2. 날 수 있더라도 멕시멈 몇미터까지인지 return받고, 날 수 없을 경우에는 false를 return받음
  3. 아래 main class에 찍어보기
abstract class Bird {
    private int x, y, z;

    void fly(int x, int y, int z) {
        printLocation();
        System.out.println("이동합니다.");
        this.x = x;
        this.y = y;
        if (flyable(z)) { // 만약 날 수 있다면 z로 이동
            this.z = z;
        } else { // 날 수 없다면
            System.out.println("그 높이로는 날 수 없습니다");
        }
        printLocation();
    }

    abstract boolean flyable(int z); 
    // 날 수 있는 새 날 수 없는 새 판단하는 추상 메소드
    // flyable은 구현제가 없는데도 abstract class 안에 있는 여기서 진짜 함수처럼 사용됨
    // 내용은 자식클래스에서 구현

    public void printLocation() {
        System.out.println("현재 위치 (" + x + ", " + y + ", " + z + ")");
    }
}

class Pigeon extends Bird { // alt + enter치고 맨위 추천 누르면 아래 오버라이드 생성됨
    @Override 
    boolean flyable(int z) {
        return z < 10000; // 높이 10000m 이하까지만 날 수 있도록 return
    }
}
// flyable 구현

class Peacock extends Bird {
    @Override
    boolean flyable(int z) {
        return false; // 공작새는 날 수 없으니 항상 false return
    }
}
// flyable 구현

public class Main {
    public static void main(String[] args) {
        Bird pigeon = new Pigeon();
        Bird peacock = new Peacock();
        System.out.println("-- 비둘기 --");
        pigeon.fly(1, 1, 3);
        System.out.println("-- 공작새 --");
        peacock.fly(1, 1, 3);
        System.out.println("-- 비둘기 --");
        pigeon.fly(3, 3, 30000);
    }
}

// -- 비둘기 --
// 현재 위치 (0, 0, 0)
// 이동합니다.
// 현재 위치 (1, 1, 3)
// -- 공작새 --
// 현재 위치 (0, 0, 0)
// 이동합니다.
// 그 높이로는 날 수 없습니다
// 현재 위치 (1, 1, 0)
// -- 비둘기 --
// 현재 위치 (1, 1, 3)
// 이동합니다.
// 그 높이로는 날 수 없습니다
// 현재 위치 (3, 3, 3)
  • fly(x, y, z) 함수는 Bird 를 상속받는 모든 클래스에서 동일한 동작
  • flyable은 구현체가 없는데도 abstract class 안에 있는 여기서 진짜 함수처럼 사용됨
  • 내용은 자식클래스에서 구현

  • 공작새는 날 수 없으니 항상 false 리턴
    • x, y 좌표로만 움직임
  • 비둘기는 기준이 되는 일정 높이가 되기 전까지는 날 수 있으므로 z좌표 움직임

  • 새의 종류마다 중복코드 없이 구현하려면 추상클래스와 추상메소드를 이용해서 구현 가능
    • 중복코드 제거
    • 각 새마다 주어진 위치까지 날 쑤 있는지 판단 할 수 잇는 유연성 허용

:: 인터페이스(Interface)

  • 객체의 특정 행동의 특징을 정의
  • 함수의 특징(method signature)인 접근제어자, 리턴타입, 메소드 이름만을 정의
  • 이때 함수의 내용은 없음
  • 인터페이스를 구현하는 클래스는 인터페이스에 존재하는 함수의 내용({} 중괄호 안의 내용)을 반드시 구현해야함
  • 인터페이스의 메소드는 추상메소드, static메소드, default 메소드 모두 허용
  • 상속과는 다르게 여러 개의 인터페이스 구현 가능

parameter를 받고 싶다면 추상메소드 옆 괄호 안에 넣고 body ( { } )는 없이 하면 됨

interface 인터페이스명{ 
	public abstract void 추상메소드명(); 
}


interface MyInterface {
	void myMethod(int x) 
}

예제

  • 인터페이스는 멤버를 가지지 못하고 동작 즉 메소드만 정의
    • 실제 구현은 implement 키워드 통해서 구현
interface Flyable {
    void fly(int x, int y, int z);
}

class Pigeon implements Flyable{
    private int x,y,z; // 인터페이스는 필드가 없기 때문에 여기에 정해줌

    @Override
    public void fly(int x, int y, int z) {
        printLocation();
        System.out.println("날아갑니다.");
        this.x = x;
        this.y = y;
        this.z = z;
        printLocation();
    }
    public void printLocation() {
        System.out.println("현재 위치 (" + x + ", " + y + ", " + z + ")");
    }
}

public class Main {

    public static void main(String[] args) {
        Flyable bird = new Pigeon();
        bird.fly(1, 2, 3);
//        bird.printLocation(); // compile error
    }
}
  • 인터페이스는 필드가 없기 때문에 implements 키워드로 구현한 Flyable 아래 private로 정해줌
class Pigeon implements Flyable{
private int x,y,z; 
}
  • bird.printLocation();
    • error
    • Flyable 타입으로 선언한 bird 변수는 실제로 Pigeon 객체이지만
    • interface인 Flyable 에 선언되지 않은 printLocation() 이라는 함수 호출할 수 없음

interface type 으로 선언되어있는 부분에서는 실제 객체가 무엇이든지, interface에 정의된 행동만 할 수 있음

:: 인터페이스 vs 추상클래스

인터페이스

  • 구현하려는 객체의 동작의 명세
  • 다중 상속 가능
  • implements 이용하여 구현
  • 메소드 시그니처 (이름, 파라미터, 리턴타입) 선언만 가능

추상클래스

  • 클래스 상속받아 이용 및 확장을 위함
  • 다중 상속 불가, 단일 상속
  • extends를 통해 구현
  • 추상메소드에 대한 구현 가능

:: ✍ 객체지향 퀴즈

요구조건 만족하는 클래스 작성

요구사항
1. 사람은 자식, 부모님, 조부모님이 있다.
2. 모든 사람은 이름, 나이, 현재 장소정보(x,y좌표)가 있다.
3. 모든 사람은 걸을 수 있다. 장소(x, y좌표)로 이동한다.
4. 자식과 부모님은 뛸 수 있다. 장소(x, y좌표)로 이동한다.
5. 조부모님의 기본속도는 1이다. 부모의 기본속도는 3, 자식의 기본속도는 5이다.
6. 뛸때는 속도가 기본속도대비 +2 빠르다.
7. 수영할때는 속도가 기본속도대비 +1 빠르다.
8. 자식만 수영을 할 수 있다. 장소(x, y좌표)로 이동한다.

요구조건 만족하는 클래스 바탕으로 Main함수로 동작 출력

1. 모든 종류의 사람의 인스턴스는 1개씩 생성한다.
2. 모든 사람의 처음 위치는 x,y 좌표가 (0,0)이다.
3. 모든 사람의 이름, 나이, 속도, 현재위치를 확인한다.
4. 걸을 수 있는 모든 사람이 (1, 1) 위치로 걷는다.
5. 뛸 수 있는 모든 사람은 (2,2) 위치로 뛰어간다.
6. 수영할 수 있는 모든 사람은 (3, -1)위치로 수영해서 간다.

1. Human class

  1. 초기화 생성자
    • Alt + ins
  2. 초기화 생성자 이용
    • Alt + ins
    • x, y 빼고 생성
    • this 다 지우고 -> this(name, age, spped, 0, 0)
  3. 위치 나타내기
  4. 누군지 나타내기
public class Human {
    String name;
    int age;
    int speed;
    int x, y;

    public Human(String name, int age, int speed, int x, int y) { // 초기화 생성자
        this.name = name;
        this.age = age;
        this.speed = speed;
        this.x = x;
        this.y = y;
    }

    public Human(String name, int age, int speed) { // 위 생성자 이용
        this(name, age, speed, 0, 0);
    }

    public String getLocation() {
        return "(" + x + ", " + y + ")";
    }

    protected void printWhoAmI() {
        System.out.println("My name is " + name + ". " + age + " aged.");
    }
}

2. Walkable, Runable, Swimmable Interface

  • 각각 파일로 생성
public interface Walkable {
    void walk(int x, int y);
}
public interface Runable {
    void run (int x, int y);
}
public interface Swimmable {
    void swim(int x, int y);
}

3. GrandParent, Parent, Child class

  • 각각 파일로 생성
    • 조부모는 walk
    • 부모는 walk, run
    • 자식은 walk, run, swim
  • 달릴 때 속도 +2, 수영할 때 속도 +1 빼먹지 말기
  • 생성자
    • Alt + ins
    • speed 지우고, super 안에 speed 속도 적기
  • 인터페이스 구현
    • Walkable 치고 바로 Alt + Enter 메소드 구현
      • 내가 누군지
      • 내 속도는
      • 이동 (x와 y)
      • 현재 위치는
public class GrandParent extends Human implements Walkable {
    public GrandParent(String name, int age) { // 생성자
        super(name, age, 1);
    }

    @Override                            // 인터페이스 구현
    public void walk(int x, int y) {
        printWhoAmI();
        System.out.println("walk speed: " + speed);
        this.x = x;
        this.y = y;
        System.out.println("Walked to " + getLocation());
    }
}
public class Parent extends Human implements Walkable, Runable{
    public Parent(String name, int age) {
        super(name, age, 3);
    }

    @Override
    public void run(int x, int y) {
        printWhoAmI();
        System.out.println("run speed: " + (speed + 2));
        this.x = x;
        this.y = y;
        System.out.println("ran to " + getLocation());
    }

    @Override
    public void walk(int x, int y) {
        printWhoAmI();
        System.out.println("walk speed: " + speed);
        this.x = x;
        this.y = y;
        System.out.println("Walked to " + getLocation());
    }
}
public class Child extends Human implements Walkable, Runable, Swimmable{
    public Child(String name, int age) {
        super(name, age, 5);
    }

    @Override
    public void run(int x, int y) {
        printWhoAmI();
        System.out.println("run speed: " + (speed + 2));
        this.x = x;
        this.y = y;
        System.out.println("ran to " + getLocation());
    }

    @Override
    public void swim(int x, int y) {
        printWhoAmI();
        System.out.println("swim speed: " + (speed + 1));
        this.x = x;
        this.y = y;
        System.out.println("swum to " + getLocation());
    }

    @Override
    public void walk(int x, int y) {
        printWhoAmI();
        System.out.println("walk speed: " + speed);
        this.x = x;
        this.y = y;
        System.out.println("Walked to " + getLocation());
    }
}

4. Main class

  • 조부모든, 부모든, 자식이든 다 같은 사람이니 Human으로 상속
  1. 각각 인터페이스 생성
  2. 각 이름, 나이, 속도, 장소 정보
  3. for 안에 if문으로 고고
public class Main {
    public static void main(String[] args) {
        Human grandParent = new GrandParent("할아버지", 80);
        Human parent = new Parent("엄마", 52);
        Human child = new Child("나", 20);

        Human[] humans = {grandParent, parent, child};
        for (Human human : humans) {
            System.out.println(human.name + ", 나이: " + human.age + ", 속도: " + human.speed + ", 장소: " + human
                    .getLocation());
        }
        System.out.println("<활동 시작>");
        for (Human human : humans) {
            if (human instanceof Walkable){
                ((Walkable) human).walk(1,1); // human.walk 치고 엔터치면 자동완선
                // 위에선 Human type인데 if 문에서 Walkable인게 확인됐으니 Walkable type으로 캐스팅 하겠다라는 의미
                System.out.println("- - - - - -");
            }
            if (human instanceof Runable){
                ((Runable) human).run(2,2);
                System.out.println("- - - - - -");
            }
            if (human instanceof Swimmable){
                ((Swimmable) human).swim(3,-1);
                System.out.println("- - - - - -");
            }
        }
    }
}

5. 결과

할아버지, 나이: 80, 속도: 1, 장소: (0, 0)
엄마, 나이: 52, 속도: 3, 장소: (0, 0)
나, 나이: 20, 속도: 5, 장소: (0, 0)
<활동 시작>
My name is 할아버지. 80 aged.
walk speed: 1
Walked to (1, 1)
- - - - - -
My name is 엄마. 52 aged.
walk speed: 3
Walked to (1, 1)
- - - - - -
My name is 엄마. 52 aged.
run speed: 5
ran to (2, 2)
- - - - - -
My name is 나. 20 aged.
walk speed: 5
Walked to (1, 1)
- - - - - -
My name is 나. 20 aged.
run speed: 7
ran to (2, 2)
- - - - - -
My name is 나. 20 aged.
swim speed: 6
swum to (3, -1)
- - - - - -

캐스팅이란?

실제 객체가 Walkable 이기도 하고 Human이기도 했을 때,
어떤 종류의 type으로 그것인 척해서 사용하겠다라는 의미

노트에 손으로 적어보면서 확인하고 익히기!!!! 젭r

0개의 댓글