ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바 기초 - 누군가를 위한..ㅋ
    Developer/Java 2013. 5. 7. 17:40
    자바의 기본 문법


    이 번 장에서는 자바 프로그램의 기본적인 문법을 살펴보자.


    코드 작성 원칙(Coding Rules)

    자바의 코드 작성 원칙은 C언어와 거의 유사하다. C언어를 해본 독자라면 쉽게 이해할 수 있을 것이다. C언어를 해보지 않은 독자도 이해할 수 있도록 충분히 쉽게 설명하였으므로 즐거운 마음으로 읽기 바란다.

    ◈ 한 명령(문장)이 끝나면 세미콜론(;)을 붙여야 한다.

    ◈ 블록(Block)은 '{'와 '}'로 묶여진 부분을 말하는 것으로 클래스와 메소드를 정의할 때, 또는 제어문에서 사용된다.

    ◈ 모든 띄움 문자는 모두 하나의 space(한 칸 띄움)로 인식된다.

    public static void main(String [] args){



    자바는 위의 문장을 아래와 같이 인식한다.

    public static void main(String[] args){



    줄띄움(개행)은 아무런 의미가 없다. 1장에서 실행했던 예제 HelloJava를 아래와 같이 작성해도 된다는 말이다.

    public class HelloJava{ public static void main(String[] args){

    System.out.println("안녕 자바!!");}}



    그렇다고 해서 위와 같이 작성하면 코드를 해석하기 힘들다. 아래와 같이 알아보기 쉽게 작성하는 게 좋다.

    public class HelloJava{

    public static void main(String[] args){

    System.out.println("안녕 자바!!");

    }

    }







    주석(Comment)

    예를 들어 큰 프로젝트를 만든다고 생각하자. 이 프로젝트의 코드가 수백 내지 수천 라인 이상이라면 다른 사람이 해석하려할 때 많은 시간이 소요될 것이다. 아마도 프로젝트의 총 작성 시간보다 더 많은 시간이 필요할 것이다. 하지만 중요 코드나 이해하기 어려운 코드에 설명을 달아 놓으면 분석 시간도 절약될 뿐만 아니라 수정하기도 쉬울 것이다. 이런 목적으로 사용되는 것이 주석이다.



    주석은 아래와 같이 세 가지로 구분된다.

    1. //

    2. /* */

    3. /** */



    1번(//)은 한 줄 주석이다. '//' 뒤의 모든 문자는 모두 주석이 된다.

    // 이것이 한 줄 주석이다.




    2번(/* */)은 여러 줄을 묶어서 주석 처리한다.

    /* 프로그램 이름: HelloJava

    작성자: Mr. Seo

    작성일: 2002년 1월 28일

    */




    3번(/** */)은 자바 문서를 작성할 때 사용하는 것으로 API 문서 같은 것을 만들 때 사용한다. 이 주석은 JDK안에 javadoc.exe와 같이 사용된다.

    javadoc.exe Abc.java


    Abc.java파일을 자바 문서로 만들려면 위와 같이 실행하면 된다. 이 때 '/** */' 부분을 javadoc가 번역하게 된다. 초보자에게는 중요한 사항이 아니므로 '그렇구나'하고 넘어가도록 하자.

    필자는 주석을 잘 사용하지 않는데 그것 때문에 많은 고생을 한다. 프로그램을 만들고 어느 정도 시간이 지나서 수정할 때 많은 시간을 허비하기 때문이다. 많은 시간을 허비하는 이유는 본인이 짠 프로그램이지만 이해가 잘 안되기 때문이다. 거짓말 같지만 남이 짠 프로그램인 것처럼 보일 때도 있다. 그 때마다 주석을 달지 않은 것에 대하여 많은 후회를 한다. 주석은 타인을 위해서 이기보다 미래의 자신을 위해서 더 필요하다.



    HelloJava.java를 아래와 같이 수정하고 실행해보자.

    /* 프로그램 이름: HelloJava

    작성자: Mr. Seo

    작성일: 2002년 1월 28일

    */



    public class HelloJava{ // HelloJava 클래스 시작

    public static void main(String[] args){ // 메인 메소드 시작

    System.out.println("안녕 자바!!"); // 도스 창에 글자 출력

    } // main 끝

    } // HelloJava 클래스 끝


    주석 처리된 부분은 컴파일에서 제외되므로 실행되지 않는다.




    식별자(Identifiers)

    식별자란 사용자가 임의로 만드는 클래스 이름, 변수 이름, 메소드 이름 등을 말한다. 다른 말로 '사용자 정의 명칭'이라고도 한다.

    public class HelloJava{ // 클래스

    public static void main(String[] args){ // 메소드

    int a=10; // 변수

    int 숫자; // 변수

    System.out.println("안녕 자바!!");

    }

    }



    위의 프로그램에서 HelloJava, main, args, a, 숫자, System, out, println이 식별자이다. System은 자바에서 지원하는 클래스이지만 식별자에 해당된다.


    식별자를 만들 때 몇 가지 지켜야 할 사항이 있다.

    1. 대소문자를 구분하고, 식별자의 길이는 제한이 없다.

    2. 영문자, 한글, 숫자, 밑줄(_), 달러문자($)를 사용할 수 있다. 그러나 숫자로 시작해서는 안 된다.

    3. 자바에서 사용하는 키워드는 사용할 수 없다.

    예) public, void, static, class 등



    옳은 예)

    Abcde, abc12, _Hi, $abc, abc123abc



    틀린 예)

    3abc, #abc, this, super



    ※ this와 super는 자바에서 사용하는 키워드(예약어)이므로 사용할 수 없다.



    [표 3-1]은 자바에서 사용하는 키워드 표이다. 참고하기 바란다.

    분 류
    키 워 드

    기본 자료형
    boolean, byte, char, short, int, long, float, double

    접근 지정자
    private, protected, public

    클래스 관련 키워드
    class, abstract, interface, extends, implements

    객체 관련 키워드
    new, instanceof, this, super, null

    메소드 관련 키워드
    void, return

    제어문
    if, else, switch, case, default, for, do, while, break, continue

    논리 값
    true, false

    예외 처리
    try, catch, finally, throw, throws

    기타
    transient, volatile, package, import, synchronized, native, final, static, strictfp

    사용되지 않는 키워드
    goto, const



    [표 3-1] 자바 키워드

    goto, const는 C언어나, 베이직 등 다른 언어에서 사용되는 키워드로 좋은 점 보다 나쁜 점이 많기 때문에 자바에서는 아예 사용하지 않는 키워드로 분류하였다.




    변수와 상수(Variable & Constant)

    변수란 '변하는 수'라는 뜻이다. 변수의 이름은 식별자를 사용한다. 상수란 '항상 같은 수'를 의미한다.



    abc=10 ;


    abc에 10을 대입하라는 명령인데, abc는 변수이고, 10은 상수이다.

    boo= true ;



    여기서 변수는 boo이고 상수는 true이다. true와 false는 참, 거짓을 표시하는 자바가 사용하는 키워드이다.



    알아두기


    변수, 상수, 메소드, 클래스 이름 짓는 관례

    변수와 메소드는 소문자로 시작하는 것을 원칙으로 하고 상수는 모두 대문자를 사용한다. 클래스 이름은 대문자로 시작하는 것을 원칙으로 한다.

    1장의 HelloJava 클래스도 대문자로 시작하고 있다.







    자료형(Data Type)

    자료형이란 변수 또는 상수가 차지하는 메모리의 양(byte)과 종류를 의미한다. 자바의 자료형은 크게 기본 자료형과 객체형으로 나눌 수 있다.

    1. 기본 자료형(Primitive Type)

    2. 객체형(Object Type)




    자료형을 구체적으로 정리하면 다음 그림과 같다.



    1. 기본 자료형(Primitive Type)

    A.논리형(Logical)

    - boolean

    B.문자형(Textual)

    -char

    C.정수형(Integral)

    -byte

    -short

    -int

    -long

    D.실수형(Floating)

    -float

    -double



    2. 객체형(Object Type)


    [그림 3-1] 자료형

    우선 기본 자료형을 자세히 살펴보고 객체형은 간단히 살펴보도록 하자. 객체형은 5장에서 자세히 공부할 것이다.



    1. 기본 자료형(Primitive Type)

    기본 자료형은 논리형, 문자형, 정수형, 실수형으로 나뉘어진다.




    A.논리형(Logical)

    참(true)과 거짓(false)을 표현하는 자료형으로 boolean이 있다. boolean은 1byte의 메모리를 차지한다.



    다음 예제를 해보자.

    Logical.java



    Public class Logical{

    public static void main(String[] args){

    boolean a=true;

    boolean b=false;

    System.out.println(a); // x1 행

    System.out.println(b); // x2 행

    }

    }



    --------------------------------------------------------------------------------

    출력 결과




    true

    false


    --------------------------------------------------------------------------------



    짚어두기


    자바 프로그램이 실행되면 main 메소드가 맨 처음 실행된다('{' 이후). 그리고 더 이상 실행될 것이 없으면 프로그램은 종료된다.

    ( 그러나 항상 main이 맨 먼저 실행되는 것은 아니다. 나중에 그 이유를 알 것이다. )





    a와 b의 자료형은 boolean이다. 따라서 a와 b는 true 또는 false 값을 가질 수 있다. a와 b가 차지하는 메모리 양은 1byte이다. x1행과 x2행에서는 a와 b가 가지고 있는 값을 출력하고 있다.



    주의하기


    표준 C언어에서는 boolean 자료형이 없고 대신에 0과 1을 사용한다. 0은 거짓을 나타내며 1은 참을 나타낸다. 그러나 자바에서는 그런 것이 없고 boolean이 있다.







    B.문자형(Textual)

    하나의 문자를 기억하는 자료형으로 char형이 있다. 2byte의 메모리를 사용하기 때문에 한글도 기억할 수 있다.

    알아두기


    자바는 문자를 처리하는 코드로 유니코드(Unicode)를 사용한다. 유니코드는 2byte를 사용하여 한 문자를 처리하는 방식으로 거의 모든 나라의 언어를 처리할 수 있다.




    Textual.java




    public class Textual{

    public static void main(String[] args){

    char a, b, c; // x1

    a='A';

    b='한';

    c='韓';

    System.out.println(a);

    System.out.println(b);

    System.out.println(c);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    A






    --------------------------------------------------------------------------------



    x1행은 char형 변수 a, b, c를 정의하고 있다. 콤마(,)를 이용하여 구분한다.

    char a, b, c;





    다음과 같이 해도 같은 결과이다.

    char a;

    char b;

    char c;





    x1행과 같이 하는 것이 라인(Line)수를 줄여 준다.



    'A', '한', '韓'은 문자형 상수들인데, 작은따옴표(')로 묶어 문자형 상수임을 나타내는 것이다. 참고로 문자열은 큰따옴표(")를 사용한다. 문자열이란 문자들의 집합을 의미한다.



    문 자: 'A', '한', '韓', 'd'

    문자열: "안녕 자바!!", "abcd", "1234", "A"




    주의하기


    문자는 기본 자료형(char)이고 문자열은 객체(Object)이다. char a="A"; 와 같이 해서는 안 된다. "A"는 문자가 아니라 문자열 객체이기 때문이다. char a='A'; 가 정답이다.






    C.정수형(Integral)

    정수형은 정수를 표현하기 위해 사용하는 것으로 메모리의 양에 따라 byte, short, int, long으로 나뉜다. 메모리 양이 클수록 큰 정수를 기억할 수 있다.



    정수형
    메모리 양
    정수 표현 범위

    byte
    1 byte
    -128 ~ 127

    (-2의 7승 ~ 2의 7승-1)

    short
    2 byte
    -32768 ~ 32767

    (-2의 15승 ~ 2의 15승-1)

    int
    4 byte
    -2147483648 ~ 2147483647

    (-2의 31승 ~ 2의 31승-1)

    long
    8 byte
    -9223372036854775808 ~9223372036854775807

    (-2의 63승 ~ 2의 63승-1)


    [표 3-2] 정수형 Data Type



    1byte는 8bit이다. bit란 메모리 최소 기억 단위로 1과 0을 기억할 수 있다. 아래 그림은 1byte를 비트(bit)로 쪼개어 본 것이다.





    [그림 3-1]



    여기서 음영색으로 된 맨 왼쪽 비트를 부호 비트라고 하는데 이 비트가 0이면 양수를 의미하고 1이면 음수를 의미한다.





    [그림 3-2] 양수와 음수





    1byte로 표현할 수 있는 최대 정수는 127이고, 최소 정수는 -128이다.





    [그림 3-3] 최대 정수와 최소 정수



    short, int, long로 이런 식으로 계산해 보면 [표 3-2]와 같은 결과가 나온다.



    Integral.java




    public class Integral{

    public static void main(String[] args){

    byte b=1; // x1

    short s=32000; // x2

    int i=-2100000000; // x3

    long l=1234567890123456890L; // x4

    System.out.println(b);

    System.out.println(s);

    System.out.println(i);

    System.out.println(l);

    }

    }



    --------------------------------------------------------------------------------

    출력 결과




    1

    32000

    -2100000000

    1234567890123456890


    --------------------------------------------------------------------------------



    x1행을 아래와 같이 바꾸면 어떻게 될까?



    byte b=1000;




    다음과 같은 에러가 발생한다.



    C:thinkIntegral.java:3: possible loss of precision

    found : int

    required: byte

    byte b=1000;

    ^




    위의 에러 메시지는 "3행에서 b가 표현할 수 있는 범위 보다 큰 정수를 b에 대입하고 있다" 라는 내용이다. byte형 변수가 기억할 수 있는 정수의 범위는 -128 ~ 127이기 때문이다. 앞으로 프로그램을 짜다보면 위와 같은 에러메시지를 많이 보게 될 것이다. 그때그때 에러 메시지를 유심히 보고 해석하는 연습을 하자. 다음에 같은 에러 메시지가 나오면 빠르게 에러를 수정할 수 있게 말이다.

    에러 메시지를 해석하는 능력도 프로그래밍 능력이다.





    x4행을 보면 숫자 뒤에 L이 있다. 만약 L이 삽입되어 있지 않으면 에러가 발생한다. int형이 표현할 수 있는 범위 이상의 수에는 L이나 l(소문자 L)을 붙여야 한다. 정수형 상수에는 두 가지가 있는데 int형과 long형이 있다. long형 상수는 뒤에 L을 붙인다.

    int형 상수: 1, 123, -12345, 012, 0x12

    long형 상수: 1L, 2L, 3000L, -60000000000L, 012L, 0x12L





    정수 표현은 10진수와 8진수, 16진수가 있다. 8진수는 숫자 앞에 0(zero)을 붙이고, 16진수는 숫자 앞에 0x나 0X를 기재한다.



    10진수: 1, 10, 1234

    8진수: 01, 010, 01234

    16진수: 0x1, 0x12, 0x1234




    알아두기


    진수 변환 방법

    8진수 012를 10진수로 변환하면 10이다.

    012 = 1*8+2

    16진수 0x12를 10진수로 변환하면 18이다.

    0x12 = 1*16+2

    16진수 0xABCD를 10진수로 변환하면 43981이다.

    0xABCD = 10*16^3+11*16^2+12*16+13






    다음 예제는 10진수와 8진수, 16진수의 사용법을 보여 주고 있다.

    Integral2.java




    public class Integral2{

    public static void main(String[] args){

    int i1= 12;

    int i2=012;

    int i3=0x12;

    int i4=0xABCD;

    System.out.println(i1);

    System.out.println(i2);

    System.out.println(i3);

    System.out.println(i4);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    12

    10

    18

    43981


    --------------------------------------------------------------------------------



    출력 결과를 보면 모두 10진수로 출력된 것을 볼 수 있는데 System.out.println()는 정수를 10진수로 변환하여 출력한다.





    D.실수형(Floating)

    실수를 표현하는데 사용되며 종류로 float 과 double이 있다. float은 4byte의 메모리를 사용하며 double은 8byte의 메모리를 사용한다.



    실수형
    메모리 양
    실수 표현 범위

    float
    4 byte
    -1.4E-45 ~ 3.4028235E+38

    double
    8 byte
    -4.9E-324 ~1.7976931348623157E+308


    [표 3-2] 실수형 Data Type



    알아두기


    과학용(지수형) 표기

    123.456 = 1.23456E+2

    0.00000123 = 1.23E-6





    실수형 변수는 실수형 상수를 기억하기 위한 것으로 소수를 기억할 수 있다. 실수형 상수로는 float형과 double형이 있는데 일반적인 소수는 모두 double형으로 간주된다.

    double형 상수: 1.23, 0.1, -0.2345, -0.1

    float형 상수: 1.23F, 0.1f, -0.2345f, -0.1F





    float형 소수를 사용하려면 소수 뒤에 F나 f를 기재한다. 아래 예제는 그 사용법을 보여준다.



    Floating.java



    public class Floating{

    public static void main(String[] args){

    float f=1.23f; // x1

    double d=1.23;

    System.out.println(f);

    System.out.println(d);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    1.23

    1.23


    --------------------------------------------------------------------------------



    x1행을 아래와 같이 하면 에러이다.

    float f=1.23; // 에러





    1.23은 double형이므로 float형 변수 f에 담을 수 없다. 큰 그릇(8byte)이 작은 그릇(4byte)에 담길 수 없는 이유와 같다.





    2. 객체형(Object Type)

    객체형은 아주 많이 있는데 대표적인 String형 객체에 대하여 알아보자.



    String은 문자열이라는 뜻으로 문자열에 관련된 클래스이다. String형 객체를 만드는 방법으로 두 가지가 있다.



    1: String s1="안녕";

    2: String s2=new String("Hello");




    1번 방법과 2번 방법에는 메모리와 관련해서 약간의 차이가 있으나 외부적으로 표현될 때는 차이가 없다. 따라서 아무거나 사용해도 무방하다.



    s1과 s2는 모두 String형 객체이다. 엄밀히 말하자면 s1과 s2는 레퍼런스 변수이고, "안녕", "Hello"가 객체이다. "안녕" 객체의 이름이 s1이고 "Hello"객체의 이름은 s2이다. 이게 무슨 말인가? 5장에서 자세히 다룰 것이다. 몰라도 염려할 필요 없다.



    다음의 간단한 예제를 해보자.

    StringTest.java




    public class StringTest{

    public static void main(String[] args){

    String s1="안녕";

    String s2=new String("Hello");

    System.out.println(s1);

    System.out.println(s2);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    안녕

    Hello


    --------------------------------------------------------------------------------







    형 변환(Casting)

    '1+2.5'를 연산(계산)하면 결과 값이 3.5인 것처럼, 두 개의 변수나 상수가 연산을 취하면 결과 값이 생기는데, 이 결과 값이 어떤 자료형이 되는가하는 문제가 바로 형 변환 문제이다.





    [그림 3-4] 형 변환 문제



    위 그림과 같이 어떤 연산을 수행하면 결과가 메모리에 기억되는데 이 메모리의 유형이 무엇이냐 하는 문제를 다룰 것이다.



    형 변환에는 자동 형 변환과 강제 형 변환이 있다. 하나씩 살펴보자.





    자동 형 변환

    말 그대로 형 변환이 자동으로 이루어진다.



    1: byte b1 = 1;

    2: byte b2 = 2;

    3: byte b3 = b1+b2;




    3행은 b1과 b2를 더한, 값을 b3에 대입하라는 명령이다. 그렇다면 b3에 무슨 값이 들어갈까? 답: 에러.



    이유를 살펴보자. 식 'b1+b2'의 값이 3인 건 확실하다. 그런데 3을 기억하는 임시 메모리의 자료형은 byte형이 아니라 int형이다(int가 되는 이유는 조금 있다가 설명할 것이다). 따라서 int형 값을 byte형 변수인 b3에 대입할 수 없다. 따라서 위의 코드는 다음과 같이 수정되어야 한다.



    1: byte b1 = 1;

    2: byte b2 = 2;

    3: int b3 = b1+b2;




    b1과 b2가 연산한 값이 자동으로 int형이 되었다. 이런 것을 자동 형 변환이라고 한다.



    알아두기


    사실 두 변수가 연산해야만 결과 값이 생기는 것이 아니다. 나중에 공부하겠지만 하나의 변수가 연산하여 결과 값이 생길 수도 있다. 이때에도 형 변환이 이루어진다.




    [표 3-3]은 두 변수가 어떤 연산을 하여 생기는 결과 값의 자료형을 나열한 것이다.


    변수1
    변수2
    결과 값

    byte

    byte

    int

    short

    int

    long
    byte

    short

    byte

    int

    int

    int
    int

    int

    int

    int

    int

    long

    변수1
    변수2
    결과 값

    long

    byte

    int

    long

    float

    double
    long

    float

    float

    float

    double

    double
    long

    float

    float

    float

    double

    double




    [표 3-3] 형 변환 표

    위의 표를 바탕으로 자동 형 변환의 내용을 조합해보면 int보다 작거나 같은 형들이 연산한 결과 값은 모두 int형임을 알 수 있다. 왜 그럴까?



    자바는 데이터를 처리할 때 4byte단위로 한다. 즉, int단위로 한다는 것이다. byte와 byte가 연산하더라도 기본 데이터 처리 단위가 4byte이므로 int가 된다는 것이다.



    알아두기


    32비트 컴퓨터라는 말이 있는데 이것은 CPU가 한번에 처리하는 기본 데이터 처리 단위가 32비트, 즉, 4byte라는 뜻이다.

    JVM도 한번에 처리하는 기본 데이터 단위가 4byte이다.




    4byte 이상의 변수들의 연산은 자료형이 큰 쪽으로 형 변환된다. 코드를 보면서 공부하자.

    int b1 = 1;

    long b2 = 2;

    <?> b3 = b1+b2;





    <?>자리에 어떤 자료형이 오면 타당할까? b1+b2의 결과 값은 long임을 알 수 있다. 따라서 <?>에 올 수 있는 자료형은 long, float, double이다(long보다 큰 자료형).



    주의하기


    float이 long보다 큰 자료형이다.

    long의 메모리 양은 8byte이고 float의 메모리 양은 4byte이다. 그러나 long은 소수를 기억하지 못하므로 float을 큰 자료형으로 취급한다.




    또 다른 코드를 보자.



    int b1 = 7;

    int b2 = 2;

    int b3 = b1/b2; // '/'은 나누기를 의미한다. --> b1÷b2

    System.out.println(b3);




    출력 결과는 무엇일까? 답: 3



    7/2의 정확한 값은 3.5이지만 'b1/b2'는 'int / int' 식이므로 결과 값의 자료형도 int가 된다. 따라서 int에 3.5가 대입될 수 없으므로 소수점 이하는 버린다. 결과적으로 3이 된다. 따라서 b3에 3이 대입된다.



    int b3 = b1/b2; --> b3 = 3;




    그렇다면 아래의 코드는 어떠한가?



    int b1 = 7;

    int b2 = 2;

    double b3 = b1/b2;

    System.out.println(b3);




    출력 결과는? 3.5라고 생각하는 독자도 있을 것이다. 그러나 아니다.



    'b1/b2'는 'int/int' 식이므로 결과형도 int이다. 따라서 3이다. 결과 값 3을 b3에 대입하므로 출력 결과는 3.0이 된다. 결과를 직접 확인하기 바란다.



    double b3 = b1/b2; --> b3 = 3.0;




    그렇다면 어떻게 b3에 3.5를 집어넣을 수 있을까? 해답은 강제 형 변환에 있다.





    강제 형 변환

    강제 형 변환이란 강제로 자료의 형을 바꾸는 것을 말한다.



    int b3 = (int)3.7; // 3.7은 double이다.




    3.7을 int형으로 바꾸려면 위와 같이 하면 된다. (int)3.7의 의미는 '3.7을 정수로 형 변환하라'는 뜻이다. 즉, 소수점 이하는 버린다. 따라서 b3에는 3이 대입된다.



    int b3 = (int)3.7; --> b3 = 3;




    아래 코드를 보자.



    int b1 = 7;

    int b2 = 2;

    double b3 = (double)b1/b2;

    System.out.println(b3);




    (double)b1 은 b1을 double형을 바꾼다. 따라서 아래와 같이 된다.



    double b3 = 7.0/b2;




    이제 double/int 가 되어 결과 값은 double이 된다. 따라서 아래와 같이 된다.



    double b3 = 3.5;




    형 변환에 관련된 예제를 해보자.



    Casting.java



    public class Casting{

    public static void main(String[] args){

    byte a=7;

    int b=2;

    double c=3.4;

    double d=a/b+c; // x1

    double e=(double)a/b+c; // x2

    System.out.println(d);

    System.out.println(e);

    }

    }



    --------------------------------------------------------------------------------



    출력 결과



    6.4

    6.9


    --------------------------------------------------------------------------------





    보다 정확한 값을 얻으려면 x2행과 같이 해야한다. 그렇지 않으면 엉뚱한 결과가 생길 수 있다. 따라서 형 변환은 수식을 만들 때 유심히 살펴야할 사항이다.



    주의하기


    형 변환관련 C와 Java의 차이점

    C++언어에서는 (int)X 와 int(X) 둘 다 가능하다. 하지만 자바는 (int)X 만 가능하다.






    String 객체와 기본 자료형의 연산

    String 객체와 기본 자료형은 '+' 연산이 수행될 수 있다. 결과 값은 String형 객체이다. 즉, '문자열+정수(실수)=문자열'이 된다.



    1: String s = "안녕" + 12;

    2: System.out.println(s); // 출력 결과: 안녕12




    1행에서 s에 "안녕12"가 대입된다. 사실 대입된다는 말은 거짓말이다. 필자는 독자에게 감히 거짓말을 하고 있다. 하지만 거짓을 말할 수밖에 없는 필자를 이해해 주길 바란다. 지금은 s에 "안녕12'가 대입된다고 생각하자. 나중에 자세히 공부하자.



    다음 코드의 출력 결과는 무엇일까?



    1: int a=12;

    2: System.out.println("a의 값은 "+a+"입니다.");




    출력 결과: "a의 값은 12입니다."



    2행의 연산 순서는 아래와 같다.



    처음: System.out.println("a의 값은 "+a+"입니다.");

    연산1: System.out.println("a의 값은 12"+"입니다.");

    연산2: System.out.println("a의 값은 12입니다.");

    출력: a의 값은 12입니다.




    여기까지 조금은 따분하고 생소하게 느꼈을 지 모르겠다. 하지만 자꾸 하다 보면 어느새 내 것이 되어 있는 자바를 보게 될 것이다. 그 날이 오길 간절히 바라며 꾸준히 따라 오길 바란다.





    연산자(Operators)

    연산자란 '+', '-', '*', '/' 등과 같은 것을 말하며 데이터를 연산하여 새로운 데이터를 만드는 역할을 한다. 자바의 연산자는 크게 '단항 연산자', '2항 연산자', '3항 연산자', '객체 연산자'로 나뉜다.



    단항 연산자: -2(음수), 와 같이 변수나 상수가 하나 필요한 연산자를 의미한다.

    2항 연산자: 2+3 과 같이 항이 2개 필요한 연산자를 말한다.

    3항 연산자: A?B:C 와 같이 항이 3개 필요한 연산자를 말한다.




    아래 표는 자바 연산자의 종류를 나열한 것이다. 형 변환에 쓰이는 '(int)'와 같은 것도 연산자에 속한다.



    연산자
    종류

    단항 연산자
    -일반 논리 연산자(!)

    -비트 논리 연산자(~)

    -부호 연산자(+, -)

    -증감 연산자(++, --)

    2항 연산자
    -산술 연산자(+, -, *, /, %)

    -쉬프트 연산자(<<, >>, >>>)

    -관계 연산자(>, <, >=, <=, ==, !=)

    -일반 논리 연산자(&&, ||)

    -비트 논리 연산자(&, |, ^)

    -대입 연산자(=, op=)

    3항 연산자
    ? :

    객체 연산자
    instanceof


    [표 3-4] 연산자의 종류



    위에 있는 연산자들을 살펴보기 전에 먼저 연산 순서를 살펴보자.



    a=1+2*3




    a의 값은 무엇일까? 답 : 7



    당연하다라고 생각하고 있을 것이다. '*'가 '+'보다 연산 순위가 높기 때문에 2*3을 먼저 계산하고 1+6을 계산한다. 그 다음, a에 7이 대입된다.



    a=1+2*3 --> a=1+6 --> a=7




    이처럼 연산을 수행할 때 순서가 있는데 이것을 연산자 우선 순위라고 한다. 다음은 우선 순위가 높은 연산자부터 낮은 연산자순으로 나열한 것이다. 프로그램을 짜다 보면 우선 순위를 자연스럽게 알게 되므로 암기할 필요는 없다.



    단항 연산자 -> 산술 연산자 -> 쉬프트 연산자 -> 관계 연산자 -> 논리 연산자 -> 3항 연산자 -> 대입 연산자




    그러나 괄호가 있으면 괄호 안을 먼저 연산한다.



    a=(1+2)*3 // 변수 a에 9가 대입된다.




    이제 연산자들을 하나하나 살펴보자.





    ! 연산자

    논리적 NOT의 의미를 가지는 단항 연산자이다. 참(true)이면 거짓(false)으로, 거짓(false)이면 참(true)으로 바꾸는 역할을 한다.



    boolean b1 = !true; // b1에 false가 대입된다.

    boolean b2 = !false; // b2에 true가 대입된다.




    주의하기


    C언어에 익숙한 독자는 자바에 !0, !1 와 같은 것이 자바에는 존재하지 않음을 인지해야한다. 자바에서는 오직 true, false만이 존재한다.





    Operator1.java




    public class Operator1{

    public static void main(String[] args){

    boolean b= true;

    System.out.println(!b);

    System.out.println(!!b); // x1

    }

    }



    --------------------------------------------------------------------------------

    출력 결과




    false

    true


    --------------------------------------------------------------------------------



    x1행을 실행하면 true가 출력된다. !!b는 !(!b)으로 표현될 수 있다. !b는 false이므로 !(!b)는 true가 된다.



    !!b --> !(!b) --> !(false) --> true




    !연산자는 조건문(if, switch)에서 사용되므로 기억하고 있자.





    ~ 연산자

    비트 논리적 NOT의 의미를 가지는 단항 연산자이다. bit 값이 1이면 0으로, 0이면 1로 바꾸어 준다.



    int a =7;

    int b = ~a;




    a와 ~a를 bit로 표현하면 다음과 같다



    a ->
    00000000 00000000 00000000 00000111 : 7

    ~a ->
    11111111 11111111 11111111 11111000 : -8




    따라서 'b=-8'이 된다.



    ~연산자를 포함하여 앞으로 나올 비트 연산자는 대부분의 일반 프로그램에서 잘 사용되지 않기 때문에 대충 봐도 상관없지만 이런 비트 연산자가 있다는 것은 기억하고 있자.



    주의하기


    또 형 변환 문제

    아래 코드를 실행했을 때 어떤 결과가 예상되는가?



    byte a=7;

    byte b=~a;

    System.out.println(b); // -8이 출력될까?



    위의 코드는 에러이다. ~a는 int형이므로 에러. 하지만 아래와 같이 하면 에러가 아니다.



    byte b=(byte)(~a);









    부호 연산자(+, -)

    양수(+), 음수(-)를 표현하는 연산자로 이미 알고 있는 것들이다.



    int a = +7; // 양수 7 , int a = 7; 과 같은 표현이다.

    int b = -7; // 음수 7






    증감 연산자(++, --)

    변수의 값 1 증가시키거나 감소시키는 단항 연산자이다.



    ++ : 변수의 값을 1 증가시킨다.

    -- : 변수의 값을 1 감소시킨다.




    아래의 예제를 해보자.



    Operator2.java



    public class Operator2{

    public static void main(String[] args){

    int a=10, b=20;

    a++; // 1 증가

    System.out.println("a= "+a);

    b--; // 1 감소

    System.out.println("b= "+b);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    a= 11

    b= 19


    --------------------------------------------------------------------------------



    출력 결과를 보면 a는 10에서 11로 값이 1 증가했고, b는 20에서 19로 값이 1감소했다.



    증감 연산자는 변수 앞에 올 수도 있고 변수 뒤에 올 수도 있는데 전자를 전위(pre-position), 후자를 후위(post-position)라고 한다.



    전위: ++a, --a, ++b, --b

    후위: a++, a--, b++, b--




    전위와 후위는 약간의 차이가 있다. 다음 예제를 해보자.



    Operator3.java



    public class Operator3{

    public static void main(String[] args){

    int a=10, b=10;

    int c=++a; // 전위

    int d=b++; // 후위

    System.out.println("a= "+a);

    System.out.println("b= "+b);

    System.out.println("c= "+c);

    System.out.println("d= "+d);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    a= 11

    b= 11

    c= 11

    d= 10


    --------------------------------------------------------------------------------



    출력결과를 보면 a, b는 모두 1이 증가되었다. 증감 연산자가 앞에 오든, 뒤에 오든, 변수의 값이 1 증감됨을 알 수 있다. 그러나 다른 변수에 대입될 때 약간의 차이가 있다.



    먼저 전위에 대하여 살펴보자.



    int c = ++a;




    전위 연산자는 '선 연산, 후 처리'를 한다. a의 값이 1증가한 후, 그 값이 c에 대입된다. 따라서 a는 11이고, c도 11이다.



    이제 후위에 대하여 살펴보자.



    int d = b++;




    후위 연산자는 '선 처리, 후 연산'을 한다. 먼저 b의 값을 d에 대입한 후, b의 값이 1 증가한다. 즉, b의 값이 먼저 d에 대입되므로 d는 10이 되고, b의 값이 1증가하여 b의 값은 11이 된다.



    --연산자도 마찬가지로 전위와 후위가 있다.



    Operator4.java



    public class Operator4{

    public static void main(String[] args){

    int a=10, b=10;

    int c=--a;

    int d=b--;

    System.out.println("a= "+a);

    System.out.println("b= "+b);

    System.out.println("c= "+c);

    System.out.println("d= "+d);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    a= 9

    b= 9

    c= 9

    d= 10


    --------------------------------------------------------------------------------







    산술 연산자

    더하기(+), 빼기(-), 곱하기(*), 나누기(/) 연산자를 의미하고, 여기에 나머지 연산자(%)가 있다.

    int a = 2 + 3; // a=5

    int b = 2 - 3; // b= -1

    int c = 2 * 3; // c= 6

    int d = 2 / 3; // d=0 <-- 형 변환

    int e = 5 % 3; // e=2 <-- 5를 3으로 나눈 나머지

    int f = 10 % 3; // f=1 <-- 10을 3으로 나눈 나머지

    double g = 5.0 % 4.2 // g=0.8







    이제 혼자 힘으로 프로그램을 짜보자.



    혼자 해보기
    Alone3_1.java




    20을 3으로 나누었을 때 몫과 나머지를 구하라.



    출력 결과 예시




    < 20을 3으로 나누면 >

    몫 = 6

    나머지= 2


    --------------------------------------------------------------------------------





    앞으로 나오는 혼자 해보기는 꼭 힘으로 풀어보자. 하루를 투자해도 풀리지 않는다면 부록을 참고하자. 부록에 혼자 해보기에 대한 힌트가 실려있다.





    쉬프트 연산자(<<, >>, >>>)

    쉬프트(Shift) 연산자도 비트 연산자이다. 'shift'는 '이동시키다'라는 뜻인데 바로 비트를 이동시킨다.



    '<<'연산자는 비트 1을 왼쪽으로 이동시킨다. 맨 오른쪽 비트는 0으로 채운다.



    a ->
    00000000 00000000 00000000 00000111 : 7

    a<<1 ->
    00000000 00000000 00000000 00001110 : 14




    a ->
    00000000 00000000 00000000 00000111 : 7

    a<<2 ->
    00000000 00000000 00000000 00011100 : 28




    왼쪽으로 한번 쉬프트할 때마다 값이 2배 증가함을 알 수 있다.



    'a<<1'은 'a*2'와 같고, 'a<<2'는 'a*4'와 같다.




    '>>'연산자는 비트 1을 오른쪽으로 이동시킨다. 수가 양이면 맨 왼쪽 비트를 0으로 채우고, 수가 음이면 맨 왼쪽 비트를 1로 채운다.



    a ->
    00000000 00000000 00000000 00000111 : 7

    a>>1 ->
    00000000 00000000 00000000 00000011 : 3




    a ->
    11111111 11111111 11111111 11001110 : -50

    a>>1 ->
    11111111 11111111 11111111 11100111 : -25




    왼쪽으로 한번 쉬프트할 때마다 값이 반으로 감소함을 알 수 있다.



    'a>>1'은 'a/2'와 같고, 'a>>2'는 'a/4'와 같다.




    '>>>'연산자는 비트 1을 오른쪽으로 이동시킨다. 양수 또는 음수와는 상관없이 맨 왼쪽 비트를 0으로 채운다.

    a ->
    00000000 00000000 00000000 00000111 : 7

    a>>1 ->
    00000000 00000000 00000000 00000011 : 3





    a ->
    11111111 11111111 11111111 11001110 : -50

    a>>1 ->
    01111111 11111111 11111111 11100111 : 2147483623




    '>>>'연산자는 나누기 또는 곱하기 효과가 필요 없고, 단지 비트 이동이 필요할 때 사용한다. 부호 비트에 0이 채워지므로 음수를 '>>>'로 연산하면 양의 정수가 생긴다.

    주의하기


    int a=10;

    int b=a>>1;

    System.out.println(a); // 무엇이 출력될까? 5?



    위 코드의 실행 결과는? 답: 10

    변수 a의 값이 5가 되는 것이 아니라 'a>>1'의 연산 결과 값이 5이다. 따라서 b에 5가 대입된다.



    a=10, b=5





    Operator5.java



    public class Operator5{

    public static void main(String[] args){

    int a=100;

    System.out.println(a<<1);

    System.out.println(a<<2);

    System.out.println(a>>1);

    System.out.println(a>>2);

    System.out.println(a>>>1);

    System.out.println(); // ()안이 비어있으면 한 줄 띄운다.

    int b=-100;

    System.out.println(b<<1);

    System.out.println(b<<2);

    System.out.println(b>>1);

    System.out.println(b>>2);

    System.out.println(b>>>1);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    200

    400

    50

    25

    50



    -200

    -400

    -50

    -25

    2147483598


    --------------------------------------------------------------------------------







    관계 연산자(>, <, >=, <=, ==, !=)

    관계 연산자는 대소 비교를 하는 연산자인데, 결과 값으로 boolean이 생긴다. 비교 연산자라고도 한다. 관계 연산자는 나중에 배울 조건문에서 많이 사용된다.



    System.out.println( 5 > 3 ); // 출력 결과: true




    5>3은 참(true)이다. 따라서 true가 출력된다.



    System.out.println( 5 < 3 ); // 출력 결과: false




    5<3은 거짓(false)이다. 따라서 false가 출력된다.



    System.out.println( 5 >= 3 ); // 출력 결과: true




    '>=' : 크거나 같으면 true, 5>=3은 참(true)이다. 따라서 true가 출력된다.



    System.out.println( 5 <= 5 ); // 출력 결과: true




    5는 5보다 작거나 같으므로 참(true)이다. 따라서 true가 출력된다.



    '==' 연산자는 두 변수의 값이 같으면 true이고, 다르면 false이다.



    System.out.println( 5 == 5 ); // 출력 결과: true




    5는 5와 같으므로 참(true)이다. 따라서 true가 출력된다.



    System.out.println( 3 == 5 ); // 출력 결과: false




    3는 5와 같지 않으므로 거짓(false)이다. 따라서 false가 출력된다.



    != 연산자는 두 변수의 값이 다르면 true이고, 같으면 false이다.



    System.out.println( 5 != 4 ); // 출력 결과: true




    5는 4와 다르므로 참(true)이다. 따라서 true가 출력된다.



    System.out.println( 5 != 5 ); // 출력 결과: false




    5는 5와 같으므로 거짓(false)이다. 따라서 false가 출력된다.



    주의하기


    a=b 와 a==b 의 차이점

    a=b : 변수 a에 b의 값을 대입한다. 대입연산자.

    a==b : a의 값이 b의 값과 같으면 true이고, 같지 않으면 false이다. 비교연산자




    다음 코드의 결과는?

    System.out.println( !(5 == 5) );





    출력 결과: false



    !(5==5) --> !(true) --> false




    다음 예제를 직접 해보자.



    Operator6.java



    public class Operator6{

    public static void main(String[] args){

    int a=1;

    int b=2;

    System.out.println(a==b);

    System.out.println(a>b);

    System.out.println(!(a>b));

    System.out.println(b==2);

    System.out.println(!(a!=b));

    System.out.println();



    System.out.println(true==false);

    System.out.println(true==(1>0));

    System.out.println(!!!!true);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    false

    false

    true

    true

    false



    false

    true

    true


    --------------------------------------------------------------------------------







    일반 논리 연산자(&&, ||)

    AND와 OR 개념으로 결과 값은 boolean이다.



    'A && B'는 'A 그리고 B' 라는 뜻으로 A, B 모두 true일 때, 그 값은 true이다.



    A
    B
    A && B

    true
    true
    true

    true
    false
    false

    false
    true
    false

    false
    false
    false


    [표 3-5] AND(&&) 연산



    'A || B'는 'A 또는 B' 라는 뜻으로 A또는 B가 true일 때 true가 된다.



    A
    B
    A || B

    true
    true
    true

    true
    false
    true

    false
    true
    true

    false
    false
    false



    [표 3-6] OR(&&) 연산



    다음 코드들의 출력 결과를 검토하자.



    System.out.println( true && true ); // 출력 결과: true


    System.out.println( false && true ); // 출력 결과: false



    System.out.println( false && false ); // 출력 결과: false



    System.out.println( true || true ); // 출력 결과: true



    System.out.println( false || true ); // 출력 결과: true



    System.out.println( false || false ); // 출력 결과: false





    이제 약간 응용한 코드를 살펴보자.



    System.out.println( (30>20) && (20==20) ); // 출력 결과: true




    관계 연산자가 논리 연산자보다 우선 순위가 높으므로 다음과 같이 할 수도 있다.



    System.out.println( 30>20 && 20==20 ); // 출력 결과: true




    아래 코드는 약간 복잡하다.



    System.out.println( (30>20) && (20==20) && (1<0) ); // 출력 결과: false




    위 코드의 연산 순서를 아래에 적었다. 괄호 안을 먼저 연산한다.



    (30>20) && (20==20) && (1<0) ) -> (true && true) && false

    -> true && false -> false




    아래 예제를 직접 실행 해보자.



    Operator7.java



    public class Operator7{

    public static void main(String[] args){

    System.out.println((30>20 || 10!=10) && 20<10);

    System.out.println(30>20 || (10!=10 && 20<10));

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    false

    true


    --------------------------------------------------------------------------------





    아래 예제의 출력 결과를 검토하자.



    Operator8.java



    public class Operator8{

    public static void main(String[] args){

    int a=10;

    System.out.println((a=20)==20);

    System.out.println(a);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    true

    20


    --------------------------------------------------------------------------------



    알아두기


    Short-Circuit

    A&&B : 만약 A가 false이면, 이 식은 B와 관계없이 false가 되므로 B는 연산하지 않는다.

    A||B : A가 true이면 B와 관계없이 연산 결과 값은 true가 되므로 B는 연산하지 않는다.



    &&, ||는 최소 단위 연산자이다.





    Short-Circuit에 관한 예제를 해보자.



    Operator9.java



    public class Operator9{

    public static void main(String[] args){

    int a=10;

    System.out.println((a>0)&&(a=20)>10);

    System.out.println(a);

    int b=10;

    System.out.println((b<0)&&(b=20)>10); // x1

    System.out.println(b);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    true

    20

    false

    10


    --------------------------------------------------------------------------------





    x1행에서 b<0이 false이므로 (b=20)>10은 연산되지 않는다.





    비트 논리 연산자(&, |, ^)

    &: 비트로 AND연산을 한다(논리곱).

    |: 비트로 OR연산을 한다(논리합).

    ^: 비트로 Exclusive OR연산을 한다(배타 논리합).



    A & B: 같은 위치의 비트를 비교해서 모두 1이면 그 결과 값도 1이 되고 나머지 경우는 모두 0이 된다.



    Operator10.java




    public class Operator10{

    public static void main(String[] args){

    int a=14, b=12;

    System.out.println(a&b);

    }

    }



    --------------------------------------------------------------------------------



    출력 결과





    12




    --------------------------------------------------------------------------------



    a는 2진수로 1110이고, b는 2진수로 1100이다. 'a&b'는 2진수로 1100인데 10진수로는 12이다.



    a ->

    b ->

    a&b ->
    1110

    1100

    1100




    a=3이고 b=10이면 a&b는 2이다.



    a ->

    b ->

    a&b ->
    0011

    1010

    0010





    A | B: 같은 위치의 비트를 비교해서 둘 중 하나가 1이면 그 결과가 1이 된다. 나머지 경우, 즉, 같은 위치의 비트가 모두 0이면 그 결과는 0이다.



    a=14이고 b=12이면 a|b=14이다.



    a ->

    b ->

    a|b ->
    1110

    1100

    1110




    a=3이고 b=10이면 a|b는 11이다.

    a ->

    b ->

    a|b ->
    0011

    1010

    1011





    A ^ B: 같은 위치의 비트를 비교해서 서로의 값이 다르면 그 결과가 1이 된다. 나머지 경우, 즉 같은 위치의 비트가 서로 같은 값이면 그 결과는 0이다.



    a=14이고 b=12이면 a^b는 2이다.



    a ->

    b ->

    a^b ->
    1110

    1100

    0010




    a=3이고 b=10이면 a^b는 9이다.



    a ->

    b ->

    a^b ->
    0011

    1010

    1001








    3항 연산자(?:)



    조건식? 값1 : 값2




    조건식이 참이면 결과는 값1이 되고 조건식이 거짓이면 결과는 값2가 된다.



    boolean b=20>10? true : false;




    20>10은 참이므로 b에는 true가 대입된다.



    int a=20<10?30:-2;




    20<10은 거짓이므로 a는 -2이다.



    다음 예제를 검토하자.



    Operator11.java



    public class Operator11{

    public static void main(String[] args){

    System.out.println(true?10:20);

    System.out.println(false?10:20);

    System.out.println((3>2)&&(2<3)?10:20);

    int b=50>20&&30>10?50:100; // 연산자 우선 순위를 생각하자.

    System.out.println(b);

    }

    }


    --------------------------------------------------------------------------------

    출력 결과




    10

    20

    10

    50


    --------------------------------------------------------------------------------



    혼자 해보기
    Alone3_2.java





    어떤 정수 n(=20)의 값이 양수인지 음수인지 구분하는 프로그램을 작성해보자.

    출력 결과 예시






    20은 양수이다.




    --------------------------------------------------------------------------------







    대입 연산자

    이제 마지막으로 대입 연산자를 살펴보자. '='연산자가 바로 대입 연산자이다. 이 연산자는 앞에서부터 사용해 왔기 때문에 다른 설명이 필요 없을 것으로 생각된다. 그러나 '='연산자 외에도 '+=', '-=', '*=', '/=', '&=', '^=', '|=' 등의 대입 연산자가 있다. '='연산자를 순수 대입 연산자라고 한다.



    int a=1;

    a+=5;

    System.out.println(a); // 출력 결과: 6




    'a+=5'는 'a=a+5'와 같은 의미이다. a와 5를 더한 값을 a에 대입한다.



    int a=10;

    a-=6;

    System.out.println(a); // 출력 결과: 4




    'a-=6'은 'a=a-6'과 같은 의미이다. 'a-6'을 a에 대입한다. 결과적으로 a는 4가 된다.

    'Developer > Java' 카테고리의 다른 글

    [Java] ThreadLocal 사용법과 활용  (0) 2013.08.14
    [Java] PID 추출  (0) 2013.08.12
    2013 코드잼 - Problem C.  (0) 2013.04.19
    2013 코드잼 - Problem B.  (0) 2013.04.16
    2013 코드잼 - Problem A. Tic-Tac-Toe-Tomek  (0) 2013.04.16
© 2018 T-Story. All right reserved.