프로그래밍언어 자바 Part-1

2. 자바 기본문법-1

이번 강좌에서는 자바 프로그램의 기본구조와 변수, 메서드, 연산자, 분기문등 기본 문법 요소를 배웁니다.

이 강의를 통해 자바언어의 구조를 이해하고 기본 문법을 활용해 기초적인 자바 프로그램을 작성하고 실행할 수 있습니다.

강의를 시작하기 전에 자바 개발환경 구축을 먼저 완료하기 바랍니다.



Note: 공통사항 -> 프로그래밍언어개요 를 먼저 학습한 다음 시작하기 바랍니다.

01: 자바 프로그램 구조

자바 프로그램은 기본적으로 클래스 구조에서 시작 합니다. 클래스는 객체지향 개념에서 객체를 정의하는 틀로서 많은 객체지향 프로그램 언어의 기본 구조 입니다.

객체지향과 관련한 보다 자세한 사항은 4.객체지향과 자바 에서 자세히 배우게 됩니다. 여기서는 구성요소들에 대해 전반적으로 이해하는 정도로만 살펴 봅니다. 클래스의 기본 구성요소는 변수메서드 입니다.

다음은 가장 기본적인 자바 프로그램의 구조 입니다.

// 클래스 선언
public class MyClass {
    // 변수 선언
    int num1;
    Message msg;

    // 메서드
    public void printName(String name) {
        ...
    }

    // 메서드
    public Message getMessage() {
        ...
    }

    // 메인 메서드
    public static void main(String[] args) {
        // 클래스 인스턴스 생성
        MyClass mc = new MyClass();
        ...
    }
}

클래스(Class)

객체지향 프로그램의 기본 구조로 자바에서 모든 프로그램 소스는 클래스 단위로 시작하게 됩니다.

인스턴스(Instance)

클래스로 부터 생성된 객체로 클래스는 객체를 정의한 틀이고 실제 프로그램은 인스턴스를 통해 동작하게 됩니다.

변수(Variable)

일반적인 프로그램언어의 변수와 기본 개념은 같습니다.

메서드(Method)

일반적인 프로그램언어의 함수와 유사합니다. 함수는 단순한 기능을 모듈화 한것이지만 메서드는 객체의 동작(행위)을 정의 합니다.

주석(Comment)

대부분의 프로그램언어와 같은 주석을 지원하며 JavaDoc 과 같은 특수한 목적의 주석이 있습니다.

// 한줄 주석
/*
    여러줄 주석
*/
/**
    JavaDoc 주석
*/

자바 식별자(Identifier) 규칙

변수, 상수, 메서드, 클래스 등을 선언할때의 일반적인 이름 규칙 입니다.

식별자 생성 관례(Coding convention)

문법적인 제한사항은 아니지만 일반적으로 다음과 같은 관례로 생성 합니다.

» 실습: 자바 프로그램 기본 구조

실습개요

이클립스를 이용해 클래스를 생성하고 간단한 출력문을 이용한 프로그램을 구현한다음 실행해서 결과를 확인하는 과정을 살펴 봅니다.

인스턴스 생성과 변수 및 메서드 사용 예제는 02:변수와 메서드에서 살펴보게 됩니다.

소스코드

public class HelloWorld {
	public static void main(String[] args) {
		System.out.println("Hello World!!");
	}
}

실행결과

Hello World!!
Note: 상세 실습 과정은 동영상 강좌에 포함되어 있습니다.


02: 변수와 메서드

1) 변수

변수는 데이터를 저장하기 위한 메모리 공간에 대한 이름으로 저장할 데이터의 크기를 알아야 필요한 공간을 확보할 수 있습니다. 따라서 적절한 자료형을 사용하는 것은 매우 중요합니다.

다만 객체지향 프로그램 언어에서는 클래스 타입을 자료형으로 사용할 수 있으며 최근에 나오는 언어들의 경우 메모리 공간의 크기를 계산하기 위한 용도라기 보다는 타입을 구분하는 개념으로 접근하고 있습니다. 나아가 타입에 대한 추론을 통해 개발자가 타입에 신경쓰지 않고 코딩을 할 수 있도록 지원하고 있습니다.

자바의 경우 원시 자료형(Primitive Type)과 클래스 타입(Class Type)을 모두 지원 하고 있으며 원시 자료형에 대한 클래스 타입들은 랩퍼 클래스(Wrapper Class)라고 합니다.

변수 선언 방법

[접근제어자] 타입 변수명
int num1 = 10;      // 원시자료형 정수 타입
String msg = "Hello";   // 객체타입 문자열 타입
Member member = new Member();   // 객체타입 Member 클래스 타입

원시자료형(Primitive type)

원시자료형은 기본적으로는 숫자형 데이터 타입 입니다. 정수, 실수, 문자, 논리형이 있습니다. 클래스 타입은 추후 객체지향에서 자세히 다루게 됩니다.

[그림: 자바 원시 자료형]

각 자료형의 명칭과 크기등은 다음과 같습니다.

자료형 크기 설명
byte 1바이트, -128~127 가장 작은 단위로 8bit 로 구성된 1byte 를 기본으로 함.
char 2바이트, 0~65535 음수를 포함하지 않는 unsigned 자료형으로 문자 표현에 적합.
short 2바이트, -32768~32767 음수를 포함한 2바이트 크기의 자료형. 작은 데이터 처리에 적합.
int 4바이트, -2147483648~2147483647 정수의 기본자료형이지만 충분한 크기가 아님에 주의
long 8바이트, -9223372036854775808 ~ 9223372036854775807 충분한 숫자값이 필요한 경우 사용
float 4바이트, 1.4E-45 ~ 3.4028235E38 실수형의 기본형이 아니므로 숫자뒤에 f 를 붙여 사용
double 8바이트, 4.9E-324 ~ 1.7976931348623157E308 실수형의 기본 자료형.
boolean 1바이트, true 혹은 false 논리형으로 참, 거짓을 표현.

다음은 다양한 변수 사용 예 입니다.

int num1;   // 정수형 변수
char c1 = 'A';  // 문자형 변수를 선언하고 `A`로 초기화
long num2 = 212355L;    // long 정수형 변수를 선언.
float num3 = 13.4F;     // float 실수형 변수를 선언.
boolean result = true;  // 논리형 변수를 선언하고 true 로 초기화.
크기 계산: signed 자료형의 경우 크기보다 하나 작은 비트를 승수로 사용하는데 그 이유는 음수 처리를 위해 최상위비트를 부호부로 사용하기 때문이다. 즉 byte 의 경우 -28~28 이 아니라 -27~27 이 된다. 또한 양수 범위에서 -1을 하게 되는데 이는 `0`을 빼기 위함이다.
결과적으로 byte 의 크기 범위는 -27~27-1 이 된다.
지수 표기법: 지수 표기법은 숫자En 또는 숫자E+n 형식으로 사용하며 이는 숫자 * 10n이된다. 보다 정밀한 숫자를 적은 자리수로 표현하기 위해 사용함.

자바 변수 유형

프로그램 코드내에서 변수의 위치에 따라 몇가지 유형으로 변수를 구분할 수 있습니다.

멤버변수(Member variable)

인스턴스 변수(Instance variable)

매개 변수(Parameter)

지역 변수(Local variable)

클래스 변수(Class variable)

» 실습: 변수 기본 예제

실습개요

다양한 자료형과 변수 유형을 포함하고 있는 종합 예제 입니다.

소스코드

public class Variables {
    // 멤버 변수, 인스턴스 변수
    int num1;

    // 멤버 변수, 클래스 변수
    static int num2;

    // 매개변수
    public void printName(String name) {
        // 지역변수
        String prtMsg = name + " Hello";
        System.out.println(prtMsg);
    }

    public static void main(String[] args) {
        // 인스턴스 생성
        Variables mc = new Variables();
        // 인스턴스 변수 사용
        mc.num1 = 100;
        // 클래스 변수 사용
        Variables.num2 = 50;  // num2 = 50 으로 사용해도 됨.

        // 인자로 매개변수에 값을 전달
        mc.printName("홍길동");
        
        System.out.printf("%d,%d",mc.num1, Variables.num2);
    }
}

실행결과

홍길동 Hello
100,50

2) 메서드(Method)

메서드는 특정 객체의 동작이나 행위를 정의한 것으로 클래스의 주요 구성요소 입니다.

메서드 선언 방법

[접근제어자] 리턴타입 메서드명([인자..]) {

}

메서드 오버로딩(Overloading)

가변 인자(Variable arguments)

생성자 메서드(Constructor method)

» 실습: 메서드 기본 예제

실습개요

다양한 메서드 유형을 선언하고 사용하는 종합 예제 입니다.

소스코드

public class Methods {
    String name;

    // 생성자 메서드
    Methods() {
        name = "홍길동";
        System.out.printf("#생성자: %s\n",name);
    }

    // 인자가 없는 메서드
    void printName() {
        System.out.printf("#printName(): %s\n",name);
    }

    // 인자가 하나인 메서드(메서드 오버로딩), 인자 값이 출력됨.
    void printName(String name) {
        System.out.printf("#printName(String name): %s\n", name);
    }

    // 가변인자를 사용한 메서드
    void printNames(String...name) {
    	System.out.println("#printNames(String...name)");
        for(String s : name) {
            System.out.println(s);
        }
    }

    // 인자가 두개인 메서드
    int calc(int num1, int num2){
        return num1+num2;
    }
    
    public static void main(String[] args) {
    	Methods m = new Methods();
    	m.printName();
    	m.printName("김길동");
    	m.printNames("아무개","홍길동","김사랑");
    	System.out.printf("#calc(int num1, int num2): %d ", m.calc(20,50));
    }
}

실행결과

#생성자: 홍길동
#printName(): 홍길동
#printName(String name): 김길동
#printNames(String...name)
아무개
홍길동
김사랑
#calc(int num1, int num2): 70 


03: 연산자(Operator)

연산자는 프로그램에서 변수의 값들을 계산하기 위해 사용 합니다. 사칙연산, 대입연산, 비트연산, 논리연산, 관계연산 등이 있습니다.

사칙연산(Arithmetic operators)

숫자 데이터를 이용해 기본적인 수학연산을 수행 합니다.

사칙 연산자 사용 예 의 미 결 과
+ 4 + 2 덧샘 연산 6
- 4 - 2 뺄샘 연산 2
* 4 * 2 곱샘 연산 8
/ 4 / 2 나누기 연산 2
% 8 % 3 나머지 연산 2
* 사칙 연산자

대입연산(Assignment operators)

변수에 값을 대입하기 위한 연산자로 축약형과 단항 연산자등이 포함되어 있습니다.

대입 연산자 사용 예 의미 결과
= weight = 80; 변수 weight에 80의 값을 할당 80
+= weight += 2; weight = weight + 2; 와 같음 82
-= weight -= 2; weight = weight - 2; 와 같음 80
*= weight *= 2; weight = weight * 2; 와 같음 160
/= weight /= 2; weight = weight / 2; 와 같음 80
%= weight %= 3; weight = weight % 3; 과 같음 2
++ weight++; weight = weight + 1; 과 같음 3
- - weight- -; weight = weight - 1; 과 같음 2
단항연산자: ++, --와 같은 단항 연산자는 변수명 앞 혹은 뒤에 사용할 수 있습니다. 앞에 사용하는 경우 값을 먼저 증/감시킨후 변수에 대입하며 뒤에 사용하는 경우 현재 변수값을 사용한 다음 증/감시킨 값을 대입하게 됩니다.
* 대입 연산자

» 실습: 연산자 기본 예제 - 사칙연산, 대입연산

실습개요

사칙연산과 대입연산 종합 예제 입니다.

소스코드

public class Operator1 {
    public static void main(String[] args) {
        int num1 = 30;
        int num2 = 14;

        int result1 = num1 * num2;
        int result2 = num1 % num2;

        System.out.printf("result1 : %d \n", result1);
        System.out.printf("result2 : %d \n", result2);
        System.out.println("-------------------");

        num1++;
        num2 *= 2;
        System.out.printf("num1++ : %d \n", num1);
        System.out.printf("num2 *= 2 : %d \n", num2);
        System.out.println("-------------------");

        System.out.printf("num1++ : %d \n", num1++);
        System.out.printf("--num1 : %d \n", --num1);
    }
}

실행결과

result1 : 420 
result2 : 2 
-------------------
num1++ : 31 
num2 *= 2 : 28 
-------------------
num1++ : 31 
--num1 : 31 

비트연산자(Bitwise operators)

일반적으로 사용하는 10진수 혹은 문자에 대한 연산이 아닌 비트단위의 연산에 사용되는 연산자 입니다.

연산에 사용되는 값은 long, int, short, char, byte 등이 될 수 있으며 10진수 데이터를 비트(2진수)로 변환한 데이터를 가지고 연산을 수행하게 됩니다.

비트단위의 데이터를 다루는 경우(센서등 기계장치로 부터 발생하는 데이터 등) 유용하게 사용할 수 있으며 비트쉬프트, XOR 등의 연산을 통해 간단한 암호화 처리등에 사용할 수 있습니다.

비트 연산자 의미 사용 예 결과
& 비트 AND 연산 a & b a(40): 0010 1000, b(122): 0111 1010, r: 0010 1000
| 비트 OR 연산 a | b a: 0010 1000, b: 0111 1010, r: 0111 1010
^ 비트 XOR 연산 a ^ b a: 0010 1000, b: 0111 1010, r: 0101 0010
~ 비트 inverse(역) 연산, 0->1, 1->0 a ~ b a: 0010 1000, r: 1101 0111
>> 비트를 우측으로 이동(shift), 2로 나누는 효과 a » 2 a: 0010 1000, r: 0000 1010
<< 비트를 좌측으로 이동(shift), 2를 곱하는 효과 a « 2 a: 0010 1000, r: 1010 0000
* 비트 시프트 연산자 a,b 는 변수, r은 결과

» 실습: 연산자 기본 예제 - 비트시프트, XOR

실습개요

비트 쉬프트 연산과 XOR 연산 예제 입니다.

소스코드

public class Operator2 {
    public static void main(String[] args) {
        int num1 = 50;
        System.out.printf("정수값 num1 : %d, %s\n", num1, Integer.toBinaryString(num1));		

        int result1 = num1 >> 1;
        System.out.printf("num1 >> 1 : %d, %s\n", result1, Integer.toBinaryString(result1));

        int result2 = num1 << 1;
        System.out.printf("num1 << 1 : %d, %s\n", result2, Integer.toBinaryString(result2));

        System.out.println("------------------");

        int pwd = 123456;
        int encPwd, decPwd;
        int key = 0x1A253B65;
                
        System.out.println("암호화 전 비밀번호 : "+pwd);

        encPwd = pwd ^ key;

        System.out.println("암호화 후 비밀번호 : "+encPwd);

        decPwd = encPwd ^ key;

        System.out.println("복호화 후 비밀번호 : "+decPwd);
    }
}

실행결과

정수값 num1 : 50, 110010
num1 >> 2 : 25, 11001
num1 << 2 : 100, 1100100
------------------
암호화 전 비밀번호 : 123456
암호화 후 비밀번호 : 438622501
복호화 후 비밀번호 : 123456

논리 연산자(Logical operators)

 true 혹은 false 를 반환하는 연산자로 여러 조건을 만족하는지 체크하기 위한 용도로 if 문등에서 사용 됩니다.

논리 연산자 의미 사용 예 결과
&& AND 연산, 양쪽이 모두 참인 경우에만 true 리턴 A && B false
|| OR 연산, 양쪽중 한쪽만 참이어도 true 리턴 A || B true
! 단항연산으로 NOT 연산 !A false
* 논리 연산자

관계연산자(Relational operators)

왼쪽과 오른쪽의 피연산자를 비교한 결과를 true, false 로 리턴하는 연산자 입니다. 보통 if, while문 등에서 수행조건을 체크하기 위해 사용합니다.

관계 연산자 의미 사용 예 결과
> 크다 a > b false
>= 같거나 크다 b > a true
< 작다 c < b true
<= 같거나 작다 b < a false
== 같다 a == c true
!= 같지않다 a != b true
* 관계 연산자, a,c=10, b=20 으로 가정
Note: 논리 연산자와 관계 연산자 실습은 다음장에 나오는 조건문과 반복문 예제에서 함께 다룹니다.


04: 자바 메모리 관리

JVM은 시스템(운영체제)으로부터 프로그램을 실행하는데 필요한 메모리를 할당받고 JVM은 할당받은 메모리를 용도에 따라 세 영역으로 나누어 관리합니다.

자바는 C언와 같이 직접적인 메모리 주소에 접근할 수 없으며 개발자가 메모리를 할당받거나 반환하지 않아도 되는 구조이기 때문에 일반적인 응용 프로그래머의 경우 구체적인 메모리 관리에 대해서는 자세히 알 필요는 없습니다.

다만 프로그램의 동작구조를 보다 정확하게 이해하기 위해서는 다음에 나오는 내용은 알아둘 필요가 있습니다.

메서드 영역 (method area)

프로그램 실행 중 특정 클래스가 사용되면, JVM은 해당 클래스의 클래스파일(*.class)을 읽어서 분석한 다음 클래스에 대한 정보를 이곳에 저장하게 됩니다. 이때 클래스변수메서드(static)도 이 영역에 함께 생성됩니다.

main() 에서 클래스에 선언된 변수에 접근할 수 없는 것도 이러한 이유로 main()static 으로 선언되어 있기 때문에 클래스에 선언된 멤버변수(인스턴스 변수)를 사용할 수 없으며 인스턴스의 변수들은 힙 영역에 생성되기 때문에 인스턴스를 통해서만 접근이 가능한 것입니다.

힙 영역 (heap area)

프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성됩니다. 즉, 인스턴스 변수들이 생성되는 공간으로 대부분의 메모리 공간은 힙 영역이 됩니다.

서버 시스템이나 메모리 사용이 많은 프로그램을 개발하거나 실행할때 힙 메모리 부족으로 문제가 발생할 수 있으며 이 경우 JVM 메모리 옵션을 조정해 주어야 합니다. -> 오라클 공식 문서 참조

호출 스택 (call stack or execution stack)

호출스택은 메서드 실행에 필요한 메모리 공간을 말합니다. 메서드가 호출될때 호출스택에는 호출된 메서드를 위한 메모리가 할당되며 이 메모리는 메서드가 작업을 수행하는 동안 지역변수 및 매개변수들의 연산 중간결과 등을 저장하는데 사용됩니다. 메서드가 작업을 마치면 할당되었던 메모리공간은 반환되어 정리(비워짐)됩니다.

지역변수들의 경우 멤머변수나 다른 함수에서 사용된 변수들과 이름이 같아도 문제가 없는 이유 입니다.

가비지 컬렉션 (garbage collection)

줄여서 GC 라고도 합니다. 쉽게 설명하면 자바에서 사용되지 않는 메모리를 정리해 주는 작업이라고 할 수 있습니다. GC과정은 전체적인 JVM의 성능에 영향을 미치는 요소이기 때문에 오랜시간동안 발전을 거듭해 오늘에 이르게 되었습니다. 가비지 컬렉터(gabage collector)는 가비지 컬렉션을 수행하는 주체가 됩니다.

규모가 크지 않거나 특히 컨테이너 기반에서 동작하는(웹서버(WAS) 프로그램이나 안드로이드 등) 프로그램들의 경우 일반 개발자들이 신경쓸 일이 많지 않고 개발자가 직접 System.gc() 를 이용해 가비지 컬렉션을 동작시키는 것은 권장되지 않습니다.

[그림] Java Heap 메모리 구조

New/ Young 영역

Old 영역

Permanent Generation

프로그램내에서 GC 대상이 되는것은 다음과 같습니다.

자바 객체 참조

좀 더 메모리를 고려하는 프로그램을 개발해야 하는 경우 단순히 new 가 아니라 WeakReference 혹은 SoftReference 를 이용해 객체를 생성해야 적절한 메모리 관리가 이루어 집니다.

Strong Reference

Soft Reference

Weak Reference


참고 자료