본문 바로가기

코딩공부/JAVA

[13] 자바 문서 보는 법 & 자바의 구조 (클래스, 인스턴스, 상속)

API vs UI

 

컴퓨터를 사용하려 한다. 컴퓨터를 직접 다루기 어렵기 때문에, 컴퓨터에 운영체제(Windows, MacOS etc..)를 설치한다. 그리고 운영체제에 맞는 Java 프로그램을 설치하고, 자바를 이용해서 나의 프로그램을 만들 수 있게 된다.

자바는 프로그램을 쉽게 만들 수 있도록 여러 가지 부품들을 제공한다. (화면에 출력 - System.out.println , 날짜 - Date, 수학 - Math etc...)

자바가 기본적으로 내장하고 있는 기능들을 "기본 라이브러리"라고 하고, 이 라이브러리라고 하는 부품을 이용해서 Java Program을 만든다. "시간의 흐름"에 따라서, 자바가 제공하는 기본적인 문법에 따라서 라이브러리가 실행되도록 하여 프로그램을 만든다.

 

API ( Application Programming Interface )

 - 자바가 기본적으로 제공하는 라이브러리 조작 방법

 - Programming : "시간의 순서"에 따라서 실행된다.

 - Application : 자바가 제공하는 부품들을 응용(Application)해서 만든다.

 

UI ( User Interface )

 - 사람이 우리가 만든 프로그램을 조작하기 위해서 조작해야 되는 조작 장치

 - Ex) 웹 - link, 데스크탑 애플리케이션 -  버튼, command line system - argument 

 

 

우리가 만든 프로그램은 사람이 사용하지 않을 수도 있다. "우리가 만든 프로그램을 부품으로" 하는 또 다름 프로그램을 만들 수 있다.

완제품에 해당되는 프로그램에게 우리의 프로그램에게 API를 제공해야 된다.

 

API Documentation - 패키지, 클래스, 변수, 메소드

"자립"의 핵심적인 기술 - 자바의 공식 라이브러리 사용 설명서를 보는 방법

api documentation java [version]

https://docs.oracle.com/javase/7/docs/api/

 

Java Platform SE 7

 

docs.oracle.com

 

패키지는 서로 연관된 비슷한 성격의 클래스를 그룹핑

클래스는 "하나의 프로그램" 이라고 생각하면 된다. 서로 연관된 변수와 메소드를 그룹핑

 

수학과 관련된 작업을 해야 할 때 사용할 수 있는 클래스를 검색 - (페이지 검색 : command + F ) 'Math'  검색 > Class 목록에서 검색된 'Math' 를 클릭하면 우측에 클래스에 대한 상세보기가 나온다.

"java.lang" : Math 클래스가 소속되어 있는 패키지

 

클래스

 서로 연관된 변수와 메소드를 그룹핑하여 이름을 붙인 것

 

클래스 사용법

1. 특정한 정보를 알아내고 싶다. 파이값을 알고 싶다면?

자바는 수학과 관련된 'Math' 클래스를 내장하고 있다.

클래스명을 입력 후, 점(.)을 찍으면 해당 클래스에 소속되어있는 변수와 메소드 리스트를 보여준다.

 

Math.PI 는 파이값이 적당한 정밀도로 저장되어 있는 변수이다. 이러한 PI는 Math 클래스에 소속되어있다. 클래스를 "디렉토리" 개념으로 볼 수 있다.

 

 

2. 어떤 정보를 처리하고 싶다.

실수의 소수점 자리를 올리고 내리고 싶다면?

Math.ceil 메소드는 천장이란 의미로 입력값을 올림 하는 기능이다.

Math.floor 메서드는 바닥이란 의미로 입력값을 내림하는 기능이다. 

 

 

인스턴스

 

(실습) 자바로 result1.txt 파일에 "Hello 1"이라는 내용을 작성

검색 또는 질문으로 어떤 클래스가 필요한지 알아내서 사용 예제를 살펴보고 이해가 안 간다면 api documnetation을 분석해서 오랜 시간에 걸쳐서 사용법을 알아내면 된다.

 

'PrintWriter'라는 클래스를 이용해보자

PrintWriter(생성할파일명) ()안에 생성할 파일명을 적고, new 키워드를 통해 'PrintWriter의 복제본(아바타)'를 만들어서 p1 이라는 변수에 담는다. "p1에는 반드시 PrintWriter라는 클래스의 인스턴스만 들어간다"는 뜻에서 데이터타입으로 PrintWriter를 지정해준다.

즉, 이 변수에 담긴 것을 PrintWriter라는 클래스의 인스턴스이다.

PrintWriter p1 = new PrintWriter(result1.txt);

 

PrintWriter 를 사용하려면 import하여 패키지를 가져와야 한다. (PrintWriter는 java.io 라는 패키지에 소속되어 있다.)

import java.io.PrintWriter;

 

※ 예외처리

파일을 처리하려는데 파일이 없는 상황과 같이 문제가 되는 경우를 "예외 상황"이라고 한다. 그러한 예외를 어떻게 처리할지에 대해서 정의해 줘야 한다.

예외를 배우기 전까진 [Add Throws declaration]을 선택해주자

 

[IOException - java.io] 서택

 

p1 인스턴스에 write() 메소드를 이용해 저장할 내용을 입력 후, p1에 대한 작업을 마쳤으면 close()를 통해서 더 이상 파일을 붙잡고 있지 않도록 처리하여, 다른 사람도 수정할 수 있도록 한다.

p1.write("Hello 1");
p1.close();

 

실행 후, 프로젝트를 Refresh 하면, result1.txt 와 result2.txt 파일이 생성된 것을 확인할 수 있다.

 

그렇다면 인스턴스는 무엇인가?

 

다음의 Math 클래스는 그냥 클래스에 변수 이름을 썼고, 클래스에 메소드를 썼다.

public class ClassApp {
	public static void main(String[] args) {
		System.out.println(Math.PI);
		System.out.println(Math.floor(1.6));
		System.out.println(Math.ceil(1.6));
	}
}

 

하지만 PrintWriter 클래스는 그냥 쓰지 않고, new를 통해서 복제한 결과를 변수에 담아서 사용하였다.

import java.io.FileNotFoundException;
import java.io.PrintWriter;

public class InstanceApp {
	public static void main(String[] args) throws FileNotFoundException {
		
		PrintWriter p1 = new PrintWriter("result1.txt");
		p1.write("Hello 1");
		p1.close();
		
		PrintWriter p2 = new PrintWriter("result2.txt");
		p2.write("Hello 2");
		p2.close();
		
	}
}

 

▶ 만약 인스턴스를 쓰지 않는다면 어떤 불편함이 있는가?

인스턴스를 쓰지 않고 그냥 사용한 (위 3줄의 코드와 동일하게 동작하는) 코드가 다음과 같다고 생각해보자(실제로 동작하지 않음)

//		PrintWriter p1 = new PrintWriter("result1.txt");
//		p1.write("Hello 1");
//		p1.close();
//		
	
		PrintWriter.write("result1.txt", "Hello 1");

 

그리고 이러한 작업이 일회성이 아니라 엄청나게 많이 이루어진다고 하면 우리 눈에 엄청나게 거슬리는 것이 있다.

 

write를 할 때마다 내가 어떤 파일을 수정할 것인지 그때그때마다 지정하고 있다.  이 PrintWriter는 PrintWriter 라는 클래스를 write 메소드가 서로 돌려쓰고 있다. 이건은 상당히 비효율적인 느낌이 든다.

 

위에 있는 PrintWriter 는 new를 통해서 인스턴스를 만들었고, 그 인스턴스는 내부적으로 각자의 상태를 가지고 있다.

(p1은 result1.txt , p2는 result2.txt 라는 내부적인 상태를 내장하고 있다.) 

인스턴스를 이용한다면 인스턴스명.write("내용"); 을 통해서 작업을 간편하게 할 수 있다.

 

따라서 Math와 같이 일회성 작업을 하는 클래스들은 그냥 사용하고, 파일을 수정하고 그 파일에 대한 여러 가지 작업들이 후속으로 따라오거나 동시에 여러 개의 파일을 작업해야 되는 경우에는 (하나의 클래스를 사용하는 것보다는) 클래스를 복제해서 각각의 다른 상태를 가지고 있는 인스턴스를 만들어서 사용하는 것이 더 효율적이다.

 

 

▶ Math와 PrintWriter는 어떤 차이가 있는지 매뉴얼을 살펴보자

PrintWriter에는 "Constructor"라는 생성자가 있다. Math와 같이 일회성 클래스는 Constructor 가 없다. 이런 Constructor를 이용해서 인스턴스를 만드는 것이 허용된다고 생각하면 된다. 

여러 Constructor 목록 중 우리가 사용했던 Constructor는 PrintWrite(STring fileName)이다.

 

해당 Contructor를 클릭하면 사용법을 볼 수 있다.

입력값으로 어떤 값으로 들어와야 하는지, 클래스를 사용하는 과정에서 생길 수 있는 오류는 어떤 것인지 (예를 들면 이 클래스의 경우 "FileNotFoundException" - "파일을 찾을 수 없을 때" 생기는 예외가 발생할 수 있다는 것을 알려주고 있다.

 

상속(Inheritance)

PrintWriter 클래스의 사용설명서를 살펴보자

PrintWriter (자식) 라는 클래스는 Writer (부모) 라는 클래스를 상속받았다.

 

java.io.Writer를 클릭해서 Writer 클래스를 살펴보자

Writer (자식) 클래스는 Object (부모) 라는 클래스를 상속받았다.

 

 

어떠한 기능을 만들 때 처음부터 끝까지 만드는 것은 어렵다. 그래서 PrintWriter 클래스를 만든 사람이 이미 만들어져 있는 Writer라는 클래스가 갖고 있는 메소드, 변수를 물려받으면서 거기에 자기가 원하는 메소드, 변수를 추가한 것이 PrintWriter 클래스인 것이다.

 

이클립스에서 PrintWriter 가 어떤 상속 관계를 가지고 있는지 살펴볼 수 있는 기능

Eclipse > 메소드명 우클릭 > [Open Type Hierarchy]

 

선택한 클래스의 상속관계를 보여준다. Object ----- 상속 -----> Writer ----- 상속 -----> PrintWriter

각 클래스에 존재하는 메소드와 변수 목록을 확인할 수 있다.

 

1. 상속받은 메소드 사용

Object에는 아주 중요한 toString() 이라는 메소드가 있다. Writer 클래스와 PrintWriter 클래스에는 toString() 메소드를 구현한 적 없지만 Object 클래스를 상속받았기 때문에, toString() 메소드를 사용할 수 있다.

 

※ class Object 

자바의 가장 기본적인 클래스

모든 클래스는 Object 클래스를 반드시 상속받는다.

 

class Writer extends Object

Writer 클래스는 Object 반드시 상속받아야 하기도 하고, Object 기능을 사용하기 위해서 상속받아 Writer 클래스를 생성하였다.

"Object 를 확장(extends)해서 Writer 클래스를 만들었다."라는 의미

 

class PrintWriter extends Writer

Writer 클래스를 상속받아 PrintWriter 클래스를 생성

 

이런 상속관계에서 PrintWriter의 인스턴스를 만들고 그 인스턴스에 toString() 하면, toString이 Object에 있는 상황에서, 자바는 먼저 PrintWriter 클래스에 toString 메소드가 있는지 확인 후, 없으면 Writer 클래스를 확인한다. 그리고 없으면 extends 가 가리키는 Object 메소드를 확인해서 Object에 구현되어있는 toString 메소드를 사용하게 된다. (없다면 에러 발생)

 

2. 상속받은 메소드 재정의 - override

Writer 클래스에는 write(String) 입력값으로 String 값을 받는 메소드가 정의되어 있다.

그리고 PrintWriter 클래스에도 write(String) 입력값으로 String 값을 받는 메소드가 정의되어 있다. 즉, PrintWriter 클래스에 write() 라는 메소드는 Writer 클래스의 write()메소드를 덮어쓰기 하여 구현한 것이다.

 

p1.write("Hello World"); 라고 하면, 자기가 속해있는 PrintWriter 의 write()메소드를 사용하게 된다. 이러한 관계를 "Override 했다."라고 한다. 

 

 

자바 공식 사용 설명서에 [Tree] 에서 상속 관계를 나무 모양으로 볼 수 있다.

자바가 기본적으로 제공하는 표준 라이브러리의 클래스들이 서로 간에 어떤 상속 관계를 맺고 있는가를 보여준다. 그리고 그 최상위에는 Object 가 있다. 이 Object 가 갖고 있는 메소드 들을 모든 클래스가 공통적으로 사용할 수 있는 메소드 이기 때문에 Object 클래스가 갖고 있는 메소드의 의미와 쓰임을 알아보면 좋다.

 

 

Writer 클래스를 상속받은 자식들 중에 알려진 클래스들의 목록

 

lock 이라는 변수(Field)가 Writer 클래스에 정의되어 있고, 그것을 상속받아서 이 PrintWriter도 lock이라는 필드를 사용할 수 있다.

 

Object 클래스가 갖고 있는 아래 메소드들을 상속받았기 때문에 사용 가능하다고 알려주고 있다.