본문 바로가기

Study for Backend/Programming language - Java

[Java기초] Class와 객체2

1. 오버라이딩(overriding)
- 오버라이딩이란 상속받은 메소드를 자식 클래스에서 재정의하여 사용하는 것이다.
- 자식 클래스에서 부모의 메소드를 수정해야 할 때 사용된다. 일반 클래스의 상속 관계에서는 많이 사용되지는 않고 추상 클래스나 인터페이스에서 필수적으로 사용되는 개념이다.
- 자식 클래스에서 부모 클래스의 메소드와 동일한 시그니쳐(메소드 이름, 리턴 타입, 매개변수의 개수/ 자료형/순서)를 적용하여야 한다.
- 오버라이딩 결과 부모 메소드는 은닉되고 자식 클래스에서 재정의된 메소드만 기본적으로 호출된다. 필요시 super. 으로 부모 메소드를 호출할 수 있다.
참고 링크
https://blog.naver.com/heartflow89/220961515893
https://yeomboyeon.tistory.com/64

2. 접근 제어자
제어자들 중에 접근의 범위를 지정해주는 제어자들을 접근 제어자라고 한다. 제어자는 따로 명시하지 않아도 항상 default제어자가 붙어있다.

접근 제어자의 종류
public : 접근 제한이 전혀 없는 것이다. 다른 클래스에서도 접근할 수 있고, 다른 패키지에서도 접근할 수 있다. 한 프로젝트 어느 곳에서든 접근이 가능하다.

protected  :  패키지에 관계없이 상속관계에 있는 자식 클래스에서 접근할 수 있도록 해준다. 상속관계에 있다면 어디서든 접근이 가능하다.


default  :  아무런 접근 제어자를 붙이지 않았다면 자동으로 default로 적용된다. 이 접근 제어자로는 한 패키지 내에서 모두 접근이 가능하다. 따라서 상속관계에서 패키지를 넘나들 수 있는 protected보다 더 좁은 범위라고 할 수 있다.

private  :  가장 강도가 높은 제한이다. private은 한 클래스 안에서만 접근이 가능하다. 클래스 외부에서 직접 접근할 수 없어서 데이터를 보호하는 것에 용이하다.

접근 제어자 사용 가능 범위
이 접근 제어자들은 아무곳에나 붙일 수 있을까? 클래스를 private으로 선언하면 아무도 접근하지 못하는 클래스가 만들어질 탠데 의미가 있을까? 여기서 접근 제어자들이 클래스, 메소드, 변수에 어떻게 적용되는지 알아볼 필요가 있다.

클래스 - public, (default)
클래스에는 public, default만 붙일 수 있다. 내부 클래스, 중첩 클래스에서는 모든 접근 제어자가 허용되지만, 특수한 경우이기에 일반적인 경우만을 설명하겠다.
클래스에 이 두가지만 있는 이유는 프로젝트 폴더 내에서 클래스가 분류되는 방법은 패키지 단위이기 때문이다. 따라서 같은 패키지에서 접근 가능한지 아닌지만 명시해주면 되므로 이 두 접근 제한자만 존재하는 것으로 보인다.
한 가지 주의할 점은 하나의 java파일에는 반드시 하나의 public 클래스만 존재해야 한다는 것에 주의하자. 이것의 이유는 하나의 파일에 너무 많은 public 클래스를 생성해버리면 규모가 커지면 커질수록 내가 사용하는 클래스가 어디 있는지 찾을 수가 없어진다. 따라서 애초에 자바를 설계할 때 부터 이를 제한하여 유지보수에 용이성을 높인 것이라고 한다.

메소드, 멤버변수 - public, protected, (default), private
모든 접근 제한자를 사용할 수 있다. 이들은 클래스 안에 존재하기 때문에 상속관계가 존재할 수 있고 클래스 내부에서만 사용하도록 제한하는 것도 필요하게 된다. 그래서 모든 접근 제한자를 사용할 수 있다.
지역변수 - 사용할 수 없음
지역변수라는 개념 자체가 한 메소드 또는 반복문, 특정 모듈 안에서 사용되고 사라지는 개념이기 때문에 접근 제한자를 굳이 만들 필요가 없다.

3. 캡슐화(Encapsulation)
하나의 클래스는 그 내부에서 어떤 작업을 하는지에 관점을 두는 것이 아니라, 어떤 역할을 하는지에 초점을 두는 개념이다. 즉, 실제로 구현된 부분은 외부에 노출시키지 않고 특정 기능만을 알려주는 것이다.
따라서 캡슐화를 실현하기 위해서 내부에 선언된 데이터를 공개할 것인지, 아니면 숨겨서 안보이게 할 것인지 정확하게 정의해줄 필요가 있다. 이것이 정보은닉(Data Hiding)이라고 하는 개념이다. 정보은닉은 캡슐화를 실현하기 위한 구체적인 방법의 일종이라고 할 수 있다.
예를들어 내가 랜덤으로 숫자를 생성하여 사용자가 그 숫자를 맞추게 하는 간단한 게임 프로그램을 만들었다고 하면, 랜덤으로 생성된 이 숫자는 private으로 선언하여 클래스 외부로 보여주지 않고, 단지 클래스 내부의 다른 함수들을 통해 비교하고 정답 여부를 도출하는 것에만 사용해야 한다는 것이다.

 

참고링크

https://hyoje420.tistory.com/13

 

// Java 프로그래밍 - 클래스와 객체_2
import car.Car2;
import java.util.SortedMap;

class Car {
    String name;
    String type;

    Car(String name, String type) {
        this.name = name;
        this.type = type;
    }

    public void printCarInfo() {
        System.out.println("=== Car Info ===");
        System.out.println("name: " + name);
        System.out.println("type: " + type);
    }

    // 오버로딩 구현
    public void printCarInfo(String date){
       this.printCarInfo();
        System.out.println("date : " + date );
    }

    public void printCarInfo(int number){
       this.printCarInfo();
        System.out.println("number : " + number );
    }

    public void printCarInfo(String date , int number){
        this.printCarInfo();
        System.out.println("date : " + date );
        System.out.println("number : " + number );
    }

}


class Car3 {
    // 스태틱 변수
    static String name = "None";
    String type;

    Car3(String name, String type) {
        this.name = name;
        this.type = type;
    }

    public void printCarInfo() {
        System.out.println("=== Car Info ===");
        System.out.println("name: " + name);
        System.out.println("type: " + type);
    }

    // 스태틱 메소드
    public static void getName(){
        System.out.println("Car name : " + name);
    }
}


public class Main {

    public static void main(String[] args) {
        Car myCar1 = new Car("a", "sedan");
        myCar1.printCarInfo();

//      1. 오버로딩 사용
        System.out.println("=== 오버로딩 사용 ===");
        myCar1.printCarInfo("2024");
        myCar1.printCarInfo(1234);
        myCar1.printCarInfo(1234);


//      2. 접근 제어자
        System.out.println("=== 접근 제어자 ===");
        Car2 myCar2 = new Car2("AAA","BBB","CCC","DDD");
/*        System.out.println(myCar2.name1);
        System.out.println(myCar2.name2);
        System.out.println(myCar2.name3);
        System.out.println(myCar2.name4);*/


//      3. Static
        System.out.println("=== Static ===");
        Car3.getName();
        Car3 myCar3_1 = new Car3("A","SUV");
        Car3 myCar3_2 = new Car3("B","RV");
        Car3 myCar3_3 = new Car3("C","Sedan");

        myCar3_1.printCarInfo();
        myCar3_2.printCarInfo();
        myCar3_3.printCarInfo();
    }

}

 

package car;
public class Car2 {
    public String name1;
    private String name2;
    protected String name3;//상속을 받아야 사용 가능
    String name4;

    public  Car2(String name1,String name2,String name3, String name4){
        this.name1 = name1;
        this.name2 = name2;
        this.name3 = name3;
        this.name4 = name4;

    }
}

 

// Practice
// 계산기 덧셈의 여러 타입 오버로딩

class Calculator {

    public int sum(int a, int b) {
        return a + b;
    }
    public double sum(double a, double b) { return a + b;}
    public double sum( String a, String b) { return double.pareDouble(a) + double.pareDouble(b); }
    public int sum(int a, int b, int c) { return a + b + c; }

}

public class Practice {
    public static void main(String[] args) {
        // Test code
        Calculator c = new Calculator();
        System.out.println(c.sum(1, 2));
        System.out.println(c.sum(1.0, 2.0));
        System.out.println(c.sum("1", "2"));
        System.out.println(c.sum(1, 2, 3));
     }
}