ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [자바] 객체지향(2) - 1 ( 패키지 )
    자바 2022. 7. 9. 11:54
    728x90

    1. 상속

    - 기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것이다.
    - 자바는 단일 상속만 허용

    - 모든 클래스들에는 Object클래스가 최상위에 위치한다.

     

    클래스간의 관계 - 상속 구현

    class Parent { }
    class Child extends Parent { }
    class Child2 extends Parent { }
    // extends 라는 키워드를 써서 상속을 할 수 있다.

    Child와 Child2간에는 서로 아무런 관계도 성립되지 않는다.

     

     

    멤버 변수, 메소드 상속 코드 예시

    class Parent {
        int age;
    }
    
    class Child extends Parent {
        void play() {
            System.out.println("놀자");
        }
    }
    
    // child class는 age라는 변수도 받는다

     

    상속 계층도

     

    - 생성자와 초기화 블럭은 상속되지 않는다. 멤버만 상속된다.
    - 자손 클래스의 멤버 개수는 조상 클래스보다 항상 같거나 많다.

    - 자손 클래스의 인스턴스를 생성하면 조상 클래스의 멤버와 자손 클래스의 멤버가 합쳐진 하나의 인스턴스로 생성된다.

     

    클래스간의 관계 - 포함 관계

    포함관계는 상속과 마찬가지로 재사용하는 방법 중 하나 이다.

    포함 - 한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것을 뜻한다.

     

    재사용 하는 방법

    // 재사용 안 할때의 코드 변화
    class Circle {
        int x;
        int y;
        int z;
    }
    
    class Point {
        int x;
        int y;
    }
    
    // 재사용 할때의 코드 변화
    class Circle {
        Point c = new Point(); // 원점
        int z;
    }

     

    상속 : is-a ( ~은 ~이다. )
    포함 : has - a ( ~은 ~을 가지고 있다. )

     

    TIP, 인스턴스 생성하는 코드인데, 복잡해 보이는것 이해하기 위한 코드

     

    Circle c = new Circle(new Point(150,150), 50);
    
    --same--
    
    Point p = new Point(150,150);
    Circle c = new Circle(50);

     

     

    2. 오버라이딩

    - 조상 클래스로부터 상속받은 메서드의 내용을 변경하는 것 ex) 2차원 -> 3차원

    class Point {
        int x;
        int y;
        
        String getLocation() {
            return "x" + x + "y" + y
        }
    }
    
    class Point3D extends Point {
        int z;
        
        String getLocation() { // 오버라이딩
            return "x" + x + "y" + y + "z" + z
        }
    }

     

    오버라이딩 조건

    - 이름이 같아야 한다
    - 매개변수가 같아야 한다
    - 반환타입이 같아야 한다.

    => 선언부가 서로 일치해야 한다.

     

    조상 클래스의 메서드를 자손 클래스에서 오버라이딩할때
    1. 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
    2. 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.
    3. 인스턴스 메서드를 static 메서드로 또는 그 반대로 변경할 수 없다.

     

    2번에서 주의 할점

    class Parent {
        void parentMethod() throws IOException, SQLException { 
            ....
        }
    }
    
    // 조상 클래스 보다 작은 수의 예외
    class Child extends Parent {
        void parentMethod() throws IOException { 
            ....
        }
    }
    
    // 예외 수에 대한 조건이 지켜지지 않는 경우
    class Parent {
        void parentMethod() throws Exception { 
            ....
        }
    }

    - 예외 수에 대한 조건이 지켜지지 않은 이유는 Exception는 모든 예외의 최고 조상이므로 가장 많은 개수의 예외를 던질 수 있도록 선언됨

     

    Q. 조상 클래스에 정의된 static 메서드를 자손 클래스에서 똑같은 이름의 static메서드로 정의할 수 있나?

    있다. 하지만, 호출시엔 ' 클래스이름.메서드이름() '으로 해야하고, static 멤버들은 자신들이 정의된 클래스에 묶여있다 생각하기

     

    오버로딩 - 기존에 없는 새로운 메소드를 정의하는 것 ( new )
    오버라이딩 - 상속받은 메소드의 내용을 변경하는 것 ( change, modify )

     

    super

    - super()은 this()와 마찬가지로 생성자다.

       -> 자주 나오는 에러 파트에 나올 수 있는 에러 파트 적었으니 확인! ( 12번 )

    - 조상 클래스로부터 상속받은 멤버를 참조하는데, 멤버변수와 지역변수의 이름이 같을 때 this를 써 구별하듯, 상속받은 멤버와 자신의 멤버와 이름이 같을때, super로 구분 

    조상 클래스의 멤버와 자손클래스의 멤버가 중복 정의되어 서로 구별할때는 super 사용하기

    - super는 static메서드에서는 사용할 수 없고 인스턴스메서드에서만 사용할 수 있다.

     

    예시 - 조상의 메서드 호출

    class Point {
        int x;
        int y;
        
        String getLocation() {
            return "x :" + x + "y : " + y;
        }
    }
    
    class Point3D extends Point {
        int z;
        String getLocation() {
            // 오버라이딩
            // return "x :" + x + "y : " + y + "z : " + z;
            return super.getLocation() + "z : " + z;
        }
    }

     

    첫 줄에 반드시 자신의 다른 생성자 또는 조상의 생성자를 호출하는 예시

    class PointTest {
        public static void main(String[] args) {
            Point3D p3 = new Point3D(1,2,3);
        }
    }
    
    class Point {
        int x,y;
        
        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
        Stirng getLocation() {
            return "x :" + x + "y :" + y;
        }
    }
    
    class Point3D extends Point {
        int z;
        
        /*
        Point3D(int x, int y, int z) {
        	super();
            this.x = x;
            this.y = y;
            this.z = z;
        }
        */
        // or
        Point3D(int x, int y, int z) {
        	super(x,y); // 조상 클래스의 생성자를 호출한다
            this.z = z;
        }
        
        Stirng getLocation() {
            return "x :" + x + "y :" + y;
        }
    }

     

     

    3. 패키지( package )

    패키지란, 클래스의 묶음 ( 클래스 or 인터페이스 포함 )
    예시, java.lang 패키지  -> java.lang.String은  java.lang에 속한 String클래스 라는 의미

     

    - 클래스가 물리적으로 하나의 클래스파일( . class )인 것과 같이 패키즈는 물리적으로 하나의 디렉토리다.

     

    - 하나의 소스파일에는 첫 번째 문장으로 단 한번의 패키지 선언만을 허용한다
    - 모든 클래스는 반드시 하나의 패키지에 속해야 한다
    - 패키지는 점(.)을 구분자로 하여 계층구조 구성할 수 있다.
    - 패키지는 물리적으로 클래스 파일을 포함하는 하나의 디렉토리이다.

     

    패키지의 선언

    package 패키지명;

    패키지는 소문자로 하며, 첫번째 문장에 하나의 소스파일에는 단 한번만 선언할 수 있다.

     

    import문

    import문은 클래스의 패키지를 미리 명시해주면서 클래스이름에서 패키지 명을 생략할 수 있다.

     

    import 선언

    일반적인 소스파일( *.java )의 구성의 순서

    1. package문
    2. import 문
    3. 클래스 선언

     

    선언하는 방법

    import 패키지명.클래스명;
    or
    import 패키지.*;

     

    import 패키지.* 이런식으로 호출하는것이 일일이 지정하는것보다 편리하다.

     

    전후 비교 코드 예시

    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    class ImportTest {
        public static void main(String[] args) {
            Date today = new Date();
            
            SimpleDateFormat data = new SimpleDateFormat("yyyy/MM/dd");
            // java.text.SimpleDateFormat data = new java.text.SimpleDateFormat("yyyy/MM/dd");
            SimpleDateFormat data = new SimpleDateFormat("hh:mm:ss a");
            
            System.out.println(date.format(today));
            System.out.println(time.format(today));
        }
    }

    - java.lang 패키지는 빈번히 사용되서 import문으로 지정하지 않아도 된다.

     

    static import 선언

    import static java.lang.Integer.* // Integer클래스의 모든 static메서드
    import static java.lang.Math.random;   // Math.random()만. 괄호 안붙임
    import static java.lang.System.out;  // out만으로 참조가능
    
    -> System.out.println(Math.random()) 
    -> out.println(random());

     

     

    4. 제어자

    제어자는 클래스, 변수 또는 메서드의 선언부에 사용되어 부가적인 의미를 더한다

     

    static

    static은 클래스의 또는 공통적인 의미를 갖는다. ( 멤버변수, 메서드, 초기화 블록에 사용가능 )

    하나의 변수를 모든 인스턴스가 공유하기에 클래스변수(static 멤버변수)는 인스턴스에 관계없이 같은 값을 갖는다.

    class Static {
        static int w = 200; // 클래스 변수
        
        static { } // 클래스 초기화 블럭
        
        static int max(int a, intb) { } // 클래스 메서드
    }

     

    final

    final 마지막의 또는 변경될 수 없는 을 의미한다. ( 클래스, 메서드, 멤버변수, 지역변수 )
    변수에 사용하면, 변경할 수 없는 상수가 되고,
    메서드에 사용되면 오버라이딩을 할 수 없게 되고,
    클래스에 사용되면 자신을 확장하는 자손클래스를 정의하지 못하게 된다
    final class Final { // 조상이 될 수 없는 클래스 
        final int MAX_SIZE = 200; // 상수 ( 멤버변수 )
        
        final void getMaxSize() { // 오버라이딩을 할 수없는 메서드
            final int LV = MAX_SIZE; // 상수( 지역변수 )
            return MAX_SIZE;
        }
    }

     

    final이 붙은 벼수는 일반적으로 선언과 동시에 초기화 하지만, 인스턴스벼수는 생성자에게 초기화 되도록 할 수 있다.

    class Card {
        final int NUMBRE;
        final String KIND;
        static int w = 100;
        static int h = 100;
        
        Card(String kind, int num) {
        // 이 부분이 생성자에 의해서 final이 붙은 변수를 초기화 하는 것이다.
            KIND = kind;
            NUMBER = num;
        }
        
        Card() {
            this KIND + " " + NUMBER;
        }
        
        public String toString() {
        	return KIND + " " + NUMBER;
        }
    }
    
    class FinalCard {
        public static void main(String[] args) {
            Card c = new Card("HEART", 10);
            c.NUMBER = 5; // 에러, cannot assign a value to final variable NUMBER
            System.out.println(c.KIND); // 이렇게 해야함
        }
    }

     

    abstract

    abstract은 미완성의 의미를 갖는다 . 메서드의 선언부만 작성하고 수행내용은 구현하지 않은 추상 메서드를 선언하는데 사용 ( 클래스, 메서드 )
    abstract class AbstractTest {
        abstract void move();
    }

     

    접근 제어자

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

    - 외부로부터 데이터 보호
    - 외부에는 불필요한, 내부적으로만 사용되는 부분을 감추기 위해

    만일 메서드 하나를 변경해야 할때, 접근제어자를 적절히 선택해서 접근 범위를 최소화하도록 노력하자 ( public이면 전부를 봐야함 )

    제어자 같은 클래스 같은 패키지 자손클래스 전체
    public  O O O O
    protected O O O X
    default O O X X
    private O X X X

     

    생성자의 접근 제어자

    보통 생정자의 접근 제어자는 클래스의 접근제어자와 같지만, 다르게 지정할 수 있다.

     

    private이니 외부에서 접근할 수 없어서, 인스턴스를 만들 수 없다.

    하지만, 클래스 내부에서는 인스턴스 생성 가능

    -> 클래스 내부 메서드가 public 이면서 static 이여야 외부에서 이 클래스 인스턴스를 사용할 수 있다.

     

    private인 클래스는 다른 클래스의 조상이 될 수 없다.

    이유는, 생성자의 접근 클래스가 private이므로 자손클래스에서 호출하는 것이 불가능하기 때문이다

    따라서 private 클래스 앞에 final을 더 추가하여 상속할 수 없는 클래스라는것을 알리기

     

    제어자의 조합

    1. 메서드에 static과 abstract를 함께 사용할 수 없다.
    2. 클래스에 abstract와 final을 동시에 사용할 수 없다.
    3. abstract메서드의 접근 제어자가 priate일 수 없다.
    4. 매서드에 private과 final을 같이 사용할 필요가 없다.

    '자바' 카테고리의 다른 글

    [자바] 예외처리  (0) 2022.07.13
    [자바] 객체지향(2) - 2  (0) 2022.07.13
    [자바] 객체지향(1)  (0) 2022.07.07
    [자바] 배열의 활용  (0) 2022.07.01
    [자바] 배열  (0) 2022.06.28
Designed by Tistory.