자바 8일차

김재현·2022년 8월 7일
0

Java

목록 보기
9/15

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

  • 클래스를 재사용하는 방법 2.
    클래스 간에 '포함(composite)'관계를 맺어주는 것이다. 클래스 간 포함관계를 맺어주는 것은 한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것을 말한다.

  • 원을 표현하기 위한 클래스 Circle과 한 점을 다루기 위한 Point 클래스.

  • Point 클래스를 재사용해서 아래와 같이 만들 수 있다.

  • 한 클래스를 작성하는데 다른 클래스를 멤버변수로 선언하여 포함시키는 것은 좋은 생각이다.
  • 하나의 거대 클래스를 작성하는 것보다 단위별로 여러 개 클래스를 작성한 다음, 이 단위 클래스들을 포함관계로 재사용하면 보다 간결하고 손쉽게 클래스를 작성할 수 있다.
  • 또한 작성된 단위 클래스들은 다른 클래스를 작성하는데 재사용될 수 있다.

클래스 간의 관계 결정하기

  • 때로 상속관계로 할지, 포함관계로 할지 결정하는 것은 혼돈스러울 수 있다.
    이 때는 '~은 ~이다.(is-a)'와 '~은 ~을 가지고 있다.(has-a)'를 넣어서 문장을 만들어보면 클래스 간의 관계가 보다 명확해진다.

    원(Circle)은 점(Point)이다. - Circle is a Point.
    원(Circle)은 점(Point)을 가지고 있다. - Circle has a Point.

  • 클래스를 가지고 문장을 만들었을 때 '~은 ~이다.'라는 문장이 성립한다면, 서로 상속관계를 맺어주고, '~은 ~을 가지고 있다.'는 문장이 성립된다면 포함관계를 맺으면 된다.
    위의 경우는 상속관계보다 포함관계를 맺어주는 것이 더 옳다.

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

단일 상속

  • 자바에서는 단일 상속만을 허용한다. 때문에 둘 이상의 클래스로부터 상속을 받을 수 없다.
  • 다중상속을 허용하면 여러 클래스로부터 상속받을 수 있기 때문에 복합적인 기능을 가진 클래스를 쉽게 작성할 수 있다는 장점이 있지만, 클래스간의 관계가 매우 복잡해진다는 것과 서로 다른 클래스로부터 상속받은 멤버간의 이름이 같은 경우 구별할 수 있는 방법이 없다는 단점을 갖고 있다.
  • 단일 상속은 하나의 부모 클래스만을 가질 수 있기 때문에 다중상속에 비해 불편한 점도 있지만, 클래스 간의 관계가 보다 명확해지고 코드를 더욱 신뢰할 수 있게 만들어준다는 점에서 다중상속보다 유리하다.

Object클래스 - 모든 클래스의 부모

  • 모든 클래스 상속 계층도의 최상위에 있는 부모클래스.
  • 다른 클래스로부터 상속받지 않는 모든 클래스들은 자동적으로 Object클래스로부터 상속받게 함.
  • 모든 상속계층도의 최상위에는 Object 클래스가 위치하고, 자바의 모든 클래스들은 Object클래스의 멤버들을 상속받기 때문에 Object클래스에 정의된 멤버들을 사용할 수 있다. 대표적으로 toString()equals(Object o)등이 있다.

오버라이딩(overriding)

  • 부모클래스로부터 상속받은 메서드의 내용을 변경하는 것을 오버라이딩이라 함.
    그래도 사용하기도 하지만, 자신에 맞게 변경해야하는 경우도 많다.
  • 사전적 의미는 '~위에 덮어쓰다(overwrite)'이다.

  • Point 클래스의 getLocation()은 한 점의 x, y 좌표를 문자열로 반환하도록 작성되었다.
  • Point3D클래스는 Point 클래스와 상속관계에 있으므로 Point 클래스로부터 getLocation()을 상속받지만, Point3D 클래스는 3차원 좌표계의 한 점을 표현하기 위한 것이므로 Point클래스의 getLocation()과는 맞지 않는다. 따라서 이 메서드를 Point3D에 맞게 z축 값도 포함해서 반환하도록 오버라이딩 하였다.

오버라이딩의 조건

  • 오버라이딩은 메서드의 내용만을 새로 작성하는 것이므로 메서드의 선언부(메서드의 이름과 매개변수, 반환타입)는 부모의 것과 완전히 일치해야 한다. 다만, 접근 제어자(access modifier)와 예외(exception)는 제한된 조건 하에서 다르게 변경할 수 있다.
  1. 접근 제어자는 부모 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
    만일 부모 클래스에 정의된 메서드의 접근 제어자가 protected라면, 이를 오버라이딩 하는 자식 클래스의 메서드는 접근 제어자가 protected나 public이어야한다. 대부분의 경우 같은 범위의 접근 제어자를 사용한다.
  2. 부모 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.

    부모 클래스의 메서드를 자식 클래스에서 오버라이딩할 때
    1) 선언부가 부모 클래스의 메서드와 일치해야한다.
    2) 접근 제어자를 부모 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
    3) 예외는 부모 클래스의 메서드보다 많이 선언할 수 있다.

오버로딩 vs 오버라이딩

  • 오버로딩은 기존에 없는 새로운 메서드를 추가하는 것.
  • 오버라이딩은 부모에게 상속받은 메서드의 내용을 변경하는 것.

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

참조변수 super

  • super는 자식 클래스에서 조상 클래스로부터 상속받은 멤버를 참조했는데 사용되는 참조변수이다. 멤버변수와 지역변수의 이름이 같은 때 this를 붙여서 구별했듯이 상속받은 멤버와 자신의 멤버와 이름이 같을 때는 this를 붙여 구별할 수 있다.
  • 모든 인스턴스 메서드에는 this와 super가 지역변수로 존재하는데, 이들에는 자신이 속한 인스턴스 주소가 자동으로 저장된다. 조상의 멤버와 자신의 멤버를 구별하는데 사용된다는 점만 제외하면 this와 super은 근본적으로 같다.

  • 셋의 결과는 모두 10으로 같다.

super() - 조상의 생성자

  • this()처럼 super()도 생성자이다.
    this()가 같은 클래스의 다른 생성자를 호출한다면, super()는 조상의 생성자를 호출한다.

패키지(package)

  • 클래스의 묶음.
  • 클래스 또는 인터페이스를 포함시킬 수 있으며, 서로 관련된 클래스들끼리 그룹 단위로 묶음으로써 클래스를 효율적으로 관리할 수 있다.
  • 같은 이름의 클래스일지라도 서로 다른 패키지에 존재하는 것이 가능하므로, 자신만의 패키지 체계를 유지함으로써 다른 개발자가 개발한 클래스 라이브러리의 클래스와 이름이 충돌하는 것을 피할 수 있다.
  • 클래스가 물리적으로 하나의 클래스파일(.class)인 것과 같이 패키지는 물리적으로 하나의 디렉토리이다. 어떤 패키지에 속한 클래스는 해당 디렉토리에 존재하는 클래스파일(클래스이름.class)이어야 한다.

패키지의 선언

  • 클래스나 인터페이스의 소스파일(.java)의 맨 위에 다음과 같이 한 줄만 적어주면 됨.
    package 패키지명
  • 패키지 선언문은 반드시 소스파일에서 주석과 공백을 제외한 첫 번째 문장이어야 하며, 하나의 소스파일에 단 한 번만 선언될 수 있다. 해당 소스파일에 포함된 모든 클래스나 인터페이스는 선언된 패키지에 속하게 된다.
  • 대소문자를 모두 허용하지만, 클래스명과 쉽게 구분하기 위해 소문자로 하는 것을 원칙으로 하고 있다.
  • 자바에서 기본적으로 제공하는 '이름 없는 패키지(unnamed package)' 덕분에 소스파일 작성 시 패키지 선언을 하지 않아도 문제가 발생하지 않는다. 결국 소속 패키지를 지정하지 않은 모든 클래스들은 같은 패키지에 속하는 셈이다.
  • 간단한 프로그램은 패키지를 지정하지 않아도 별 문제 없지만, 큰 프로젝트나 Java API와 같은 클래스 라이브러리를 작성하는 경우에는 미리 패키지를 구성해서 적용해야 한다.

import문

  • 소스코드를 작성할 때 다른 패키지의 클래스를 사용하려면 패키지명이 포함된 클래스 이름을 사용해야 한다. 하지만, 매번 패키지명을 붙여 작성하기란 여간 불편한 일이 아니다.
    클래스의 코드를 작성하기 전에 import문으로 사용하고자 하는 클래스의 패키지를 미리 명시해주면 소스코드에 사용되는 클래스이름에서 패키지명은 생략할 수 있다.
  • import문은 package문 다음에, 그리고 클래스 선언문 이전에 위치해야한다.

    import 패키지명.클래스명;
    또는
    import 패키지명.*;

  • 키워드 import와 패키지명을 생략하고자 하는 클래스의 이름을 패키지명과 함께 써주면 된다.
    '패키지명.*'을 이용해서 지정된 패키지에 속하는 모든 클래스를 패키지명 없이 사용할 수 있다. 실행 시 성능상의 차이는 없다.

static import문

  • static import문을 사용하면 static 멤버를 호출할 때 클래스 이름을 생략할 수 있다. 특정 클래스의 static멤버를 자주 사용할 때 편리하며 코드를 간결화 할 수 있다.

제어자(modifier)

  • 클래스나 변수, 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다. 크게 접근 제어자와 그 외로 나눌 수 있다.

접근 제어자 : public, protected, (default), private
그 외 : static, final, abstract, native, transient, synchronized, volatile, strictfp

  • 제어자는 클래스나 멤버변수와 메서드에 주로 사용되며, 하나의 ㅐ상에 대해서 여러 제어자를 조합하여 사용하는 것이 가능하다.
    단, 접근 제어자는 한가지만 사용할 수 있다.

static - 클래스의, 공통적인

  • '클래스의' 또는 '공통적인'의 의미를 가지고 있다.
    인스턴스 변수는 하나의 클래스로부터 생성되었더라도 각기 다른 값을 유지하지만, 클래스변수(static멤버변수)는 인스턴스에 관계 없이 같은 값을 갖는다. 하나의 변수를 모든 인스턴스가 공유하기 때문이다.
  • static이 붙은 멤버변수와 메서드, 그리고 초기화 블럭은 인스턴스가 아닌 클래스에 관계된 것이기 때문에 인스턴스를 생성하지 않고도 사용할 수 있다.
  • 인스턴스메서드와 static메서드의 근본적인 차이는 메서드 내에서 인스턴스 멤버를 사용하는가의 여부이다.

static이 사용될 수 있는 곳 - 멤버변수, 메서드, 초기화 블럭

  • 인스턴스 멤버를 사용하지 않는 메버드는 static을 붙여 static 메서드로 선언하는 것을 고려하자. static메서드로 선언하는 것은 인스턴스를 생성하지 않기 때문에 더 더 편리하고 속도도 더 빠르다.

final - 마지막의, 변경될 수 없는

  • '마지막의' 또는 '변경될 수 없는'의 의미를 갖고 있으며, 거의 모든 대상에 사용될 수 있다.
    변수에 사용되면 값을 변경할 수 없는 상수가 되며, 메서드에 사용되면 오버라이딩을 할 수 없게 되고, 클래스에 사용되면 자신을 확장하는 자식클래스를 정의하지 못하게 된다.

final이 사용될 수 없는 곳 - 클래스, 메서드, 멤버변수, 지역변수

  • 대표적인 final class로 String과 Math가 있다.

abstract - 추상의, 미완성의

  • '미완성'의 의미를 가지고 있다.
    메서드의 선언부만 작성하고 실제 수행내용은 구현하지 않은 추상 메서드를 선언하는데 사용된다.
    클래스에서는 추상메서드가 존재한다는 것을 쉽게 알 수 있게 한다.

abstact가 사용될 수 있는 곳 - 클래스, 메서드

  • 추상 클래스는 인스턴스를 생성할 수 없다.

접근 제어자 (access modifier)

  • 접근 제어자는 멤버 또는 클래스에 사용하며, 해당하는 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다.
    접근 제어자가 지정되어 있지 않다면, 접근 제어자가 default임을 뜻한다.

접근 제어자가 사용될 수 있는 곳 - 클래스, 멤버변수, 메서드, 생성자.
private - 같은 클래스 내에서만 접근 가능.
(default) - 같은 패키지 내에서만 접근 가능.
protected - 같은 패키지 내에서, 그리고 다른 패키지의 자손 클래스에서 접근이 가능.
public - 접근 제한이 전혀 없다.
접근 범위가 넓은 쪽에서 좁은 순으로 나열해보면

  • public은 접근 제한이 전혀 없는 것, private은 같은 클래스 내에서만 사용하도록 제한하는 가장 높은 제한, default는 같은 패키지 내의 클래스에서만 접근이 가능하도록 하는 것이다.
    protected는 패키지에 관계 없이 상속관계에 있는 자손 클래스에서 접근할 수 있도록 하는 것이 제한목적이지만, 같은 패키지 내에서도 접근 가능하다. 따라서 protected가 default보다 접근범위가 넓다.

0개의 댓글