Java API Documentation 보는법

2020-08-29

.

JAVA_TIL(20200829)

  • study program : youtube 생활코딩 채널 ‘JAVA1’

# API vs UI

  • 우리가 컴퓨터를 사용하려면 컴퓨터가 있어야 하는데 컴퓨터를 직접사용하는 것이 어렵기 때문에 운영체제를 설치한다. 그리고 그 운영체제 위에 자바라는 프로그래밍 언어를 설치했다. 그리고 이 자바를 이용해서 나의 프로그램을 만든 것이다.

  • 자바는 사용자가 프로그램을 쉽게 만들 수 있도록 여러가지 부품을 제공한다. 예를 들어서 화면에 뭔가 출력하고 싶을때 systemoutprinln 이라는 것을 썼고, 날짜는 data, 수학적인 기능은 math를 사용할 수 있다. 이렇게 자바가 기본적으로 내장하고 있는 기능들을 기본 라이브러리라고 부른다.

  • 우리는 이런 라이브러리들을 이용해서 나만의 자바 프로그램을 만드는 것이다. 자바가 제공하는 기본적인 문법을 통해서 시간의 순서에 따라 자바가 제공하는 라이브러리를 실행하는 프로그램을 만들 수 있다.

  • 이런 맥락에서 자바가 기본적으로 제공하는 부품들의 조작방법을 Application Programming Interface(API)라고 부른다. Program이라는 것은 시간의 순서에 따라 실행된다는 의미가 강조된 단어이고, application이라는 것은 자바가 제공하는 부품들을 응용한다는 응용의 의미가 강조된 단어다. 따라서 우리가 자바를 응용해서 프로그래밍적으로 실행되는 프로그램을 만들기 위해서 사용해야하는 조작장치, 조작방법을 API라고 부르는 것이다.

  • 그래서 프로그램을 잘 만들기 위해서는 어떤 API가 있고, 그 API는 어떻게 조작하는가를 잘 알고 있어야 한다. 그래서 우리가 자바 프로그램을 만들어서 다른 사용자들이 사용되게 된다면 그거를 사람이 우리가 만든 프로그램을 조작하기 위한 조작 장치가 있을텐데 이 조작장치를 User Interface라고 부른다.

image

  • 동시에 우리가 만든 프로그램은 사람이 사용하지 않을 수도 있다. 무슨말이냐면 우리가 만든 프로그램을 하나의 부품으로하여 또 다른 프로그램이 만들어질 수도 있다는 것이다. 그럴경우에는 우리의 프로그램이 우리의 프로그램을 사용하는 완제품을 만드는 프로그램에게 API를 제공해야 한다.

image

# 패키지, 클래스, 변수, 메소드

  • 구글에 api documentation java 라고 검색하면 https://docs.oracle.com/javase/7/docs/api/ 와 같은 사이트를 찾을 수 있다. 자바가 기본적으로 제공하는 라이브러리에 대한 도큐먼트다.

image

  • 사이트에 접속하면 좌측에 All classes 메뉴가 있다. class는 하나의 프로그램으로 생각하면 된다. 여기에서 수학과 관련된 어떤 작업을 해야하는데 직접만들기 싫다 그러면 math를 검색해서 math class를 찾을 수 있다.

image

  • Class Math 제목위에 java.lang라고 표시되어 있는데 이건 무슨말이냐면 math class가 소속된 패키지를 말하는 것이다. class의 숫자가 엄청 많아지면 정리정돈을 해줘야 할 필요가 있는 것이고 그런 차원에서 복수개의 클래스를 하나의 패키지로 묶는 경우가 많다.

  • 또한 이미 math라고 하는 클래스가 있는데 내가 나만의 math라는 class를 만들고 싶다고 하면 똑같은 math라는 이름의 클래스가 같은 공간에 있으면 충돌이 날 것이다. 그래서 이런문제를 해결하기 위한 정리정돈의 도구이다. 화면 좌측상단에 Packages 메뉴가 있어서 package 목록을 쭉 확인할 수 있다.

  • 그러면 java.lang 패키지를 검색해보자. 검색해보면 아래 그림과 같이 java.lang에 속해있는 class들의 목록을 쭉 볼 수 있다.

image

  • 패키지는 비슷한 성격의 class들을 모아서 이름을 붙인것이다 라고 보면 된다. 그러면 class는 뭐냐 클래스는 서로 연관된 변수와 또 메소드라는 것을 모아서 거기에다 이름을 붙인것이다. math class 도큐먼트에 들어가면 아래 그림과 같이 변수와 메소드 정보들이 있는 것을 확인할 수 있다.

image

  • 아래 그림은 지금까지 공부한 내용을 도식화한 것이다.

Class : 변수와 메소드를 그룹핑한 것

Package : 비슷한 성격의 class들을 그룹핑한 것

image

# 클래스

수학과 관련된 어떤 작업을 하는데 3.14 파이의 값이 정확하게 기억이 안난다고 가정하자.

자바는 수학과 관련된 작업을 할때 도움을 주기 위해서 기본적으로 수학과 관련된 내장함수가 있다.

그 클래스 이름이 Math이다. 아래 코드와 같이 Math.PI를 입력하면 이것은 3.14…라고 하면 파이의 구체적인 값이 적절한 정밀도로 저장되어 있는 변수 PI이다. 그 PI가 Math라는 클래스 안에 소속되어 있는 것이다.

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

[ClassApp 실행결과]
3.141592 ...

어떤 정보를 알고 싶은것 뿐만아니라 어떤 정보를 처리하고 싶을때도 있을것이다.

예를 들어서 1.6이라는 정보가 있는데 여기서 0.6을 무조건 없애고 싶다라고 할때 수학에서는 내림을 쓰면 된다.

이럴때는 아래 코드와 같이 Math.floor()메서드를 쓰면 된다.

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

[ClassApp 실행결과]
1.0

## 올림을 하고 싶을때
public class ClassApp{
    public static void main(String[] args){
        System.out.println(Math.ceil(1.6));
    }
}

[ClassApp 실행결과]
2.0

클래스는 서로 연관된 변수와 메서드들을 모아서 거기에 이름을 붙인거라고 할 수 있다.

# 인스턴스

result1.txt에다가 hello1이라는 텍스트를 자바를 이용해서 작성해보려고 한다. PrintWriter라는 도구를 이용할 것이다.

그렇게 하려면 어떤 클래스가 필요한지, 활용법은 어떻게 되는지 확인해야 한다.

# PrintWriter는 내장함수이기는 하지만 Package를 import해주는 작업이 필요하다.
# 가져오고자 하는 PrintWriter는 아래소스에서 PrintWriter라는 이름의 클래스는 java.io 패키지에 속해있는것이다.
# 라는 것을 명시한 것이다.
import java.io.PrintWriter;

public class InstanceApp{
    # throws IOException를 붙여줘야 한다 왜냐하면 result1.txt가 없으면 문제가   있기 때문이다.
    # 이런 예외를 어떻게 처리할지에 대해서 'ADD throws declaration' 옵션을 준것이다.
    public static void main(String[] args) throws IOException{
        
        # new PrintWriter("result1.txt") p1이라는 변수에 할당시켰다.
        # 그러면 p1에 할당된 변수는 PrintWriter라는 클래스의 인스턴스라고 한다.
        # 그리고 p1은 아무거나 저장되면 안되기 때문에 데이터 타입으로 앞에 PrintWriter라는  붙여줬다.
        # PrintWriter 클래스 인스턴스만 저장된다는 의미다.
        PrintWriter p1 = new PrintWriter("result1.txt")
        p1.write("Hello 1")
        p1.close();
        
        PrintWriter p2 = new PrintWriter("result2.txt")
        p1.write("Hello 2")
        p1.close();
        
    }
}

[InstanceApp 실행결과]
result1.txt, result2.txt가 생성되고 각각의 파일내용에 Hello 1, hello2가 적혀있을 것이다.

그러면 인스턴스는 뭔지에 대해 얘기해보자.

PrintWriter는 그냥쓰지 않고 그것을 복제한 결과를 p1에 담았다. 왜 이렇게 했을까

만약에 result파일을 수만개를 만들어야 한다고 가정하자. 위와 같이 변수를 할당하지 않고 아래와 같이 일일히 수동으로 코드를 작성해야하는 참사가 발생할 것이다.

import java.io.PrintWriter;

public class InstanceApp{
    public static void main(String[] args) throws IOException{
        
        PrintWriter.write("result1.txt","hello 1");
        PrintWriter.write("result2.txt","hello 2");
        PrintWriter.write("result3.txt","hello 3");
        PrintWriter.write("result4.txt","hello 4");
        
        ...
        
        수만개?
    }
}

PrintWriter p1 = new PrintWriter("result1.txt")는 new를 통해 인스턴스를 만들었고, 인스턴스는 내부적으로 각자의 상태를 갖고 있다. 예를 들어서 p1은 result1.txt, p2는 result2.txt라는 내부적인 상태를 내장하고 있다. 따라서 p1.write하게 되면 result1.txt에 대한 write가 되는 것이고, p2.write하게 되면 result2.txt에 대한 write가 일어나는 것이다.

우리가 어떤 파일을 수정한다고 하면 그 파일을 수정만 하고 끝나는게 아니라 파일을 열고 쓰고 닫는 일련의 다른 후속작업들이 같이 필요하다. 또한 여러개의 파일을 수정해야 할수도 있다. 그럴때는 하나의 클래스를 앞에 new를 붙어서 복제해서 각각의 다른 상태를 가지고 있는 인스턴스로 만들어서 사용하는 경우 더 효율적일수 있다.

PrintWriter 클래스 도큐먼트에 가보면 constructor(생성자)라는게 있고 그것에 대한 설명이 있다. 반면에 math 클래스는 constructor라는게 없다. constructor(생성자)가 있다는 것은 constructor(생성자)를 이용해서 인스턴스를 만드는 것이 허용되어 있다는 것이다.

constructor(생성자)를 어떻게 쓰는지는 클릭해보면 설명이 다 나온다. constructor(생성자)의 입력값으로는 어떤게 들어와야 되는지에 대한 설명이 있고, 저 클래스를 사용하는 과정에서 생길 수 있는 error에 대한 설명이 있다. 여기서는 파일을 찾을 수 없을때 예외를 알려주고 있다.

image

어떤 클래스를 사용할때 그 클래스를 만든사람이 그 클래스를 인스턴스로서 사용하기를 원한다면 constructor(생성자)를 가지고 있다. PrintWriter(“result1.txt”)가 constructor(생성자) 인것이고 앞에 new를 붙이게 되면 이게 복제가 되어 p1 인스턴스를 만들 수 있고, p1에 대한 어떤 값이 올 수 있냐에 대한 규제를 하기 위해서 앞에다가 PrintWriter라는 이름을 붙인 것이다.

# 상속

image

PrintWriter 도큐먼트를 보면 java.io.PrintWriter 바로위에 java.io.Writer라는게 보일것이다. PrintWriter라는 클래스는 Writer라는 클래스를 상속받았다. 즉 PrintWriter는 자식이고 Writer는 부모이다.

java.io.Writer를 클릭해서 들어가보면 아래 그림과 같이 java.lang.Object 클래스를 상속받았다고 나와있다.

image

그러면 지금까지 얘기한게 무슨얘기냐 하면 우리가 어떤 프로그램을 만들때 처음부터 끝까지 모든기능을 만들기는 어렵다고 했다. 그래서 PrintWriter를 만든 사람도 처음부터 끝까지 다 자기가 만들기 싫어서 기존에 이미 있던 Writer라는 클래스가 갖고 있는 메소드, 변수를 그대로 사용하면서 거기에 자기가 원하는 메소드와 변수를 만든것이다. 마찬가지로 Writer를 만든사람도 Object클래스에 있는 메소드와 변수를 그대로 사용하면서 자기가 원하는 기능을 만든 것이다.

아래 그림과 같이 이클립스에서 PrintWriter를 마우스 오른쪽 클릭한 다음 Open Type Hierarchy를 클릭하면 상속관계를 볼 수 있다. 각각의 클래스에 어떤 변수가 있고 어떤 메소드가 있는지도 확인할 수 있다.

image

지금까지 정리한 내용을 도식화 하면 아래 그림과 같다.

image

기본 클래스인 Object 클래스가 있고 Object 클래스를 이용해서 Writer를 구현한 클래스가 있다. object 클래스를 확장해서 Writer 클래스를 만들었다는 것이다. 그리고 나서 또 누군가가 PrintWriter 클래스를 만들었는데 처음부터 끝까지 전부 만든게 아니라 Writer 클래스를 이용해서 구현한 클래스이다. 다시말해서 Writer 클래스를 확장해서 PrintWriter를 만든것이다.

여기서 아래와 같은 코드가 있다고 하면

PrintWriter p1 = new PrintWriter("result1.txt");

p1.toString()

PrintWriter 클래스에 toString() 메소드가 있는지 확인해보고 없으면 PrintWriter가 상속받은 Writer 클래스에서 찾아본다. 거기에도 없으면 Object 클래스에서 찾아본다. 만약에 없으면 Error가 날 것이다.

Open Type Hierarchy에서 가만히 보면 Writer 클래스에 write() 메서드가 있고, PrintWriter에도 똑같은 이름의 write() 메서드가 있다. PrintWriter 클래스를 만든사람이 Writer클래스에 있는 write() 메서드가 마음에 안들었는지 그거를 가져다가 뭔가 기능을 추가했던 아니던 간에 메서드를 덮어씌운것이다.

그러면 아래코드에서 write()메서드는 어떤 클래스의 Write() 메서드일까. PrintWriter 클래스의 메서드이다.

import java.io.PrintWriter;

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

위에서 언급한 내용을 도식화 하면 아래와 같다.

image

PrintWriter 클래스를 만든사람이 Writer클래스에 있는 write() 메서드가 마음에 안들었는지 그거를 가져다가 뭔가 기능을 추가했던 아니던 간에 메서드를 덮어씌운 것을 override 라고 부른다.

자바 도큐먼트에도 Tree 메뉴가 있는데 아래 그림과 같이 상속관계를 트리형식으로 보여준다. 어마어마하게 많은 정보가 있는데 자바가 기본적으로 제공하는 표준 라이브러리 클래스들이 서로간에 어떤 상속관계를 맺고 있는가를 보여준다. 그 정점에 Object 클래스가 있다. 이 Object 클래스는 메소드들은 모든 클래스가 공통적으로 사용할 수 있는 메소드이다.

그 다음에 아래 그림에서 Writer 클래스 메뉴에서 Direct Knwon Subclasses 라고 되어 있는 것은 Writer 클래스를 상속받은 클래스중에 유명한 것들에 대한 예시 목록을 보여주는 것이다. 나도 Writer 클래스를 상속받아서 나만의 클래스를 만들 수 있다.

image

참고로 자바에서 변수는 Field라고 부르기도 한다.

ex) 설명서에서 일부 메뉴 해석법

Fields inherited from class java.lang.클래스이름 : 특정 클래스에 정의된 변수를 상속받았기 때문에 해당되는 변수를 그대로 사용할 수 있다.

Methods inherited from class java.lang.클래스이름 : 특정 클래스에 정의된 메소드를 상속받았기 때문에 해당되는 메소드들을 그대로 사용할 수 있다.