본문 바로가기

자바 프로그래밍/1장. 자바 프로그래밍이란

4. 자바 언어의 특징

반응형

자바의 컴파일된 결과물은 실행코드(기계어 코드)가 아니어서 바로 실행할 수는 없다. 그것을 실행하려면 java.exe 도구를 이용해야만 하는데, 그 이유는 자바의 탄생배경과 관련이 되어있다. 

 

그렇다면 자바는 어떤 목적으로 나왔으며 그래서 어떤 특징을 가지고 있는지 알아보도록 하자.

4-1 자바의 탄생배경

자바가 탄생하던 1990년 초만 해도 가전에 프로그램을 심는다는 생각은 아주 생소한 시기였다.

 

 

그런 시기에 자바를 만든 Sun Microsystems 회사에서는 TV에 프로그램을 심어서 주문이 가능한 양방향 통신이 가능한 TV를 만들 생각을 하였다. 물론 지금은 이미 구현이 되어 사용하고 있기 때문에 신기할 것도 없는 기능이지만 말이다.

 

그런 발상을 할 수 있었던 이유는 미국은 TV를 케이블로 시청하고 있었기 때문이다.

 

공중파로 TV를 시청하던 한국과 달리 미국은 땅이 크고 지역간의 거리가 멀어서 공중파 대신 케이블을 이용하는 것이 효율적이었다.

 

그래서 그런 인프라를 활용해서 양방향 통신이 가능한 TV를 생각할 수 있었는데, 얼마지나지 않아 그 생각은 TV를 넘어서서 모든 가전으로 대상을 확대하고 WORA(Write Once Run Anywhere - 한번 만든 프로그램이 어떠한 환경에서도 실행될 수 있는)가 가능한 프로그래밍 환경을 위해 Green Project 팀을 구성하였다.

 

 

이 사진이 그 때의 초창기 팀 사진인지는 확실하지 않치만 주요한 인물 두 명이 모두 포함되어 있기는 하다.

 

동그라미로 표시된 두 인물 중에서 왼쪽 인물이 이 팀의 초기 리더인 패트릭 노튼(Patrick Naughton)이며 그 오른쪽이 자바의 아버지라 불리는 제임스 고슬링(James Gosling)이다.

 

Green Project의 초기는 패트릭 노튼이 진행하던 프로젝트 였고 그 때의 프로젝트 이름은 Stealth Project 였다. 하지만 곧 마이크 쉐르단(Mike Sheridan)과 제임스 고슬링이 참여하면서 프로젝트 이름은 Green Project로 바뀌었다.

 

그린 프로젝트의 목표는 모든 전자기기에서 돌아갈 수 있는 플랫폼을 만드는 것이었다. 이 프로젝트의 초창기에는 플랫폼의 메인 언어로 C++를 고려하였으나 패트릭 노튼은 C++의 문제점들로 골머리를 앓았다고 한다.

 

A) 패트릭 노튼이 지적한 C++의 단점

  • 언어의 구문이 복잡하여 단일한 문제에 대해서 너무 다양한 코드 작성이 가능하고 
  • 메모리 관리를 프로그래머에게 맡기고 있어서 실수의 위험성이 크며
  • 크로스 플랫폼(이기종 환경에서의 동작)을 지원하는데 제약사항이 있다.

 

그럼에도 불구하고 초기에 C++을 생각했던 이유는 제한된 환경에서 동작하는 프로그램을 만들어야 하는 것 때문이었는데, 그것을 포기하고 새로운 언어를 만들기로 해서 탄생한 언어가 자바이다.

 

4-2 자바 언어적인 특징

자바 언어는 C++ 언어를 기반으로 만들어졌으며 앞서 지적된 사항들을 제거하는 것을 기본으로 한다. 그래서 C++과 비교했을 때 자바에는 다음과 같은 특징들이 사라졌다.

 

  • 객체 제거하는 delete 키워드 제거
  • 참조와 포인터 중에서 포인터 제거
  • 데이터 구조를 정의하는 struct와 class 중에서 struct 키워드 제거
  • 함수를 클래스 밖에서 정의할 수 있는 구문 제거

 

이렇듯 자바는 C++이 가지고 있는 기능 중에서 문제가 될 만한 구문들을 제거하였다. 그래서 자바의 특정에서 제일 먼저 꼽는 특징은 “간결성”이다. 

 

모든 기능을 제거만 한 것은 아니다.  C++에는 없던 추가된 내용도 있고 개선된 내용도 있다.

 

  • 콜렉션을 언어에 포함하였다.
  • 글로벌한 문자를 처리할 수 있는 인코딩이 포함되었다.
  • 완전한 객체지향 언어가 되도록 하였다.

 

콜렉션이란 많은 데이터를 수집하나 관리해주는 라이브러리로써 그 당시 C++에서는 외부라이브러리로 있었을 뿐 언어에는 포함되지 않은 상태였다. 그리고 C++은 객체를 반드시 정의할 필요없었기 때문에 함수를 클래스 없이 정의할 수 있었다. 자바에서는 모든 함수는 반드시 클래스 블록 안에만 정의할 수 있게 하였다.

 

그래서 자바 언어의 대표적인 특징을 꼽으라고 하면 다음처럼 말할 수 있을 것이다.

 

  • 간결성
  • 언어에 콜렉션을 포함
  • 완전한 객체지향 언어

 

4-3 자바 번역기의 특징

자바 언어로 만든 프로그램은 WORA를 목표로 만들어졌다. 그래서 자바 프로그램이 어떤 CPU 환경으로 배포가 되든 그것은 문제없이 실행될 수 있어야만 한다.

 

하지만 그것은 그리 간단한 문제가 아니다. 자바의 모태인 C++은 컴파일러를 사용하는 언어이다. 그래서 컴파일을 거치고나면 특정 CPU에서 바로 실행할 수 있는 기계어가 만들어진다.

 

위와 같이 컴파일을 마친 최종 결과물은 CPU가 바로 실행할 수 있는 특정 CPU의 코드로 만들어진다. 

 

위의 그림에서 오른쪽은 서로 호환이 안되는 INTEL CPU와 애플의 M1 CPU를 보여주고 있다.

 

만약에 컴파일을 INTEL CPU에서 수행했다면 그 결과물인 실행 파일은 INTEL CPU에서만 동작할 것이고 M1 CPU에서 했다면 M1 CPU에서만 동작할 것이다. 이것은 Green Project 팀이 바라는 WORA가 아닌 것이다.

 

그것을 가능하게 하는 유일한 방법은 컴파일러를 번역기로 사용하지 않고 인터프리터를 사용하도록 하는 것이었다.

4-4 컴파일러와 인터프리터

자바로 언어로 작성한 코드를 실행하려면 그것을 기계어로 번역해주어야만 한다. 그 때 사용하는 번역기를 컴파일러라고 하였다. 그런데 컴파일러 말고 인터프리터(Interpreter)라는 번역기도 존재한다.

 

인터프리터는 번역기 역할도 하지만 번역이 주목적이 아니라 코드를 바로 실행시켜주는 것을 목적으로 한다. 

 

이 번역기는 소스코드를 바로 실행해주기 위해서 소스코드 전체를 번역하지 않고 당장 실행에 필요한 블록부터 번역해서 실행하도록 도와주며 추가적으로 더 필요하면 그때그때마다 번역을 하면서 실행을 시켜주는 것을 도와준다. 

 

인터프리터는 필요한 것만 번역할 뿐 전체코드를 번역하지 않기 때문에 번역된 결과물을 남기지 않는다. 그래서 인터프리터의 또 다른 이름을 JIT(Just In Time) Compiler라고 부르기도 한다.

 

컴파일러와 인터프리터의 특징은 마치 인터넷을 통해서 영화를 보는 두 개의 방법과 비교될 수 있다.  인터넷 영화를 볼 때는 전체 파일을 다운로드 받아서 보는 방법(= 컴파일러를 사용하는 방법)과 필요한 부분만 그때그때 받아서 바로 보는 스트리밍 방법(=인터프리터)으로 나누어 볼 수 있다.

 

영화 전체 파일을 받아서 본 상태에서 다음에 영화를 또 보고 싶다면 이전에 다운로드했던 파일을 바로 보면 된다.  반면에 스트리밍으로 영화를 본 상태에서 다음에 영화를 또 보고 싶다면 이전에 다운로드 받았던 것이 남아있지 않기 때문에 영상을 다시 내려 받아서 봐야만 한다. 

 

이와 유사하게 소스코드를 컴파일러로 번역하고 실행한 상태에서 다음에 또 실행하고 싶다면 이전에 번역했던 결과물을 바로 실행하면 된다. 반면에 인터프리터로 번역하고 실행한 상태라면 매번 실행할 때마다 다시 번역해서 실행해야만 한다.

 

프로그램을 배포할 때 수행성능을 생각한다면 컴파일한 결과물을 배포하는 것이 바람직하다. 하지만 인터프리터를 사용함으로써 얻는 커다란 장점을 무시할 수는 없다.

 

4-5 인터프리터 언어의 장점

 

C++ 처럼 컴파일러를 이용해 실행 파일을 배포하는 방법은 WORA(한번 만든 프로그램이 어떠한 환경에서도 실행될 수 있는)를 구현할 수가 없다. 왜냐하면 번역된 결과물은 특정 CPU에서만 동작하기 때문이다.

 

 

그래서 CPU 에 상관없이 프로그램이 모든 곳에서 동작하려면 컴파일된 코드가 아니라 소스코드를 배포하는 수 밖에 없다.

 

 

이렇게 소스코드를 받아서 바로 실행하는데 도움을 주는 번역기가 인터프리터이다.

 

4-6  인터프리터와 가상머신

 

자바 언어는 그 탄생 목적이 모든 가전에서 동작하는 프로그램을 만들기 위한 것이기 때문에 그것을 만족하기 위해서 자바도 인터프리터 언어로 만들어 질 수 밖에 없었다.

 

그래서 자바는 컴파일러를 사용할 필요없이 인터프리터를 이용하여 소스코드를 바로 실행할 수 있다.

 

 

일전에 컴파일한 Program.class 파일을 삭제해보자. 그리고 명령 프롬프트 창을 열고 다음처럼 소스코드를  바로 실행해보도록 한다.



C:\Users\newlec>cd c:\Workspace

c:\Workspace>java Program.java
total is 140
avg is 46.000000

c:\Workspace>

 

실제로 바로 실행할 수 있음을 확인 할 수 있다.





가상 머신(Virtual Machine)은 리얼 머신(Virtual Machine)의 반대되는 의미이다. 여기서 머신이란 코드를 실행해주는 실행자를 말하는데, CPU를 의미하는 말이다. 그런 면에서 java.exe는 소스코드를 실행해주는 역할을 하고 있으니 머신은 머신인데 실제 CPU는 아니므로 “가상”이라는 말을 붙여서 가상 머신이라고 부른다.

 

가상머신은 코드를 실행시키기 위해서 인터프리터(JIT Compiler)를 내장하고 있으며 코드를 로드하는 기능, 로드 되는 클래스의 유효성을 검사하는 기능, 메모리를 관리해주는 기능 등을 내장하고 있다.

 

4-7 자바는 컴파일 언어인가? 인터프리터 언어인가?

 

자바 컴파일러는 사실 C++ 컴파일러처럼 기계어를 만드는 번역기는 아니다. 다만 수행성능을 개선하기 위해서 보조적으로 사용하는 번역기이다.

 

C++ 컴파일러의 번역과정은 위의 그림처럼 6단계를 거쳐서 기계어를 만들어낸다. 

 

기호들을 모두 분쇄해서 형태소를 파악하고 그 순서가 올바른지 구문분석을 하고 그것이 어떤 연산인지를 파악한 후에 중간코드(Intermediate Language 코드)를 만든다.

 

여기까지는 아직 CPU와는 무관한 결과물을 만든다. 이후부터는 CPU에 종속되는 최적화가 이루어지고 CPU 장치의 언어로 번역이 이루어진다.

 

자바 컴파일러는 그림의 4단계인 중간코드 까지만 번역한다. 그래야만 특정 CPU에 종속되지 않기 때문이다.  그 중간까지만 번역된 결과물이 클래스 파일(Program.class)이다. 

 

이 파일은 클래스 파일이라고도 하지만 중간까지만 번역된 파일이기 때문에 “중간코드(IL) 파일”이라고 부르기도 한다. 또는 중간 코드가 모두 1 Byte 크기로 이루어졌기 때문에 “바이트 코드” 파일 이라고 부르기도 한다. 그 외에도 실제 실행되는 코드가 아니기 때문에 가짜 코드라는 의미로 “슈도 코드” 파일이라고 부르기도 한다.

 

그렇다면 번거롭게 컴파일러를 사용하지 말고 그냥 소스파일을 배포하면 더 좋은 것이 아닐까? 그렇지 않다.

 

클래스 파일(Program.class)을 실행할 때와 소스파일(Program.java)을 실행할 때의 속도차이는 인간이 그 차이를 느낄 정도로 간극이 크다.

 

실제로 두 방법으로 코드를 각각 실행시켜 보도록 하자. 

 

다음은 컴파일하고 그 결과물을 실행하는 방법을 보여주고 있다.

 

c:\Workspace>javac Program.java

c:\Workspace>java Program
total is 140
avg is 46.000000

 

다음은 소스코드를 바로 실행하는 방법을 보여주고 있다.

 

c:\Workspace>java Program.java
total is 140
avg is 46.000000

 

아마도 두 방법을 직접 실행해보면 속도차이를 느낄 수 있을 것이다.

 

컴파일러를 사용할 때의 장점은 실행속도 뿐만 아니라 컴파일 과정에서 발생할 수 있는 구문오류도 확인할 수가 있다. 

 

그래서 배포하기 전에 오류를 체크하고 바로 잡을 수 있는 시간을 가질 수가 있다. 이것은 좀 더 안전한 프로그램을 만드는데 아주 중요한 특징이라고 할 수 있다.

 

결과적으로 자바는 컴파일러와 인터프리터 모두를 사용함으로써 둘 모두의 장점을 가지는 복합형 언어로서 현대적인 언어라고 할 수 있다.

 

4-8 자바는 고급 언어이다.

 

컴퓨터 프로그램을 만드는 방법이 처음부터 컴파일러나 인터프리터를 이용하는 방식은 아니었다.

 

처음에는 기계의 스위치 상태를 숫자로 표현하는 기계어(Machine Language)를 사용했었다. 

 

그 후에 코드 생산성을 높이기 위해서 기계의 기능을 숫자 대신 문자로 된 명칭으로 프로그램을 만들기 시작하고 번역기를 통해서 기계어로 변환하였다. 이 때 사용하는 번역기는 컴파일러가 아닌 어셈블러(Assembler)이다.

 

참고로 기계장치가 제공하는 기능집합을 Assemble이라고 하고 그것으로 만들어진 언어를 어셈블리어(Assembly Language)한다. 그리고 어셈블리어로 만든 코드를 기계어로 번역해주는 번역기를 어셈블러라고 한다.

 

그 후에 시간이 더 흐른 뒤에 현재 우리가 사용하는 컴파일러와 같은 좀 더 복잡한 번역기가 등장하였다. 이 번역기는 수학식을 닮은 구문을 작성하면 그것으로 어셈블리어 코드로 번역해준다.

 

이 번역기의 등장으로 프로그래머는 기계에 대한 이해보다는 수학식의 이해가 더 요구되는 시대에 살게 되었다.

 

 

이렇게 컴퓨터 프로그램을 만드는 언어는 시간이 흐르면서 달라져왔고 이 언어들을 세대로 구분하기도 하고 장치와 관련되는 기준에 따라서 구분하기도 한다.

 

위의 언어들을 세대로 구분하면 기계어는 1세대 언어, 어셈블리어는 2세대 언어, 자바처럼 컴파일러나 인터프리터를 사용하는 언어는 3세대 언어라고 한다.

 

또한 번역기를 사용하는 언어의 종류를 구분하기 위해서 어셈블러를 이용하는 언어를 저급언어, 컴파일러나 인터프린터를 사용하는 언어를 고급언어라고 한다.

 

기계어나 어셈블리어는 기계장치의 기능과 연관되어 있기 때문에 물리언어라고 하고 자바와 같은 언어는 논리언어라고 구분하기도 한다.

 

이 외에도 이 언어들을 구분하기 위한 용어들은 많다. 이 모든 용어들을 외우려고 하기 보다는 상황에 따라서 달라지는 개념만 가지는 것이 중요하다.







(아직 작성중...일단 진도에 맞추어서 다음 내용부터….나중에 다시 보충 예정)

 

반응형