[4기] 백엔드 개발자 부트캠프 "오르미" ~ing/[4기] 백엔드 개발자 부트캠프 오르미 수업 복습

[4기] 31일차 Java ( final필드와 상수,접근제어자, set&get, 상속 )

sohee99 2024. 2. 1. 20:47

오늘의 학습 내용! 

 

final필드

 

final은 최종적이라는 의미를 갖듯이 필드에 final을 입력 시 이것이 곧 최종값이 되어 실행 도중 수정할 수 없다! 

 

public class Person {
        // final 은 값이 바뀌면 x
        final String nation = "korea"; // 필드 안에서 초기화 가능
        final String name;

 

이렇게 nation을 final로 선언했다면 다른 값으로 변경 시도 시, 컴파일 오류가 발생한다! 

 

즉, final은 값이 바뀌면 안될 때 사용한다!!!!!! ㅎㅎㅎ

 

 

 

public class Person {
        // final 은 값이 바뀌면 x
        final String nation = "korea"; // 필드 안에서 초기화 가능
        final String name;

        Person(String name){
            this.name = name; //생성자 안에서 초기화 할 수있는 것
        }

        Person(){
            //디폴트생성자를 쓰게되면 필드의 final 초기화가 되지 않음.
            this.name = "초기이름생성";
        }
    }

 

public class PersonExample {

    public static void main(String[] args) {
        Person person = new Person("사람1");

        System.out.println(person.name);
        System.out.println(person.nation);
    }
}

 

final 실습 작성 해보기 

 

상수(static final)

 

- 원주율 파이, 지구의 무게 및 둘레는 불변의 값인데 이런 불변의 값을 저장하는 필드가 자바에서는 상수라고 한다. 

 

final 필드는 수정할 수 없는 필드지만 이것을 곧 상수라고 부르지는 않는다! 

 

final필드는 객체마다 저장되고 생성자 매개변수로 여러가지 값을 가질 수 있기 때문에 상수가 될 수 없다! 

 

기억기억 하자!!!!😊

 

 

final 필드는 바뀌지 않는 수 지만 상수는 아니다! 

 

상수는 모두 대문자로 작성하는 것이 컨벤션! 혼합된 이름이라면 _언더바로 연결! 

 

public class Earth {
    static final double PI = 3.14159;
    static final double EARTH_RADIUS = 6400;
    static final double EARTH_SURFACE_AREA;

    static {
        EARTH_SURFACE_AREA = 4 * PI * EARTH_RADIUS * EARTH_RADIUS;
    }
}

 

public class EarthExample {
    public static void main(String[] args) {
        System.out.println("지구의 반지름 :" + Earth.EARTH_RADIUS + "km");
        System.out.println("지구의 표면적 :" + Earth.EARTH_SURFACE_AREA + "km^2");
    }
}

 

지구의 반지름 과 표면적을 출력하기!!!! ㅎㅎㅎ 

 

지구의 반지름: 6400.0km

지구의 표면적: 5.147185403641517E8 km^2

 

출력값은 이렇게 나옵니당 ㅎㅎㅎ

 

 

접근 제어자

 

- 변수나 메소드의 사용권한을 설정할 수 있다. 

 

출처 - 이스트소프트 조성연

 

이렇게 접근 제어자는 4가지 종류가 있다. private 으로 갈수록 좁아 터진걸 볼 수 있는데, 

 

좁은 만큼 접근 범위가 적다는거! 

 

코드로 범위를 설명하자면 ! 

 

패키지 구성

 

public class AccessSample {
    private int number = 1;
    //클래스 내에서만 접근 가능
    int number2 = 2;
    //같은패키지
    protected int number3 = 3;
    //같은 패키지 or 상속을 받은 부모클래스에서 선언했을 경우 자식 클래스가 패키지가 다르더라도 사용가능
    public int number4 = 4;

    void  printNumber(){
        //클래스내부에서는 private 포함 다 가능
        System.out.println(number);
        System.out.println(number2);
        System.out.println(number3);
        System.out.println(number4);
    }
}

 

이렇게 access 라는 패키지에 AccessSample 의 클래스를 생성하고 코드를 작성했습니당!!!

 

private, default, protected, public 을 입력 후 출력해보면 

 

* int number2 = 2;와 같이 접근제어자를 아무것도 입력안했을 경우 default 접근제어자에 해당

 

클래스 내부에서 출력했을 때는 모두 접근이 가능하다! 

 

그럼 다른 패키지에서 출력을 입력하면?

 

public class AccessSamplePrint {

    public static void main(String[] args) {
        AccessSample access = new AccessSample();
        System.out.println(access.number4);
        //패키지가 다르기 때문에 public 인 number4만 가능
    }

 

 Access2 패키지를 만들어 AccessSamplePrint 클래스를 만들어 접근 할려고 하면? 

 

위와같이 number4만 가능하다!

 

왜냐?  public만 다른 패키지라도 접근이 가능하기 때문에 

 

나머지 접근제어자들은 접근이 불가능하다!!! 

 

 

그럼 private는? 

 

그냥 클래스 내에서만 접근이 가능하다! 

 

그럼  default는 ?

 

 

동일한 패키지안의 클래스에서 접근 할려고하면 ? 가능하다! 

 

 

여기서 중요 포인트는 protected!!!!!!!😁

 

protected는 default와 같이 동일한 패키지 안의 클래스에 접근하지만 

 

한가지 더 접근이 가능하다 그것은바로오오오오오~~~~

 

 

부모클래스에게 상속받은 자식클래스에서 접근이 가능하다! 

 

public class ChildAccessSample extends AccessSample {
            //extends 키워드 사용 부모클래스의 속성들을 받아올 수 있다.

    void  printNumber(){
       // System.out.println(number);  //접근 불가 - private 같은 클래스내에서만 접근 가능
       // System.out.println(number2); //접근 불가 - default 같은 패키지 내에서만 가능하기 때문에 접근 no
        System.out.println(number3); //접근 가능 - protected 부모 클래스에게 상속받았기 때문에
        System.out.println(number4); //접근 가능 - public
    }
}

 

ChildAccessSample이 AccessSample 과 다른 패키지에 속하지만 

 

 

extends 키워를 사용하여  AccessSample 부모클래스의 속성을 받아올 수 있는것!

 

 

이렇게 출력시, private 와 default는 다른 클래스 및 다른 패키지에 속하므로 당연히 접근 불가일 것이고

 

 

접근이 가능한건 상속받은 protected 와 어떤 패키지에 있어도 가능한 public이 접근이 가능하다! 

 

접근 제어자 같은 클래스 같은 패키지 자식 클래스  전체
public O O O O
protected O O O  
default O O    
private O      

 

 

 

 

 

이런 접근제어자는 왜 사용하는것일까? 

 

 

 


접근 제어자를 사용하는 이유!

1. 외부로부터 데이터를 보호하기 위해서
2. 외부에는 불필요하고 내부에서 사용하는 부분을 감추기 위해 ( 캡슐화 ) 

 

이렇게 접근 제어자를 사용함으로 서 외부에서 함부로 변경하지 못하게 접근 제한을 하는데 

 

 


이것을 데이터 감추기 즉 캡슐화에 해당한다! 

 

 

Setter 메소드

 

- 데이터를 외부에서 접근할 수 없도록 막고 메소드를 공개하여 외부에서 메소드를 통해 데이터에 접근하도록 유도

 

public class Car {
    private int speed;

 

public void setSpeed(int speed){
    if (speed < 0) {
        this.speed = 0;
    } else {
        this.speed = speed;
    }
}

 

private의 접근제어자를 사용하여 외부에서 접근이 안되게 막아버리고, 

 

setter 메소드로 speed값을 변경할 수 있게 공개 public하였다. 

 

 

Getter 메소드

 

setter과 같이 읽을 때도 메소드를 사용하는 것이 좋은데! 

 

그때 사용하는것은 Getter!!!!

 

메소드로 필드값을 가공하고 외부로 전달! 

 

public class Car {
    private int speed;

    public double getSpeed() {
        double km = speed * 1.6;
        return km;
    }
}

 

setter과 동일하게 private으로 접근을 막고,

 

getter을 통해 스피드 값 1.6을 곱한 값으로 가공 후 외부 전달! 

 

 

이렇게 getter와 setter로 필드값을 안전하게 변경 및 사용하는 것이 베스트!!!!!!!!!!

 

출처 - 이스트소프트 조성연

 

하지만 필드타입이 boolean일경우!

 

get으로 시작하지 않고 is 로 시작한다는거!

 

boolean isStop(){
    return stop;
}

 

이렇게 ㅎㅎㅎㅎㅎㅎㅎㅎ

 

신기하구려 ㅎㅎㅎㅋㅋㅋㅋㅋ

 

 

상속

 

- 부모클래스의 멤버를 자식 클래스에게 물려주는 것!

 

1. 클래스를 재활용하여 새로운 class 작성

2. 클래스 간 공유 될 수 있는 속성과 기능을 상위클래스로 추상화 

3. 부모의 클래스를 재활용하여 물려받기 사용 

 

출처- 이스트소프트 조성연

 

 

코드로 보게 되면,

 

부모클래스 Vehicle

public class Vehicle {
    String modal; //부모클래스라도 dafault 라서 다른 패키지에서는 접근 불가 이때는 protected 사용

    int speed;

    boolean stop;

    String color;

    int wheelCount;

    boolean onOff;

    public String getModal(){ //private 라면 getModal 을 사용하여 접근 한다.
        return modal;
    }

    public Vehicle(){
        modal = "Tesla modelX";
        speed = 300;
        stop = true;
    }

    public Vehicle(String modal, int speed){
        this.modal = modal;
        this.speed = speed;
    }
    public void print(){
        System.out.println(modal + ", " + speed + "," + stop);
    }
}

 

자식 클래스 Motorcycle

public class Motorcycle extends Vehicle{ // 다른언어와 달리 자바는 다중 상속이 지원되지 않는다.

    private String rider; //새로운 요소도 추가 가능

    void  setSpeed(int speed){   //새로운 메소드 추가 가능
        this.speed = speed;
    }
    public void print(){
        System.out.println("Child(Motorcycle) : " + modal + ", " + speed + "," + stop);
    }
}

 

자식 클래스2 Car

public class Car extends Vehicle{

    Car(String model, int speed, boolean stop){
        super(model, speed);
    }

    public void print(){
        System.out.println("Child : " +modal + ", " + speed + "," + stop);
    }
}

 

실행할 Printer 까지!

public class InheritPrinter {

    public static void main(String[] args) {
        Motorcycle motorcycle = new Motorcycle();
        motorcycle.speed = 0;
        motorcycle.stop = false; //자식클래스에서는 부모값을 물려받았지만 여기서 변경가능
        motorcycle.print();
    }
}

 

public class Motorcycle extends Vehicle{ // 다른언어와 달리 자바는 다중 상속이 지원되지 않는다.

 

이렇게 부모 클래스 Vehicle을 상속 받을려면 extends 키워드를 사용하여 물려받는다. 

 

자바의 경우 부모클래스 다중 상속은 지원되지 않는다는점! 부모클래스는 1개만!!!

 

 

상속을 통해 알수 있는 것은

 

부모클래스에서 사용된 필드와 메소드를 물려 받고 

 

+ 자식클래스에서 추가적인 생성자와 메소드 또한 생성할 수 있다. 

 

하지만, 모든 필드와 메소드들을 물려받는 것이 아닌

 

private 접근 제한이 있는 필드와 메소드는 상속 제외이며,

 + 여기선 public 접근제어자로 getter을 이용하여 호출하면 ok

 

부모클래스와 자식 클래스가 다른 패키지에 존재하면 default 접근 제한을 갖는 필드, 메소드는 상속 대상 제외

+ 이것 또한 접근 허용하고 싶다면 default에서 protected로 바꾸면? ok

 

이렇게 공통으로 사용되는 메소드나 필드를 부모클래스에서 상속을 중복적인 코드를 제거 할 뿐만아니라

 

수정이 필요시, 부모클래스에서 한번만 수정해주면 모든 자식 클래스에서 수정효과를 가져옴으로 유지보수 good!!!

 

만약, 상속받았지만? 값을 변경하고 싶을 땐, 

 

getter을 이용하여 가공하여 바꿔서 호출 할 수 있으며, 

 

자식 클래스에서 직접 값을 변경 해도 된다! 

 

ex)

public static void main(String[] args) {
    Motorcycle motorcycle = new Motorcycle();
    motorcycle.speed = 0;
    motorcycle.stop = false; //자식클래스에서는 부모값을 물려받았지만 여기서 변경가능
    motorcycle.print();
}

 

이렇게 직접 변경 해도 ok!!!!

 

부모 생성자 호출

 

출처 - 이스트소프트 조성연

 

자식 객체를 생성하면 부모 객체가 먼저 생성되는 식이다. 

 

모든 객체는 클래스의 생성자를 호출해야만하는데 그럼 부모생성자는 ?

 

자식 생성자의 맨 첫줄에서 호출한다. 

 

public class Person {
    String name;
    String ssn;

 

 

이렇게 부모 클래스 Person에 생성자가 없다면?

 

자식 요소인   

 

public class Student extends Person{
    int studentNo;

    /* 부모클래스에 만약 생성자가 없다면
    Student(){
        super(); // super 맨첫줄에 선언해야한다.
    }
     */

 

Student에서 super()을 선언하여 부모의 기본 생성자를 호출한다!

 

+ 부모클래스의 생성자가 없을 시 자동으로 디폴트 생성자 쏘옥 

 

public Person(){}

 

요렇게! ㅎㅎㅎ

 

 

부모클래스인 Person

public class Person {
    String name;
    String ssn;

//    public Person(){}


    public Person(String name, String ssn) { //매개변수가 있는 생성자를 생성 시 디폴트 생성자로 호출 불가
        this.name = name;
        this.ssn = ssn;
    }
}

 

 

자식 클래스인 Student

public class Student extends Person{
    int studentNo;

    /* 부모클래스에 만약 생성자가 없다면
    Student(){
        super(); // super 맨첫줄에 선언해야한다.
    }
     */

    public Student(String name, String ssn, int studentNo) { //매개변수를 생성함으로서 디폴트 생성자는 x
        super(name, ssn);
        //원래 부모클래스의 디폴트 생성자를 호출해야하는데
        // 부모클래스에 존재 x 그리하여 매개변수가 있는 생성자를 호출해야한다.
        this.studentNo = studentNo;
    }
}

 

실행하기 위해 StudentExample!

public class StudentExample{
    public static void main(String[] args) {
        Student student = new Student("길동", "123456-1234567", 1);
//      Person person = new Student();
        System.out.println("name: " + student.name);    // 부모에게서 물려받은 필드 출력
        System.out.println("ssn: " + student.ssn);     // 부모에게서 물려받은 필드 출력
        System.out.println("studentNo: " + student.studentNo);
    }
}

 

작성하였을 때, 

 

자식클래스인 Student 에서 

 

super(name, ssn);

 

를 주석처리해주면? 컴파일 오류가생긴다.

 

super(name, ssn);을 주석처리하게 되면

 

부모클래스에서 기본 생성자를 호출할려고 할텐데

 

현재 부모클래스에는 기본생성자자가 없으므로 컴파일오류가 생긴다!

 

여기서 

 

public class Person {
    String name;
    String ssn;

    public Person(){}


    public Person(String name, String ssn) { //매개변수가 있는 생성자를 생성 시 디폴트 생성자로 호출 불가
        this.name = name;
        this.ssn = ssn;
    }
}

 

이렇게 부모 클래스에서 public Person(){} 기본 생성자를 넣어주면? 

 

컴파일 오류가 없어진다. 

 

 

 

즉, 부모클래스에서 매개변수가 있는 생성자를 생성했을 시, 

 

자식클래스에서는 부모클래스의 기본생성자인 super()를 호출해야하는데

 

매개변수가 있는 생성자만 있고 부모클래스에 기본생성자가 존재하지 않으면 

 

매개변수가 존재하는 super(name, ssn);을 호출해야한다. 

 

super(name, ssn);

 

이렇게! 상속에 대해 공부하였는데용 ㅎㅎ

 

되게,,, 복잡하긴한데 나름 

 

재밌었어요!! 제가 100% 정확하게 이해한건 아닌거같긴한데 

 

 

제가 이해한게 맞겠죠>!? ㅋㅋㅋㅎㅎㅎㅎ 

 

+ 만약 누군가 전문가가 보신다면 틀렸다면 댓글로 알려주시길.. ㅎㅋㅋㅋ 

 

아직 메소드와 생성자가 조금 헷갈리지만

 

확실히 어제보다는 성장했다는 느낌을 받습니다 ㅋㅋㅋㅎ!!!

 

 

 

자바의정석 기초편으로 공부하고 유튜브 참고하니 

 

조금 개념에 대해서는 더 알아간 거같아요 ㅎㅎ

 

 

수업 뿐만 아니라 이해가 조금 안되는 부분은

 

 

영상 시청과 책이 도움이 된다는 걸 알아버렸어요!!! ㅋㅋㅎㅎㅎ

 

 

그리하여 수업 듣고 복습하고 자바의 정석으로 오늘 배운내용 다시 살펴보는 식으로 할려고합니다!!!!

 

 

 

다음주 부터는 , 제가 3월 9일에 SQLD 개발자 자격증을 접수해놔서 

 

그것도 조금씩 준비해보려고 합니다!!!!  

 

 

오늘도 열심히 공부했고!!!!!!!

 

 

내일도 파이팅 합시당!!!!!