제어자(modifier)는 클래스, 변수 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다.

제어자의 종류는 크게 접근제어자와 그 외의 제어자로 나눌 수 있다.

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

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

단, 접근제어자는 네 가지 중 하나만 선택해서 사용할 수 있다.

제어자들 간의 순서는 관계없지만 주로 접근 제어자를 제일 왼쪽에 놓는 경향이 있다.

 

static - 클래스의, 공통적인

static은 클래스의 또는 공통적인 의미를 가지고 있다. 인스턴스 변수는 하나의 클래스로부터 생성되었더라도 각기 다른 값을 유지하지만 클래스 변수(static멤버 변수)는 인스턴스에 관계없이 같은 값을 가진다.

하나의 변수를 모든 인스턴스가 공유하기 때문이다.

 static이 붙은 변수와 메서드, 그리고 초기화 블록은 인스턴스가 아닌 클래스에 관계된 것이기 때문에 인스턴스를 생성하지 않고도 사용할 수 있다.

인스턴스 메서드와 static메서드의 근본적인 차이는 메서드 내에서 인스턴스 멤버를 사용하는가의 여부에 있다.

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

 

제어자 대상 의미
static 멤버변수 - 모든 인스턴스에 공통적으로 사용되는 클래스변수가 된다.
- 클래스변수는 인스턴스를 생성하지 않고도 사용 가능하다.
- 클래스가 메모리에 로드될 때 생성된다.
메서드 - 인스턴스를 생성하지 않고도 호출이 가능한 static 메서드가 된다.
- static메서드 내에서는 인스턴스멤버들을 직접 사용할 수 없다.

 

인스턴스 멤버를 사용하지 않는 메서드는 static을 붙여서 static메서드로 선언하는 것을 고려해보도록 하자.

가능하다면 static메서드로 하는 것이 인스턴스를 생성하지 않고도 호출이 가능해서 더 편리하고 속도도 더 빠르다.

static초기화 블록은 클래스가 메모리에 로드될 때 단 한 번만 수행되며, 주로 클래스 변수(static변수)를 초기화하는데 주로 사용된다.

 

 

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

final은 마지막의 또는 변경될 수 없는의 의미를 가지고 있으며 거의 모든 대상에 사용될 수 있다.

변수에 사용되면 값을 변경할 수 없는 상소가 되며, 메서드에 사용되면 오버 라이딩을 할 수 없게 되고 클래스에 사용되면 자신을 확장하는 자손 클래스를 정의하지 못하게 된다.

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

 

제어자 대상 의미
final 클래스 변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다.
그래서 final로 지정된 클래스는 다른 클래스의 조상이 될 수 없다.
메서드 변경될 수 없는 메서드. final로 지정된 메서드는 오버라이딩을 통해 재정의 될 수 없다.
멤버변수 변수 앞에 final이 붙으면, 값을 변경할 수 없는 상수가 된다.
지역변수

대표적인 final클래스로는 String과 Math가 있다.

 

final class FinalTest {	// 조상이 될 수 없는 클래스
	final int MAX_SIZE = 10;	// 값을 변경할 수 없는 멤버변수(상수)

	final void getMaxSize() {	// 오버라이딩할 수 없는 메서드(변경불가)
		final int LV = MAX_SIZE;	// 값을 변경할 수 없는 지역변수(상수)
		return MAX_SIZE;
	}
}

 

 

생성자를 이용한 final멤버 변수의 초기화

final이 붙은 변수는 상수이므로 일반적으로 선언과 초기화를 동시에 하지만, 인스턴스 변수의 경우 생성자에서 초기화되도록 할 수 있다.

클래스 내에 매개변수를 갖는 갖는 생성자를 선언하여, 인스턴스를 생성할 때 final이 붙은 멤버 변수를 초기화하는데 필요한 값을 생성자의 매개변수로부터 제공받는 것이다.

 이 기능을 활용하면 각 인스턴스마다 final이 붙은 인스턴스변수는 모든 인스턴스에서 같은 값을 가져야만 할 것이다.

 

 

abstract - 추상의, 미완성의

abstract는 메서드의 선언부만 작성하고 실제 수행 내용은 구현하지 않은 추상 메서드를 선언하는 데 사용된다.

그리고 클래스에 사용되어 클래스 내에 추상 메서드가 존재한다는 것을 쉽게 알 수 있게 한다.

abstract가 사용될 수 있는 곳 - 클래스, 메서드
제어자 대상 의미
abstract 클래스 클래스 내에 추상 메서드가 선언되어 있음을 의미한다.
메서드 선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알린다.

추상 클래스는 아직 완성되지 않은 메서드가 존재하는 미완성 설계도 이므로 인스턴스를 생성할 수 없다.

 

드물지만 추상 메서드가 없는 클래스, 즉 완성된 클래스도 abstract를 붙여서 추상 클래스로 만드는 경우도 있다.

이 클래스 자체로는 쓸모가 없지만, 다른 클래스가 이 클래스를 상속받아서 일부의 원하는 메서드만 오버 라이딩해도 된다는 장점이 있다.

 

 

접근 제어자(access modifier)

접근 제어자는 멤버 또는 클래스에 사용되어, 해당하는 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다.

접근 제어자가 사용될 수 있는 곳 - 클래스, 멤버 변수, 메서드, 생성자

private	같은 클래스 내에서만 접근이 가능하다.
default	같은 패키지 내에서만 접근이 가능하다.
protected 같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근이 가능하다.
public	접근 제한이 전혀 없다.
제어자 같은 클래스 같은 패키지 자손클래스 전체
클래스 public, (default)
메서드 public, protected, (default), private
멤버변수
지역변수 없 음

 

접근 제어자를 이용한 캡슐화

클래스나 멤버, 주로 멤버에 접근 제어자를 사용하는 이유는 클래스의 내부에 선언된 데이터를 보호하기 위해서이다.

데이터가 유효한 값을 유지하도록, 또는 비밀번호와 같은 데이터를 외부에서 함부로 변경하지 못하도록 하기 위해서는 외부로부터의 접근을 제한하는 것이 필요하다.

이것을 데이터 감추기(data hiding)라고 하며, 객체지향 개념의 캡슐화(encapsulation)에 해당하는 내용이다.

또 다른 이유는 클래스 내에서만 사용되는, 내부 작업을 위해 임시로 사용되는 멤버 변수나 부분 작업을 처리하기 위한 메서드 등의 멤버들을 클래스 내부에 감추기 위해서이다.

외부에서 접근할 필요가 없는 멤버들을 private으로 지정하여 외부에 노출시키지 않음으로써 복잡성을 줄일 수 있다.

 

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

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

 

get으로 시작하는 메서드는 단순히 멤버변수의 값을 반환하는 일을 하고, set으로 시작하는 메서드는 매개변수에 지저 된 값을 검사하여 조건에 맞는 값일 때만 멤버 변수의 값을 변경하도록 작성되어 있다.

 만일 상속을 통해 확장될 것이 예상되는 클래스라면 멤버에 접근 제한을 주되 자손 클래스에서 접근하는 것이 가능하도록 하기 위해 private대신 protected를 사용한다. private이 붙은 멤버는 자손 클래스에서도 접근이 불가능하기 때문이다.

보통 멤버변수의 값을 읽는 메서드의 이름을 get멤버 변수 이름으로 하고, 멤버 변수의 값을 변경하는 메서드의 이름을 set멤버 변수로 한다.

get으로 시작ㅎ나는 메서드를 getter라고 하고 set으로 시작하는 메서드를 setter라고 한다.

 

 

생성자의 접근 제어자

생성자에 접근 제어자를 사용함으로써 인스턴스의 생성을 제한할 수 있다.

 생성자의 접근제어자를 private으로 지정하면 외부에서 생성자에 접근할 수 없으므로 인스턴스를 생성할 수 없게 된다. 그래도 클래스 내부에서는 인스턴스를 생성할 수 있다.

대신 인스턴스를 생성해서 반환해주는 public메서드를 제공함으로써 외부에서 이 클래스의 인스턴스를 사용하도록 할 수 있다. 이 메서드는 public인 동시에 static 이어야 한다.

이처럼 생성자를 통해 직접 인스턴스를 생성하지 못하게 하고, public메서드를 통해 인스턴스에 접근하게 함으로써 사용할 수 있는 인스턴스의 개수를 제한할 수 있다.

또한 생성자가 private인 클래스는 다른 클래스의 조상이 될 수 없다. 왜냐하면, 자손 클래스의 인스턴스를 생성할 때 조상 클래스의 생성자를 호출해야만 하는데, 생성자의 접근 제어자가 private이므로 자손 클래스에서 호출하는 것이 불가능하기 때문이다.

 그래서 클래스 앞에 final을 추가하여 상속하지 못하는 클래스를 알리는 것이 좋다.

 

 

 

 

제어자(modifier)의 조합

대상 사용가능한 제어자
클래스 public, (default), final, abstract
메서드 모든 접근제어자, final, abstract, static
멤버변수 모든 접근 제어자, final, static
지역변수 final

 

제어자를 조합해서 사용할 때 주의해야 할 사항에 대해 정리해 보았다.

1. 메서드에 static과 abstract를 함께 사용할 수 없다.
static메서드는 몸통이 있는 메서드에만 사용할 수 있기 때문이다.

2. 클래스에 abstract와 final을 동시에 사용할 수 없다.
클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미이고 
abstract는 상속을 통해서 완성되어야 한다는 의미이므로 서로 모순되기 때문이다.

3. abstract메서드의 접근 제어자가 private일 수 없다.
abstract메서드는 자손클래스에서 구현해주어야 하는데 접근 제어자가 private이면,
자손클래스에서 접근할 수 없기 때문이다.

4. 메서드에 private과 final을 같이 사용할 필요는 없다.
접근제어자가 private인 메서드는 오버라이딩될 수 없기 때문이다. 이 둘 중 하나만 사용해도 의미가 충분하다

 

파일 할당 테이블(영어: File Allocation Table, FAT)은 디지털 카메라 등에 장착되는 대부분의 메모리 카드와 수많은 컴퓨터 시스템에 널리 쓰이는 컴퓨터 파일 시스템 구조(architecture)이다. FAT 파일 시스템은 상대적으로 간단하기 때문에 플로피 디스크, 플래시 메모리 카드, 디지털 카메라 및 다른 수많은 휴대용 기기에서 흔하게 볼 수 있다. FAT의 성능은 다른 대부분의 파일 시스템에 견주어 좋지 않은 평을 받는다. 그 까닭은 운영 시간을 낭비하게 만드는 너무나도 단순한 자료 구조를 이용하고 조그마한 파일이 많이 있으면 디스크 공간을 잘 활용하지 못하기 때문이다.

플로피 디스크의 경우 FAT는 ECMA-107[3]  ISO[4]/IEC 9293[5] 으로 표준화되어 있다. 이러한 표준들은 긴 파일 이름 지원이 포함되지 않은 FAT12와 FAT16만 포함하고 있다.

FAT 파일 시스템은 기술적으로 비교적 잘 문서화되어 있으며 실질적으로 기존의 모든 PC 운영 체제가 이를 지원한다. 그러므로 솔리드 스테이트 메모리 카드를 위한 쓸모있는 포맷으로서 운영 체제 사이의 자료 공유를 위한 편리한 방법이 되었다.

 

FAT32

2기가바이트 이상의 하드디스크를 지원하며, 윈도우 95 OSR2부터 이 파일 시스템을 사용할 수 있다.

FAT32에서는 하나의 파일은 최대 4기가바이트-1바이트의 용량을 가질 수 있다. 하나의 파티션이 최대 8테라바이트의 용량을 가질 수 있고, 최대 268,435,437개의 파일을 담을 수 있다. 윈도우 98, 윈도우 미와 같은 구형 운영 체제나, 리눅스, OS X과 같은 운영 체제에서 윈도우와 호환성이 필요할 때, 또는 디지털카메라, 게임기 등에서도 이용된다. 윈도우 XP 등에 내장된 디스크 관리자 유틸리티에서는 32기가바이트 이상의 하드디스크를 파티션할 때 FAT32를 선택할 수 없고 NTFS만 나오지만, 별도 유틸리티를 이용하거나 다른 운영 체제에서 파티션을 설정하면 문제 없이 사용할 수 있다.

클러스터의 크기가 작아 하드디스크의 낭비를 줄일 수 있다. FAT16보다 효율적으로 하드디스크를 이용한다. 물리적 드라이브의 크기에 따라서 클러스터의 크기를 다르게 설정한다.

FATX

FATX는 FAT 파일 시스템을 수정한 버전이며 마이크로소프트의 엑스박스 게임기 하드 디스크 드라이브와 메모리 카드를 위하여 설계된 것이다. FATX는 아래의 exFAT와 혼동해서는 안 된다.

exFAT

'Extended File Allocation Table'의 약자로 일명 FAT64라고도 한다. 윈도우 XP와 윈도우 서버 2003 (둘다 x86, x64) 사용자들은 마이크로소프트사로부터 업데이트 KB955704를 내려받아 설치하면 exFAT 지원을 사용할 수 있고,[9] 윈도우 비스타의 경우 서비스 팩 1, 윈도우 임베디드 CE 6.0부터 지원한다. FAT32의 한계를 극복하고자 개발되었으며 고용량의 플래시 메모리 미디어를 위한 파일 시스템이다. 여유공간 계산이 빨라졌으며 파일 삭제 또한 빨라졌다. FAT32에서 파일의 최대 크기가 4기가바이트인 반면, exFAT에서는 16엑사바이트가 파일의 최대 크기가 된다.

 

출처 : 위키백과

https://ko.wikipedia.org/wiki/%ED%8C%8C%EC%9D%BC_%ED%95%A0%EB%8B%B9_%ED%85%8C%EC%9D%B4%EB%B8%94

패키지(package)

패키지란, 클래스의 묶음이다. 패키지에는 클래스 또는 인터페이스를 포함시킬 수 있으며, 서로 관련된 클래스끼리 그룹 단위로 묶어 놓음으로써 클래스를 효율적으로 관리할 수 있다.

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

디렉터리가 하위 디렉터리를 가질 수 있는 것처럼, 패키지도 다른 패키지를 포함할 수 있으며 점'.'으로 구분한다.

예를 들면 java.lang패키지에서 lang패키지는 java패키지의 하위 패키지이다.

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

 

 

패키지의 선언

패키지를 선언하는 것은 아주 간단하다. 클래스나 인터페이스의 소스파일의 맨 위에 패키지라고 적어주면 된다.

package 패키지명;

위와 같은 패키지 선언문은 반드시 소스파일에서 주석과 공백을 제외한 첫 번째 문장이어야 하며, 하나의 소스파일에서 단 한 번만 선언될 수 있다. 해당 소스파일에 포함된 모든 클래스나 인터페이스는 선언된 패키지에 속하게 된다. 

 패키 지명은 대소문자를 모두 허용하지만, 클래스명과 쉽게 구분하기 위해서 소문자로 하는 것을 원칙으로 하고 있다.

큰 프로젝트나 Java API와 같은 클래스 라이브러리를 작성하는 경우에는 미리 패키지를 구성하여 적용해야 한다.

 

 

import문

소스코드를 작성할 때 다른 패키지의 클래스를 사용하려면 패키 지명이 포함된 클래스 이름을 사용해야 한다.

하지만, 매번 패키 지명을 붙여서 작성하는 것이 불편하므로 클래스의 코드를 사용하기 전에 import문으로 사용하고자 하는 클래스의 패키지를 미리 명시해주면 소스코드에 사용되는 클래스 이름에서 패키 지명은 생략할 수 있다.

import문의 역할은 컴파일러에게 소스파일에 사용된 클래스의 패키지에 대한 정보를 공개하는 것이다.

컴파일러는 import문을 통해 소스파일에 사용된 클래스들의 패키지를 알아낸 다음, 모든 클래스 이름 앞에 패키 지명을 붙여준다.

이클립스는 ctrl+shift+o를 누르면 자동으로 import문을 추가해준다.

 

 

import문의 선언

모든 소스파일(. java)에서 import문은 package문 다음에, 클래스 선언문 이전에 위치해야 한다. import문은 package문과 달리 한 소스파일에 여러 번 선언할 수 있다.

일반적인 소스파일(*. java)의 구성은 다음의 순서로 되어 있다.

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

import문을 선언하는 방법은 다음과 같다.

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

키워드 import와 패키 지명을 생략하고자 하는 클래스의 이름을 패키 지명과 함께 써주면 된다.

'패키 지명.*'은 같은 패키지에서 여러 개의 클래스가 사용될 때 유용하다.

실행 시 성능상의 차이는 전혀 없다.

단, 이 경우에는 하위 패키지는 포함하지 않는다.

import java.util.*;

import java.text.*;

즉 위의 두 패키지를 합친다고 아래와 같이 표현하면 안 된다.

import java.*; (이렇게 표현 X)

 

static import문

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

import static java.lang.Integer.*;
import static java.lang.Math.random;
import static java.lang.System.out;

 

System.out.println(Math.random()); > out.println(random());으로 사용이 가능하다.

import static java.lang.System.out;
import static java.lang.Math.*;

public class StaticImportEx1 {
	public static void main(String[] args) {
//		System.out.println(Math.random());
		out.println(random());
		
//		System.out.println("Math.PI :"+Math.PI);
		out.println("Math.PI :" + PI);
	}
}
0.9214332841721639
Math.PI :3.141592653589793

사용자가 입력 데이터를 전달하는 방법중의 하나로, url 주소에 미리 협의된 데이터를 파라미터를 통해 넘기는 것을 말한다.

http://host:port/path?querystring

query parameters( 물음표 뒤에 = 로 연결된 key value pair 부분)을 url 뒤에 덧붙여서 추가적인 정보를 서버 측에 전달하는 것이다. 클라이언트가 어떤 특정 리소스에 접근하고 싶어하는지 정보를 담는다.

형식

  • 정해진 엔드포인트 주소 이후에 ?를 쓰는것으로 쿼리스트링이 시작함을 알린다
  • parameter=value로 필요한 파라미터의 값을 적는다
  • 파라미터가 여러개일 경우 &를 붙여 여러개의 파라미터를 넘길 수 있다.
    엔드포인트주소/엔드포인트주소?파라미터=값&파라미터=값= 로 key 와 value 가 구분된다.

 

 

출처 : https://velog.io/@pear/Query-String-%EC%BF%BC%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%A7%81%EC%9D%B4%EB%9E%80

 

Query String 쿼리스트링이란?

사용자가 입력 데이터를 전달하는 방법중의 하나로, url 주소에 미리 협의된 데이터를 파라미터를 통해 넘기는 것을 말한다.http://host:port/path?querystringquery parameters( 물음표 뒤에 = 로 연결된 key valu

velog.io

 

 

전사적 자원 관리(영어: Enterprise resource planning: ERP)는 경영 정보 시스템(MIS)의 한 종류이다. 전사적 자원 관리는 회사의 모든 정보 뿐만 아니라, 공급 사슬관리, 고객의 주문정보까지 포함하여 통합적으로 관리하는 시스템이다. 경영, 인사, 재무, 생산 등 기업의 전반적 시스템을 하나로 통합함으로써 효율성을 극대화하는 경영 전략이다. ERP를 도입시 생산부분이 마케팅을 실시간으로 조회하여 생산일정을 조회 및 변경할 수 있는 등 비용 낭비나 생산 지연 요인을 사전에 제거하는 일이 가능해진다.

 

경영 정보 시스템

경영 정보 시스템( Management Information Systems, 줄여서 MIS)은 기업이라는 시스템의 관점에서 경영시스템의 목표인 이익창출을 위해 다른 하위 시스템을 효율적으로 작용하도록 지원하는 시스템이다. 경영 정보 시스템은 자료를 저장하고, 정보를 생성함으로써 기업 내에서 필요한 지식을 생성하고 축적하며 이를 활용하도록 하는 통합적 컴퓨터 정보시스템이다. 눈에 보이지 않는 지식이지만 이러한 지식의 원천을 형성하는 자료와 정보를 제공하는 기능을 담당하는 것이 경영정보시스템이다. 

 

 

출처 : 위키백과  https://ko.wikipedia.org/wiki/%EC%A0%84%EC%82%AC%EC%A0%81_%EC%9E%90%EC%9B%90_%EA%B4%80%EB%A6%AC

'팀프로젝트 지식 > 용어' 카테고리의 다른 글

용어 몇가지 정리  (0) 2021.07.30

오버 라이딩이란

조상 클래스로부터 상속받은 메서드의 내용을 변경하는 것을 오버 라이딩이라고 한다.

(override의 의미는 ~위에 덮어쓰다(overwrite)이다.)

 

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;
	}
}

Point클래스의 getLocation은 한 점의 x, y좌표를 문자열로 반환하도록 작성되었다.

Point클래스는 3차원 좌표계의 한 점을 표현하기 위한 것이므로 조상인 Point클래스로부터 상속받은 getLocation()은 Point 3D클래스에 맞지 않는다.

그래서 이 메서드를 Point3D클래스 자신에 맞게 z축의 좌표값도 포함하여 반환하도록 오버 라이딩하였다.

 

 

 

 

오버 라이딩의 조건

오버 라이딩은 메서드의 내용만을 새로 작성하는 것이므로 메서드는 조상의 것과 완전히 일치해야 한다.

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

한마디로 선언부가 서로 일치해야 한다는 것이다. 다만 접근 제어자(access modifier)와 예외(exception)는 제한된 조건 하에서만 다르게 변경할 수 있다.

 

1. 접근 제어자는 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.

만일 조상 클래스에 정의된 메서드의 접근 제어자가 protected라면, 이를 오버 라이딩하는 자손 클래스의 메서드는 접근 제어자가 protected나 public이어야 한다. 대부분의 경우 같은 범위의 접근 제어자를 사용한다.

Public > protected > (default), privvate이다.

 

2. 조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.

아래의 코드를 보면 child클래스의 parentMethod()에 선언된 예외의 개수가 조장인 Parent클래스의 parentMethod()에 선언된 예외의 개수보다 적으므로 바르게 오버 라이딩되었다.

class Parent {
	void parentMethod() throws IOException, SQLException {
		...
	}
}
class Child extends Parent {
	void parentMethod() throws IOException {
		...
	}	
	...
}

여기서 한 가지 주의할 것이 있는데 예외 문의 개수만 문제가 아니라 조상 클래스 여부도 따져야 한다.

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

 

오버 로딩 vs 오버 라이딩

 

오버 로딩과 오버 라이딩은 혼동하기 쉽지만 차이가 명백하다.

오버 로딩은 기존에 없는 새로운 메서드를 추가하는 것이고, 오버 라이딩은 조상으로부터 상속받은 메서드의 내용을 변경하는 것이다.

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

아래의 코드를 보고 오버 로딩과 오버 라이딩을 구별할 수 있어야 한다.

class Parent {
		void parentMethod() {}
}

class Child extends Parent {
		void parentMethod() {}
		void parentMethod(int i) {}

		void childMethod() {}
		void childMethod(int i) {}
		void childMethod() {}
}

 

프로그래밍은 어떤 메서드가 어떤 인스턴스로 호출되는가를 실행할 때 알게 되고 컴파일 때는 모른다.

 

 

super

super는 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는 데 사용되는 참조 변수이다.

멤버 변수와 지역변수의 이름이 같을 때 this를 사용할 수 있다. 그래도 조상 클래스의 멤버와 자손 클래스의 멤버가 중복 정의되어 서로 구별해야 하는 경우에만 super를 사용하는 것이 좋다.

조상의 멤버와 자신의 멤버를 구별하는 데 사용된다는 점을 제외하고는 super와 this는 근본적으로 같다.

모든 인스턴스 메서드에는 자신이 속한 인스턴스의 주소가 지역변수로 저장되는데, 이것이 참조 변수인 this와 super의 값이 같다.

 static메서드(클래스 메서드)는 인스턴스와 관련이 없다. 그래서 this와 마찬가지로 super 역시 static메서드에서는 사용할 수 없고 인스턴스 메서드에서만 사용할 수 있다.

 

 

super() - 조상 클래스의 생성자()

this()와 마찬가지로 super() 역시 생성자이다. this()는 같은 클래스의 다른 생성자를 호출하는 데 사용되지만, super()는 조상 클래스의 생성자를 호출하는 데 사용된다.

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

이때 조상 클래스 멤버의 초기화 작업이 수행되어야 하기 때문에 자손 클래스의 생성자에서 조상 클래스의 생성자가 호출되어야 한다.

생성자의 첫 줄에서 조상 클래스의 생성자를 호출해야 하는 이유는 자손 클래스의 멤버가 조상 클래스의 멤버를 사용할 수도 있으므로 조상의 멤버들이 먼저 초기화되어 있어야 하기 때문이다.

이와 같은 조상 클래스 생성자의 호출은 클래스의 상속관계를 거슬러 올라가면서 계속 반복된다. 마지막으로 모든 클래스의 최고 조상인 Object클래스의 생성자인 Object()까지 가서야 끝이 난다.

그래서 Object클래스를 제외한 모든 클래스의 생성자는 첫 줄에 반드시 자신의 다른 생성자 또는 조상의 생성자를 호출해야 한다. 그렇지 않으면 컴파일러는 생성자의 첫 줄에 super();를 자동적으로 추가할 것이다.

Object클래스를 제외한 모든 클래스의 생성자 첫 줄에 생성자.this() 또는 super(),를 호출해야 한다.
그렇지 않으면 컴파일러가 자동적으로 super();를 생성자의 첫 줄에 삽입한다.

인스턴스를 생성할 때는 클래스를 선택하는 것만큼 생성자를 선택하는 것도 중요하다.

1. 클래스 - 어떤 클래스의 인스턴스를 생성할 것인가?
2. 생성자 - 선택한 클래스의 어떤 생성자를 이용해서 인스턴스를 생성할 것인가?

 

상속의 정의와 장점

기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것이다. 보다 적은 양의 코드로 새로운 클래스를 만들 수 있음과 동시에 코드의 추가 및 변경이 용이하다.

자바에서 상속을 구현하는 방법은 클래스 이름뒤에 상속받고자 하는 클래스의 이름을 키워드 'extends'와 함께 써 주기만 하면 된다.

class Child extends Parent {
	// ...
}

이 두 클래스는 서로 상속 관계에 있다고 하며, 상속해주는 클래스를 '조상 클래스'라 하고 상속받는 클래스를 '자손 클래스'라 한다.

서로 상속관계에 있는 두 클래스를 조상 클래스, 자손 클래스와 같은 용어로 표현하기도 한다.

조상 클래스 부모(parent)클래스, 상위(super)클래스, 기반(base)클래스
자손 클래스 자식(child)클래스, 하위(sub)클래스, 파생된(derived)클래스

아래와 같이 서로 상속관계에 있는 두 클래스를 표현하면 다음과 같다.

class Parent { }
class Child extends Parent { }

클래스는 타원으로 표현했고 클래스간의 관계는 화살표로 표시했다. 

이와 같이 클래스 간의 상속관계를 그림으로 표현한 것을 상속계층도(class hierarchy)라고 한다.

자손 클래스는 조상의 멤버를 모두 상속받는다.

 

조상 클래스가 변경되면 자손 클래스는 자동적으로 영향을 받게 되지만, 자손 클래스가 변경되는 것은 조상 클래스에 아무런 영향을 주지 못한다.

또한 자손클래스는 조상 클래스의 모든 멤버를 상속받으므로 항상 조상 클래스보다 같거나 많은 멤버를 갖게 된다.

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

접근 제어자(access modifier)가 private 또는 default인 멤버들은 상속되지 않는다기보다 상속은 받지만 자손 클래스로부터의 접근이 제한되는 것이다.

또한 같은 조상클래스를 가지고 있더라도 자손 클래스끼리는 아무런 관계도 성립되지 않는다.

상속을 이용하는 이유는 같은 내용의 코드를 하나 이상의 클래스에 중복적으로 추가해야하는경우에는 상속관계를 이용해서 코드의 중복을 최소화해야 한다. 자손 클래스는 조상 클래스의 모든 멤버를 물려받으므로 조상의 조상 클래스까지 상속받게 된다.

 

 

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

상속 이외에도 클래스를 재사용하는 또 다른 방법이 있는데, 그것은 클래스 간에 포함(Composite) 관계를 맺어 주는 것이다.

클래스 간의 포함관계를 맺어 주는 것은 한 클래스의 멤버변수로 다른 클래스 타입의 참조 변수를 선언하는 것을 뜻한다.

class Circle {
	int x;
	int y;
	int r;
}
class Point {
	int x;
	int y;
}

Point 클래스를 이용해서 Circle클래스를 작성한다면

class Circle { 
	Point c = new Point();
	irt r;
}

이와같이 한 클래스를 작성하는 데 다른 클래스를 멤버 변수로 선언하여 포함시키는 것은 코드를 다시 작성할 수고를 줄이고 작은 단위로 분리함으로써 재사용 가능성도 높아진다.

그리고 무엇보다 코드가 간결해서 이해하기 쉽다.

 

클래스간의 관계 결정하기

클래스를 작성하는 데 있어서 상속관계를 맺어 줄 것인지 포함관계를 맺어 줄 것인지 판단하는 방법은 ~은~이다(is-a)와 ~은~을 가지고 있다.(has-a)를 넣어서 문장을 만들어보면 된다.

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

이렇게 비교를해보면 두 번째 문장이 맞다는 것을 더 쉽게 알 수 있다.

원과 점 사이의 관계는 상속보다는 포함 관계가 어울린다는 사실을 알 수 있다.

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

프로그램의 모든 클래스를 분석하여 가능한 많은 관계를 맺도록 노력해서 코드의 재사용성을 높여야 한다.

public class DrawShape {
	public static void main(String[] args) {
		Point[] p = {	
				new Point(100, 100),
				new Point(140, 50),
				new Point(200, 100)
		};
		Triangle t = new Triangle(p);
		Circle c = new Circle(new Point(150, 150), 50);
		
		t.draw();
		c.draw();
	}

}

class Shape {
	String color = "black";
	void draw() {
		System.out.printf("[color=%s]%n", color);
	}
}

class Point {
	int x;
	int y;

	Point(int x, int y) {
		this.x = x;
		this.y = y;
	}

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

	String getXY() {
		return "(" + x + "," + y + ")"; // x와 y의 값을 문자열로 반환
	}
}

class Circle extends Shape {
	Point center;
	int r;

	Circle() {
		this(new Point(0, 0), 100);
}
	Circle(Point center, int r) {
		this.center = center;
		this.r = r;
	}
	
	void draw() {
		System.out.printf("[center=(%d, %d), r=%d, color=%s]%n", center.x, center.y, r, color);
	}
}

class Triangle extends Shape {
	Point[] p = new Point[3];
	
	Triangle(Point[] p) {
		this.p = p;
	}
	
	void draw() {
		System.out.printf("[p1=%s, p2=%s, p3=%s, color=%s]%n",
				p[0].getXY(),p[1].getXY(), p[2].getXY(), color);
	}
}
[p1=(100,100), p2=(140,50), p3=(200,100), color=black]
[center=(150, 150), r=50, color=black]

도형을 의미하는 shape클래스를 정의하고, 2차원 좌표에서 점을 의미하는 Point클래스를 정의한 다음, 이 두 클래스를 재활용해서 Circle클래스와 Triangle클래스를 정의하였다.

Circle클래스는 Shape클래스로부터 모든 멤버를 상속받았으므로, Shape클래스에 정의된 color이나 draw()를 사용할 수 있다.

 

 

class Shape {
		String color = "black";

		void draw() {
			System.out.printf("[color=%s]%n", color);
		}
}

Circle클래스에도 draw()가 정의되어 있다. 그러면 둘 중에 어떤 것이 호출되는 것인가?

그것은 Circle클래스의 draw()가 호출된다.

class Circle extends Shape {
		...
		void draw() {
			System.out.printf("[center=(%d, %d), r=%d,color=%s]%n",
					center.x, center.y, r, color
		}
}

이처럼 조상 클래스에 저의 된 메서드와 같은 메서드를 자손 클래스에 정의하는 것을'오버 라이딩'이라고 하며 매우 중요한 내용이다.

Circle c = new Circle(new Point(150, 150), 50);

위의 문장은 아래 두 문장을 합쳐 놓은 것이다.

Point P = new Point(150, 150);
Circle c = new Circle(P, 50);

문장이 복잡하면 여러 문장으로 분해하는 연습을 하면 이해하는데 한결 도움이 된다.

 

 

단일 상속(single inheritance)

자바에서는 오직 단일 상속만을 허용한다.

class TVCR extends TV, VCR {	// 에러. 조상은 하나만 허용한다
	//...
}

만약 이대로 한다면 Multiple markers at this line이라는 에러가 난다.

class Tv {
	boolean power;
	int channel;
	
	void power()	{ power = !power; }
	void channelUP() { ++channel; }
	void channelDown() { --channel; }
}

class VCR {
	boolean power;
	int counter = 0;
	void power() {	power = !power; }
		void play() { }
		void stop() { }
		void rew() { }
		void ff() { }
	}

class TVCR extends Tv {
	VCR vcr = new VCR();
	
	void play() {
		vcr.play();
	}
	
	void stop() {
		vcr.stop();
	}
	void rew() {
		vcr.rew();
	}
	void ff() {
		vcr.ff();
	}

}

자바는 다중 상속을 허용하지 않으므로 Tv클래스를 조상으로 하고, VCR클래스는 TVCR클래스에 포함시켰다. 그리고 TVCR클래스에 VCR클래스의 메서드와 일치하는 선언부를 가진 메서드를 선언하고 내용은 VCR클래스의 것을 호출해서 사용하도록 했다.

외부적으로는 TVCR클래스의 인스턴스를 사용하는 것처럼 보이지만 내부적으로는 VCR클래스의 인스턴스를 생성해서 사용하는 것이다.

 

Object클래스 모든 클래스의 조상

모든 클래스 상속계층도의 최상위에 있는 조상 클래스이다. 다른 클래스로부터 상속받지 않는 모든 클래스들은 Object클래스로부터 상속받게 함으로써 이것을 가능하게 한다.

class Tv {
	...
}
class Tv extends Object {
	...
}

모든 상속계층도의 최상위에는 Object클래스가 위치한다.

 

6-21 Tv클래스를 주어진 로직대로 완성하시오 완성한 후에 실행해서 주어진 실행결과와 일치하는지 확인하라.

class MyTv {
	boolean isPowerOn;
	int channel;
	int volume;
	final int MAX_VOLUME = 100;
	final int MIN_VOLUME = 0;
	final int MAX_CHANNEL = 100;
	final int MIN_CHANNEL = 1;

	void turnOnOff() {
		// (!) isPowerOn의 값이 true면 false로, false면 true로 바꾼다
	}

	void volumeUp() {
		// (2) voulum의 값이 MAX_VOLUME보다 작을 때만 값을 1증가시킨다/
	}

	void volumeDown() {
		// (3) volum의 값이 MIN_VOLUME보다 클 때만 값을 1감소시킨다.
	}

	void channelUp() {
		// (4) channel의 값을 1 증가시킨다.
		// 만일 channel이 MAX_CHANNEL이면, channel의 값을 MIN_CHANNEL로 다시 바꾼다.
	}

	void channelDown() {
		// (5)channel의 값을 1감소시킨다.
		// 만일 channel이 MIN_CHANNEL이면, channel의 값을 MAX_CHANNEL로 바꾼다.

	} // class MyTv

class Exercise6_21 {
	public static void main(String args[]) {
		MyTv t = new MyTv();
		t.channel = 100;
		t.volume = 0;
		System.out.println("CH:" + t.channel + ", VOL:" + t.volume);

		t.channelDown();
		t.volumeDown();
		System.out.println("CH:" + t.channel + ", VOL:" + t.volume);

		t.volume = 100;
		t.channelUp();
		t.volumeUp();
		System.out.println("CH:" + t.channel + ", VOL:" + t.volume);

	}
}
class MyTv {
	boolean isPowerOn;
	int channel;
	int volume;
	final int MAX_VOLUME = 100;
	final int MIN_VOLUME = 0;
	final int MAX_CHANNEL = 100;
	final int MIN_CHANNEL = 1;

	void turnOnOff() {
		// (!) isPowerOn의 값이 true면 false로, false면 true로 바꾼다
		isPowerOn = !isPowerOn;
	}

	void volumeUp() {
		// (2) voulume의 값이 MAX_VOLUME보다 작을 때만 값을 1증가시킨다/
		if (volume < MAX_VOLUME)
			volume += 1;
	}

	void volumeDown() {
		// (3) volume의 값이 MIN_VOLUME보다 클 때만 값을 1감소시킨다.
		if (volume > MIN_VOLUME)
			volume -= 1;
	}

	void channelUp() {
		// (4) channel의 값을 1 증가시킨다.
		// 만일 channel이 MAX_CHANNEL이면, channel의 값을 MIN_CHANNEL로 다시 바꾼다.
		if (channel == MAX_CHANNEL)
			channel = MIN_CHANNEL;
		else
			channel += 1;
	}

	void channelDown() {
		// (5)channel의 값을 1감소시킨다.
		// 만일 channel이 MIN_CHANNEL이면, channel의 값을 MAX_CHANNEL로 바꾼다.
		if (channel == MIN_CHANNEL)
			channel = MAX_CHANNEL;
		else
			channel -= 1;
	}
} // class MyTv

class Exercise6_21 {
	public static void main(String args[]) {
		MyTv t = new MyTv();
		t.channel = 100;
		t.volume = 0;
		System.out.println("CH:" + t.channel + ", VOL:" + t.volume);

		t.channelDown();
		t.volumeDown();
		System.out.println("CH:" + t.channel + ", VOL:" + t.volume);

		t.volume = 100;
		t.channelUp();
		t.volumeUp();
		System.out.println("CH:" + t.channel + ", VOL:" + t.volume);

	}
}
CH:100, VOL:0
CH:99, VOL:0
CH:100, VOL:100

 

 

 

 

6-22 다음과 같이 정의된 메서드를 작성하고 테스트하시오.

매서드명 : isNumber

기     능 : 주어진 문자열이 모두 숫자로만 이루어져있는지 확인한다.

모두 숫자로만 이루어져 있으면 true를 반환하고, 그렇지 않으면 false를 반환한다.

만일 주어진 문자열이 null이거나 빈문자열 ""이라면 false를 반환한다.

반환타입 : boolean

매개변수 : String str - 검사할 문자열

[Hint] String클래스의 charAt(int i)메서드를 사용하면 문자열의 i번째 위치한 문자를 얻을 수 있다.

public class Exercise6_22 {
	/*
	 * (1) isNumber . 메서드를 작성하시오
	 */
	public static void main(String[] args) {
	String str = "123";
	System.out.println(str+"는 숫자입니까? "+isNumber(str));
	str = "1234o";
	System.out.println(str+"는 숫자입니까? "+isNumber(str));
	}
}
public class Exercise6_22 {

	public static boolean isNumber(String str) {
		if (str == null || str == "") {
			return false;
		}
		for(int i=0; i<str.length();i++) {
			char ch = str.charAt(i);
			
			if (ch<'0' && ch>'9'){
				return false;
			}
		}
		return true;
	}
	public static void main(String[] args) {
		String str = "123";
		System.out.println(str + "는 숫자입니까? " + isNumber(str));
		str = "1234o";
		System.out.println(str + "는 숫자입니까? " + isNumber(str));
	}
}

 

 

 

 

6-23 다음과 같이 정의된 메서드를 작성하고 테스트하시오.

매서드명 : max

기     능 : 주어진 int형 배열의 값 중에서 제일 큰 값을 반환한다. 

만일 주어진 배열이 null이거나 크기가 0인 경우,  -999999를 반환한다.

반환타입 : int 

매개변수 : int[] arr - 최대값을 구할 배열

public class Exercise6_23 {
	/*
	 * (1) max메서드를 작성하시오.
	 */
			}

		}
		return max;
	}

	public static void main(String[] args) {
		int[] data = { 3, 2, 9, 4, 7 };
		System.out.println(java.util.Arrays.toString(data));
		System.out.println("최대값 :" + max(data));
		System.out.println("최대값 :" + max(null));
		System.out.println("최대값 :" + max(new int[] {})); // 0 최대값 크기가 인 배열
	}
}
public class Exercise6_23 {
	/*
	 * (1) max메서드를 작성하시오.
	 */
	static int max(int[] arr) {
		if (arr == null || arr.length == 0)
			return -999999;
		int max = arr[0];

		for (int i = 0; i < arr.length-1; i++) {
			if (arr[i + 1] > max) {
				max = arr[i + 1];
			}

		}
		return max;
	}

	public static void main(String[] args) {
		int[] data = { 3, 2, 9, 4, 7 };
		System.out.println(java.util.Arrays.toString(data));
		System.out.println("최대값 :" + max(data));
		System.out.println("최대값 :" + max(null));
		System.out.println("최대값 :" + max(new int[] {})); // 0 최대값 크기가 인 배열
	}
}
[3, 2, 9, 4, 7]
최대값 :9
최대값 :-999999
최대값 :-999999

 

 

 

6-24 다음과 같이 정의된 메서드를 작성하고 테스트하시오.

 

메서드명 : abs

기     능 : 주어진 값의 절대값을 반환한다.

반환타입 : int

매개변수 : int value

class Exercise6_24 {
		/*
		 * 	(1) abs메서드를 작성하시오.
		 */
	public static void main(String[] args)
	{
		int value = 5;
		System.out.println(value+"의 절대값:"+abs(value));
		value = -10;
		System.out.println(value+"의 절대값:"+abs(value));
	}
}
class Exercise6_24 {
	public static int abs(int value) {
		if (value > 0) {
			return value;
		} else {
			return -value;
		}
	}
	public static void main(String[] args) {
		int value = 5;
		System.out.println(value + "의 절대값:" + abs(value));
		value = -10;
		System.out.println(value + "의 절대값:" + abs(value));
	}
}
5의 절대값:5
-10의 절대값:10

+ Recent posts