1. 패키지 (package)

  • 하나의 소스 파일에는 첫 번째 문장으로 단 하나의 패키지 선언만 허용한다.
  • 모든 클래스는 반드시 하나의 패키지에 속해야 한다.
  • 패키지는 점(.)을 구분자로 하여 계층 구조로 구성된다.
  • 패키지는 물리적인 클래스 파일(.class)을 포함하는 하나의 디렉터리이다.
  • 같은 이름의 클래스가 다른 패키지에 있을 수 있다.
// 디렉토리 : com/company/sample
package com.company.sample;

class Sample {}

1.1. 패키지 선언

package com.company.sample; // 패키지 선언
  • 주석과 공백을 제외한 가장 첫 번째 라인에 선언한다.
  • 하나의 소스 파일에 단 한 번만 선언 가능하다.
  • 선언된 패키지안에 해당 클래스가 속해야 한다.
  • 패키지 명은 대소문자 구분이 되지만 클래스와 구분을 하기 위해 소문자로 하는 것을 원칙으로 한다.
  • 자바에서 기본적으로 '이름 없는 패키지(unnamed package)가 있어 패키지를 선언하지 않고도 문제없이 사용할 수 있다.

2. import 문

  • 다른 패키지의 클래스를 사용하려면 패키 지명 + 클래스 이름을 사용해야 한다. 이런 점이 불편하여 import를 통해 미리 선언할 수 있다.
  • 컴파일러는 import문을 보고 각 클래스 명 앞에 패키지 명을 붙인다.
  • 같은 패키지 내의 클래스 들은 import문을 저장하지 않고 패키지 명 생략 가능하다.
package com.company.sample;

import java.util.Scanner; // Sacnner 선언
import java.util.StringTokenizer; // StringTokenizer 선언

class Sample {
    main() {
        // 패키지명 + 클래스 이름
        // 이런 부분이 불편하여 import로 미리 선언
        java.util.Scanner sc = new java.util.Scanner(System.in); 
    }
}

2.1. import 선언문

import java.util.Scanner;
import java.util.*; // 패키지 하위 클래스 전부 미리 선언

'*'는 하위 패키지의 클래스까지 포함하는 것이 아니다.

 

java.lang은 묵시적으로 모든 소스파일에 선언되어 있어 언제든지 사용 가능하다.

2.2. static import 문

static 멤버로 호출할 때 클래스 명을 생략할 수 있다.

import static java.lang.Integer;
import static java.lang.Math.random;
import static java.lang.System.ou;

System.out.println(Math.random());

System.out.println(random()); // 클래스 명 생략

'개발 언어 > Java' 카테고리의 다른 글

[Java] 다형성  (0) 2021.08.25
[Java] 제어자  (0) 2021.08.25
[Java] 상속  (0) 2021.08.24
[Java] 변수의 초기화  (0) 2021.08.24
[Java] 생성자  (0) 2021.08.24

상속

상속이란?

말 그대로 부모에게 물려받는다는 뜻이다. 상위 클래스의 멤버를 하위 클래스가 모두 사용할 수 있으며 기존의 클래스를 재사용하여 새로운 클래스를 만드는 것을 말한다.

1. 상속의 정의와 장점

1.1. 정의

'extends' 키워드를 이용하여 상속을 받는다. 

class Child extends Parent {}

1.2. 장점

  1. 적은 양의 코드로 새로운 클래스를 생성할 수 있다.
  2. 코드를 공통으로 관리하기 때문에 추가 및 변경이 용이하다.
  3. 코드의 중복을 제거하고 재사용성을 높이고 생산성과 유지보수에 크게 기여한다.

* 용어

Parent : 조상 클래스, 부모 클래스, 상위 클래스, 기반 클래스

Child : 자식 클래스, 하위 클래스, 파생 클래스

2. 상속 관계도 (상속 계층도)

 

class Child extends Parent {}
  • Child 클래스는 Parent 클래스의 멤버 들을 모두 포함하고 있다.
  • Parent 클래스에 age라는 변수를 추가 하면 Child 클래스도 자동으로 age라는 변수를 추가하는 것과 같은 효과가 있다.
  • 위와 반대로 Child 클래스에 play() 메서드를 추가하면 Parent 클래스에는 영향이 없다.
  • Parent 클래스를 확장한다고 표현한다.
  • 생성자와 초기화 블럭은 상속되지 않고 멤버(변수, 클래스)만 상속된다.
  • Child 클래스는 Parent 클래스보다 멤버의 개수가 같거나 많다.

* 중요

접근 제어자가 private 또는 default인 멤버는 상속이 되지만 Child 클래스에서 접근이 제한된다.

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

멤버 변수로 다른 클래스 인스턴스를 생성하여 포함관계를 맺는다.

class Circle {
    Point p = new Point(); // 포함
    int r;
}

class Point {
    int x;
    int y;
}

4. 클래스 간의 관계 결정하기

상속 관계 : ~은 ~이다. (is ~ a)

포함 관계 : ~은 ~을 가지고 있다. (has ~ a)

// 상속 관계
class SportsCar extends Car {}

// 포함 관계
class Circle {
    Point p = new Point();
}
  • 가능한 많은 관계를 맺어주어 코드의 재사용성을 높여야 한다.
  • Child, Parent의 이름이 같은 메서드는 Child 메서드가 실행되며, 이것을 '오버라이딩'이라고 한다.
  • 참조 변수를 출력하면 참조 변수가 가리키고 있는 인스턴스의 toString을 호출하여 출력한다.
    모든 클래스의 최상위인 Object클래스에 정의된 toString()을 호출하는 것이 가능하다.
    ex) Card c = new Card();
    System.out.println(c); === System.out.println(c.toString); 두 개의 예제는 동일하다.

5. 단일 상속 (single inheritance)

단일 상속은 하위 클래스가 상위 클래스를 한 개만 상속받을 수 있다는 뜻이다.

여러 개의 클래스로부터 상속받을 수 없으며 여러 상위 클래스의 멤버 이름이 겹치면 구분 방법이 없기 때문이다.

해결 방안으로는 TV 클래스를 상속받고 VCR 클래스를 포함시킬 수 있다.

// 상속과 포함
class TVCR extends TV {
    VCR vcr = new VCR();
}

// 여러 상위 클래스 상속 불가
class TVCR extends TV, VCR {
    ...
}

6. Object 클래스 - 모든 클래스의 조상

다른 클래스로부터 상속받지 않는 클래스들은 모두 자동으로 Object 클래스를 상속받는다. 컴파일러가 추가해준다.

상속 클래스가 있더라도 상위로 계속 올라가면 최상위에는 Object 클래스를 상속받는다.

상속 계층도에서도 Object가 생략되는 경우가 많다.

7. 오버라이딩 (Overriding)

오버라이딩이란?

상속받은 메서드의 내용을 변경하는 것이 오버라이딩이다.

class Parent {
    public int get() {}
}

class Child extends Parent {
    public int get() {} // 오버라이딩
}

Parent 클래스의 get메서드와 비슷한 기능을 기대할 수 있어 오버라이딩을 사용한다.

7.1. 오버라이딩의 조건

  1. 하위 클래스와 상위 클래스의 메서드 명이 같아야 한다.
  2. 하위 클래스와 상위 클래스의 메서드 매개변수가 같아야 한다.
  3. 하위 클래스와 상위 클래스의 메서드 반환 타입이 같아야 한다.

7.2. 제한된 조건하에 변경 가능한 것

  1. 접근 제어자는 상위 클래스의 메서드 보다 좁은 범위로 변경 불가능하지만 넓은 범위로 변경 가능하다.
    범위 순서 : public > protected > default > private
  2. 상위 클래스의 메서드 보다 많은 예외를 선언할 수 없다.
    상위 메서드 : public int get() throws IOException, SQL.... {}
    하위 메서드 : public int get() throws IOException {}

7.3. 오버라이딩의 제한

  1. 접근 제어자를 상위 클래스의 메서드 보다 좁은 범위로 변경 불가능하다.
  2. 예외는 상위 클래스의 메서드 보다 많이 선언 불가능하다.
  3. 인스턴스 메서드를 static 메서드로, static 메서드를 인스턴스 메서드로 변경 불가능하다.

* 중요

상위 클래스에 정의된 static 메서드를 하위 클래스에 똑같은 선어부로 정의 가능하다. 이것은 오버라이딩이 아닌 각 클래스의 static 메서드이다.

8. Super

  • 상위 클래스의 멤버를 참조하는 참조 변수이다.
  • 인스턴스 메서드에서만 사용 가능하다.
  • 상위, 하위 클래스의 멤버가 같아 혼동이 올 때 사용하는 것이 좋다.
  • 상위 클래스의 멤버도 this를 이용해 사용할 수 있다.
  • 오버라이딩 된 메서드에서 상위 메서드 호출시 사용한다.
  • 오버라이딩 된 메서드에서 상위 메서드를 포함시키는 것이 좋다.
    - 추후 업데이트가 돼도 동작하기 때문
    - 상위 메서드에서 추가 작업이 필요할 경우
class Parent {
    public String name;
    
    public int get() {}
}

class Child {
    Child() {
        super(); // 상위 클래스 생성자 호출
        super.name; // 상위 클래스 멤버 변수
        super.get(); // 상위 클래스 메서드 호출
        
    }
    public int get() {]
}

9. Super() - 상위 클래스의 생성자

  • this()와 마찬가지로 생성자이다.
  • 상위 클래스의 멤버 변수도 초기화가 필요하여 사용한다.
  • Object 클래스를 제외하고는 모두 생성자를 첫 줄에 정의한다.
  • 생성자 첫줄에 상위 클래스의 생성자인 super나 자기 자신의 생성자 this가 없으면 컴파일러가 자동으로 추가한다.
  • 상위 클래스의 멤버 변수는 상위 클래스의 생성자를 통해 초기화가 필요하다.
class Parent {
    public String name;
    
    Parent(String name) {
        this.name = name;
    }
    
    public int get() {}
}

class Child {
    Child() {
        super("홍길동"); // 상위 클래스 생성자 호출        
    }
    
    public int get() {]
}

'개발 언어 > Java' 카테고리의 다른 글

[Java] 제어자  (0) 2021.08.25
[Java] Package와 import  (0) 2021.08.24
[Java] 변수의 초기화  (0) 2021.08.24
[Java] 생성자  (0) 2021.08.24
[Java] 오버로딩과 오버라이딩  (0) 2021.08.24

1. 변수의 초기화

  • 변수를 선언하고 처음으로 값을 저장하는 행위를 일컫는 말이다.
  • 선언과 동시에 초기화하는 것이 적절한 초기화이다.
  • 멤버 변수는 자료형에 기본값으로 자동 초기화되면 바로 사용 가능하다.
  • 지역 변수는 반드시 초기화해야 사용할 수 있다.

2. 명시적 초기화 (explicit initialization)

명시적 초기화 : 변수 선언과 동시에 초기화하는 것이다.

명시적 초기화는 가장 우선적으로 고려되어야 하며 가장 간단한 초기화 방법이다.

int a = 5;
Sample sm = new Sample();

3. 초기화 블록(initialization block)

초기화 블록은 두 가지 종류가 있다. 인스턴스 초기화 블록과 클래스 초기화 블록이 있다.

초기화 블록 안에는 메서드와 같이 조건문, 반복문, 예외 처리 등의 작업을 할 수 있다.

class Sample {
    private int a;
    private static int b;
    private int c;
    
    // 인스턴스 초기화
    {
    	this.a = 0;
    }
    
    // 클래스 초기화
    static {
    	Sample.b = 0;
    }
    
}
  • 인스턴스 블록은 모든 생성자에 공통 코드로 넣는 데 사용한다.
  • 생성자 보다 인스턴스 초기화 블록이 먼저 수행된다.
  • 클래스 초기화 블록은 클래스가 메모리에 처음 로딩될 때 한 번만 수행된다.

4. 멤버 변수의 초기화 시기와 순서

4.1. 시점

클래스 변수의 초기화 : 클래스가 처음 로딩될 때 단 한번 실행된다.

인스턴스 변수의 초기화 : 인스턴스가 생성될 때마다 각 인스턴스 별로 생성된다.

4.2. 순서

클래스 변수의 초기화 : 기본 값 -> 명시적 초기화 -> 클래스 초기화 블록

인스턴스 변수의 초기화 : 기본 값 -> 명시적 초기화 -> 인스턴스 초기화 블록 -> 생성자

class Sample {

    private int a;
    private int b;
    private int c;
    
    {
      System.out.println("인스턴스 초기화 블록");      
    }
    
    static {
        System.out.println("클래스 초기화 블록");
    }
    
    Sample() {
      System.out.println("인스턴스 생성");
    }
}

// 결과
// 클래스 초기화 블록
// 인스턴스 초기화 블록
// 인스턴스 생성

'개발 언어 > Java' 카테고리의 다른 글

[Java] Package와 import  (0) 2021.08.24
[Java] 상속  (0) 2021.08.24
[Java] 생성자  (0) 2021.08.24
[Java] 오버로딩과 오버라이딩  (0) 2021.08.24
[Java] 클래스와 객체  (0) 2021.08.20

생성자

생성자란?

인스턴스 생성 시 호출되는 "인스턴스 초기화 메서드"이다

1. 생성자의 조건

  1. 생성자의 이름과 클래스의 이름이 같아야 한다.
  2. 생성자는 리턴 값이 없다.
public Sample {

    Sample() { // 생성자
        ...
    }
}

1.1. 생성자의 특성

  1. 생성자도 오버로딩이 가능하다.
  2. 인스턴스 생성은 "new"가 생성한다.
  3. 생성자는 인스턴스 변수들을 초기화에 사용되는 메서드이다.

1.2. 인스턴스 생성 수행 과정

  1. 연산자 new에 의해서 메모리(heap)에 클래스의 인스턴스가 생성된다.
  2. 생성자 클래스()를 호출되어 수행한다.
  3. 연산자 new의 결과로 생성된 클래스 인스턴스의 주소가 반환되어 참조 변수에 저장된다.

인스턴스 생성 시 클래스 내에 선언되어 있는 생성자 중 하나를 선택해야 한다.

class Sample {
   private int a;
   private int b;
   private int c;

   Sample() {
       this(0, 0, 0);
   }

   Sample(int a, int b, int c) {
       this.a = a;
       this.b = b;
       this.c = c;
   }
}

Sample sm = new Sample(); // new를 이용한 인스턴스 생성

Sample sm = new Sample(1, 2, 3); // 생성자 중 매개변수 있는 생성자 선택

2. 기본 생성자

클래스 내에 생성자가 없으면 컴파일러가 자동으로 기본 생성자를 추가하여 컴파일한다.

// 컴파일 전
class Sample {

}

// 컴파일 후
class Sample {
    Sample() {}
}

3. 생성자에서 다른 생성자 호출하기 - this(), this

  • 생성자에서 인스턴스 변수 앞에 this를 붙여 사용한다. 그 이유는 매개변수와 혼동이 올 수 있기 때문이다.
  • this는 참조 변수로 인스턴스 자기 자신을 가리킨다. ex) Sample sm = new Sample(); 의 sm과 this가 같다.
  • static 메서드에서는 this 사용 불가능하다.

* this

  • 인스턴스 자신을 가리키는 참조 변수이다.
  • 인스턴스의 주소가 저장되어 있다.
  • 모든 인스턴스 메서드에 지역변수로 숨겨져 있다.

* this()

  • 생성자 말한다.
  • 같은 클래스의 다른 생성자를 호출 시 사용한다.

3.1. 생성자의 이름으로 클래스 이름 대신 this를 사용

class Sample {
   private int a;
   private int b;
   private int c;

   Sample() {
       this(0, 0, 0);
   }

   Sample(int a, int b, int c) {
       this.a = a;
       this.b = b;
       this.c = c;
   }
}

3.2. 한 생성자에서 다른 생성자를 호출할 때 반드시 첫 줄에서만 호출 가능

class Sample {
   private int a;
   private int b;
   private int c;

   // 예시 1
   Sample() {
       this(0, 0, 0);
   }

   // 예시 2
   Sample() {
       this.a = 0;
       this(0, 0, 0); // 에러
   }

   Sample(int a, int b, int c) {
       this.a = a;
       this.b = b;
       this.c = c;
   }
}

예시 2번의 이유는 생성자끼리의 호출 이전에 하는 초기화 작업이 무의미 해지기 때문에 에러가 발생하는 것이다.

'개발 언어 > Java' 카테고리의 다른 글

[Java] 상속  (0) 2021.08.24
[Java] 변수의 초기화  (0) 2021.08.24
[Java] 오버로딩과 오버라이딩  (0) 2021.08.24
[Java] 클래스와 객체  (0) 2021.08.20
[Java] 객체 지향 프로그래밍  (0) 2021.08.20

+ Recent posts