천천히 빛나는

Java 기초 : 접근 제어자 & Abstract & final 본문

JAVA/JAVA

Java 기초 : 접근 제어자 & Abstract & final

까만콩 •ᴥ• 2024. 1. 16. 23:49

 

접근 제어자

class A{
    public String y(){
        return "public void y()";
    }

    private String z(){
        return "private void z()";
    }

    public String x(){
        return z();
    }
}

public class AccessDemo1 {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a.y());
        System.out.println(a.z()); // 호출불가
        System.out.println(a.x());
    }
}

접근 제어자는 클래스의 멤버(변수와 메소드)들의 접근 권한을 지정한다. 객체를 보호하기 위해서 외부의 접근을 허용하거나 차단해야할 필요가 생기게 되는데 접근 제어자를 통해 이를 통제할 수 있게 된다. private은 클래스 안에서는 접근이 가능하지만 외부에서는 접근이 불가능하다.

 

Checker.java와 Same.java는 같은 패키지에 소속되어있으며 Other.java와는 다른 패키지이다. 

Other.java과 Same.java는 private, default, protected, public 타입의 메소드를 가진 class가 구현되어있다.

 

Checker.java는 3개의 클래스를 가지고 있다. (SameClassChecker, SamePackageChecker, OtherPackageChecker)

SameClassChecker은 같은 클래스 안에서 자신의 메소드를 호출하게 된다. 여기서 모든 메소드는 타입에 관계없이 접근이 가능하다.

Same class를 상속받고 있는 SamePackageChecker class는 Same class의 public, protected, default에 접근이 가능하다.

Other class를 상속받고 있는 OtherPackageChecker class는 Other class의 public과 protected에 접근이 가능하다. 상속을 받지 않는다면 public에만 접근이 가능하다. default는 다른 패키지에 존재하면 상속과 관계없이 무조건 호출이 불가능하다.

public은 무조건 다 접근 가능하다. private은 같은 클래스에서만 가능하다.

protected와 default는 같은 패키지일 때만 접근이 가능하다. 하지만 protected는 다른 패키지여도 상속 관계라면 접근이 가능하다.

  public protected default private
같은 패키지, 같은 클래스 허용 허용 허용 허용
같은 패키지, 상속 관계 허용 허용 허용 불용
같은 패키지, 상속 관계 아님 허용 허용 허용 불용
다른 패키지, 상속 관계 허용 허용 불용 불용
다른 패키지, 상속 관계 아님 허용 불용 불용 불용

 

 

 

클래스의 접근 제어자

클래스의 접근 제어자는 public과 default 뿐이다. 접근 제어자가 public이면 다른 패키지의 클래스에서도 사용가능하지만 default는 같은 패키지에서만 사용 가능하다. impot로 다른 패키지를 load 하더라도 default는 호출이 불가능하다. 

package org.opentutorials.javatutorials.accessmodifier.outter;
import org.opentutorials.javatutorials.accessmodifier.inner.*;
public class ClassAccessModifierOuterPackage {
    PublicClass publicClass = new PublicClass();
    //DefaultClass defaultClass = new DefaultClass();
}

 

또한 public 클래스가 포함된 소소코드는 public 클래스의 클래스 명과 소스코드의 파일명이 같아야 한다. 즉 하나의 소스파일에는 하나의 public 클래스만 존재할 수 있다.

package org.opentutorials.javatutorials.accessmodifier.inner;
//public class PublicName {}
public class PublicNameDemo {}

PublicNameDemo.java라는 파일에서 PublicName이라는 public class를 만들 수 없다.

 

 

 

Abstract (추상 클래스, 추상 메소드)

abstract class A{
    public abstract int b(); // 추상메소드 (본체 없음)
    //본체가 있는 메소드는 abstract 키워드를 가질 수 없다.
    //public abstract int c(){System.out.println("Hello")}
    //추상 클래스 내에는 추상 메소드가 아닌 메소드가 존재 할 수 있다. 
    public void d(){
        System.out.println("world");
    }
}

public class AbstractDemo {
    public static void main(String[] args) {
        A obj = new A(); // 불가능!
    }
}

abstract class는 무조건 상속을 해야하하는 class이다. 추상 클래스 내에는 추상 메소드가 아닌 일반 메소드가 존재해도 괜찮다. abstract 키워드를 가진 메소드는 본체가 존재하면 안된다. abstact 메소드를 사용하기 위해서는 반드시 오버라이딩을 해서 사용을 해야 한다. 

메소드 중 하나라도 추상 메소드라면 그 메소드를 가지고 있는 클래스는 무조건 추상 클래스가 된다. 

 

class B extends A{
    public int b(){return 1;}
}

이와 같이 추상 메소드는 오버라이딩이 되어야 하며 추상 클래스는 객체를 만들 수 없으며 상속에 사용된다.

 

 

abstract class Calculator{
    int left, right;
    public void setOprands(int left, int right){
        this.left = left;
        this.right = right;
    } 
    public abstract void sum();  
    public abstract void avg();
    public void run(){
        sum();
        avg();
    }
}
class CalculatorDecoPlus extends Calculator {
    public void sum(){
        System.out.println("+ sum :"+(this.left+this.right));
    }
    public void avg(){
        System.out.println("+ avg :"+(this.left+this.right)/2);
    }
} 
class CalculatorDecoMinus extends Calculator {
    public void sum(){
        System.out.println("- sum :"+(this.left+this.right));
    }
    public void avg(){
        System.out.println("- avg :"+(this.left+this.right)/2);
    }
} 
public class CalculatorDemo {
    public static void main(String[] args) { 
        CalculatorDecoPlus c1 = new CalculatorDecoPlus();
        c1.setOprands(10, 20);
        c1.run();
         
        CalculatorDecoMinus c2 = new CalculatorDecoMinus();
        c2.setOprands(10, 20);
        c2.run();
    }
   
}

추상 클래스 Calculator에 추상 메소드 sum()과 avg()가 존재한다. 여기서 sum()과 avg()는 사용자에 따라 다르게 구현되어야 하는 부분이라서 추상메소드가 되었다. run()는 무조건 sum()과 avg()를 실행하는 함수이다. 

 

 

 

final (상속, 변경 금지)

추상이 상속을 강제하는 것이라면 final은 상속/변경을 금지하는 규제이다.

 

final 필드 (= final 변수)

static final double PI = 3.14;

같은 클래스 내에서도, 같은 패키지 내에서도 모두 변경이 불가능하다. 

 

final 메소드

class A{
    final void b(){}
}
class B extends A{
    void b(){} // 불가능
}

class B에서 오버라이딩이 불가능하다.

 

final 클래스

final class C { // final 클래스
    final void b(){}
}
class D extends C{} // 상속 불가

final class C는 상속이 불가능하다.