1장 자바 프로그래밍 기초(1)

2023. 12. 13. 17:47프로그래밍 공부/Data Structure

 1.1 시작하기: 클래스, 타입 및 객체

자료 구조와 알고리즘을 구축하려면 컴퓨터에 상세한 명령어를 전달해야 하는데, 
자바와 같은 고급 컴퓨터 언어를 사용하는 것이 이 장에서 아주 좋은 방법이다.
이 장에서는 독자가 기존의 고급 언어에 어느 정도 익숙하다고 가정하고
자바 프로그래밍 언어에 대해 간략하게 설명한다.
그러나 이 책에서는 자바 언어에 대한 완벽한 설명을 제공하지는 않다.
여기에 포함되지 않은 스레드나 소켓과 같이
자료 구조 설계와 직접적인 관련이 없는 언어의 주요 측면이 있다.
자바에 대해 더 많이 알고 싶은 독자는 이 장의 마지막 부분을 참조하자.
먼저 화면에 "Hello Universe!"를 인쇄하는 프로그램으로 시작하는데,
이 프로그램은 그림 1.1의 해부된 형태이다.

그림 1.1: "Hello Universe!" 프로그램.

 

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

1st Line

public: this says anyone can run this program

class: all code in a Java program must belong to a class

Universe: the name of this class

{: curly brace for the class body

 

2nd Line

public: anyone can run this method

static: this method belongs to the class, not an object(more on this later)

void: this method doesn't return anything

main: the name of this method

(String[] args): the parameters passed to this method

(in this case the arguemnts on the command line as an array of strings)

 

3rd Line

System.out.println: the name of the method we want to call

(in this case the method for printing strings on the screen)

("Hello Universe!"): the prameter passed to this method

(in this case the string we want to print)

; semicolon indicating the end of this statement

 

4rd Line

}: curly brace for closing the method body

 

5rd Line

}: curly brace for closing the class

 

자바 프로그램에서 주된 "액터"는 객체이다.

객체(object): 데이터를 저장하고 이 데이터에 접근하고 수정하기 위한 방법을 제공한다.

모든 객체는 클래스의 인스턴스이다.

클래스(class): 객체의 타입(type)뿐만 아니라 객체가 수행하는 연산의 종류를 정의한다.

자바에서 클래스의 중요한 멤버(member)는 다음과 같다

(클래스는 내부 클래스 정의도 포함할 수 있지만 이 개념에 대한 논의는 일단 미루자):

1) 인스턴스 변수(instance variable) (= 필드(field)라고도 함)

 Java 객체의 데이터는 인스턴스 변수에 저장된다.

따라서 일부 클래스의 객체가 데이터를 저장하려면

해당 클래스에서 해당 객체의 인스턴스 변수를 지정해야 한다.

인스턴스 변수는 기본 타입(예: 정수, 부동 소수점 숫자 또는 Boolean)에서 가져올 수도 있고

다른 클래스의 객체를 참조할 수도 있다.

2) 메소드(method)

메소드: 객체가 반응하는 "메시지"를 표현하는 데이터에 작용할 수 있는 연산

이것들은 생성자, 프로시저 및 함수로 구성된다.

그들은 해당 클래스의 객체의 동작을 정의한다.


클래스가 선언되는 방법

간단히 말해서, 객체는 데이터와 그 데이터를 처리하고 통신할 수 있는 방법의 특정한 조합이다.

클래스는 객체의 타입을 정의한다.

그러므로, 객체는 해당 클래스의 이름을 타입으로 사용하기 때문에

정의 클래스의 인스턴스로 불리기도 한다.

Java 클래스의 정의에 대한 예는 코드 조각 1.1에 나와 있다.
코드 조각 1.1: 접근, 증가 및 감소가 가능한 단순 카운터용 Counter 클래스이다.

public class Counter{
    protected int count; // a simple integer instance variable
    /** The default constructor for a Counter object */
    Counter() { counter = 0; }
    /** An accessor method to get the current count */
    public int getCount() { return count; }
    /** A modifier methdo for incrementing the count */
    public void incrementCount() { count++; }
    /** A modifier method for decrementing the count */
    public void decrementCount() { count--;}
}

이 예제에서 클래스 정의는 괄호로 구분되며, 즉 "{""로 시작하여 "}"로 끝나는 것에 주목하자.

자바에서 괄호 "{"와 "}" 사이의 문장 집합은 프로그램 블록(block)을 정의한다.

Universe 클래스와 마찬가지로 Counter 클래스도 공개(public)되므로 

다른 클래스에서도 Counter 객체를 생성하여 사용할 수 있다.

 

Counter - 생성자 메소드

count라는 정수인 인스턴스 변수가 하나 있다.

이 변수는 Counter에서 0으로 초기화된다.

이 메소드는 새 Counter 객체를 만들고자 할 때 Counter로 호출된다.

 

getCount - 접근자 메소드

이 메소드는 카운터의 현재 값을 반환한다.

 

업데이트 메소드

incrementCount - 카운터를 증가시키는 메소드

decremntCount - 카운터를 감소시키는 메소드

 

이것은 Java 클래스의 구문과 구조를 보여준다.

또한 Java 클래스에 main 메소드가 필요하지 않음을 보여준다

(그러나 이러한 클래스는 자체적으로 아무것도 수행할 수 없다).

식별자(identifier): Java에서 클래스, 메소드 또는 변수의 이름

식별자는 문자로 시작하고 문자, 숫자 및 밑줄 문자로 구성되어 있으면 모든 문자열이 될 수 있다.

(여기서 "글자" 및 "숫자"는 유니코드 문자 집합에 정의된 모든 문자 언어에서 사용할 수 있다).

Java 식별자에 대한 이 일반 규칙의 예외를 표 1.1에 나열한다.

표 1.1: 자바에서 예약어(reversed word)들의 목록. 

자바에서 이 이름들은 메소드나 변수 이름으로 사용될 수 없다.

예약어
abstract, else, interface, switch, boolean, extends, long, synchronized, break, false,

native, this, byte, final, new, throw, case, finally, null, throws,

catch, float, package, transient, char,for, private, true, class, goto,

protected, try, const, if, public, void, continue, implements, return, volatile, default,

import, short, while, do, instanceof, static, double, int, super

 

 

 

클래스 수식어

클래스 수식어(class modifier): class 키워드 앞에 오는 선택 키워드

우리는 이미 public 키워드를 사용하는 예를 보았다.

일반적으로 다른 클래스 수식어와 그 의미는 다음과 같다:

 

abstract 클래스 수식어: abstract 메소드를 가지는 클래스

abstract 메소드는 abstract 키워드로 선언되고 비어 있다

(즉, 이 메소드에 대한 코드 본문을 정의하는 블록이 없다).

인터페이스(interface): abstract 메소드만 있고 인스턴스 변수가 없는 클래스

abstract 클래스는 일반적으로 abstract 메소드와 실제 메소드가 혼합된다

(2.4절에서 abstract 클래스와 그 사용에 대해 설명한다)

 

final 클래스 수식어: 서브 클래스가 없을 수 있는 클래스

(이 개념에 대해서는 다음 장에서 설명하겠다.)

 

public 클래스 수식어: 동일한 패키지에 포함된 클래스

또는 클래스를 import하는 모든 것에 의해 인스턴스화되거나 확장될 수 있는 클래스

(이에 대해서는 1.8절에서 더 자세히 설명한다.)

public 클래스는 classname. java라는 자신의 별도 파일에서 선언된다.

여기서 "classname"은 클래스의 이름이다.

 

• 기본 클래스 수식어: public 클래스 수식어를 사용하지 않는 경우 클래스

이 때 클래스는 friendly한 것으로 간주된다.

이는 동일한 package의 모든 클래스에서 사용 및 인스턴스화할 수 있음을 의미한다.

 

1.1.1 기본 타입

객체의 타입은 객체가 어떤 클래스에서 기원하는지에 따라 결정된다.

효율성과 단순성을 위해 자바에는 객체가 아닌

다음과 같은 기본 타입(base type)(원형(primitive) 타입이라고도 함)도 있다:
boolean : 부울 값: true 또는 false

char : 16비트 유니코드 문자
byte : 8비트 부호화된(singed) 2의 보수(complement) 정수
short : 16비트 부호화된 2의 보수 정수

int : 32비트 부호화된 2의 보수 정수
long : 64비트 부호화된 2의 보수 정수
float : 32비트 부동 소수점 번호(IEEE 754-1985)
double : 64비트 부동 소수점 번호(IEEE 754-1985)

 

이러한 유형 중 하나를 갖는다고 선언된 변수는

어떤 객체에 대한 참조가 아니라 단순히 해당 유형의 값을 저장한다.

정수 상수들, 예를 들어 14나 195는

'L'이나 'l'이 바로 뒤따르지 않는 한 int 타입이며,

이 경우 그들은 long 타입이다.

부동소수점 상수들, 예를 들어 3.1415나 2.158e5는

'F'나 'f'가 바로 뒤따르지 않는 한 double 타입이 되며,

이 경우 그들은 float 타입이다.

코드 조각 1.2에서 많은 기본 타입을

main 메소드의 지역 변수로 정의하는 간단한 클래스를 보여준다.
코드 조각 1.2: 기본 타입의 사용 예를 보여주는 Base 클래스.

public class Base {
    public static void main (String[] args) {
        boolean flag = true;
        char ch = 'A';
        byte b = 12;
        short s = 24;
        int i = 257;
        long l = 890L;        // note the use of "L" here
        float f = 3.1415F;    // note the use of "F" here
        double d = 2.1828;
        System.out.println("flag = " + flag); // the "+" is the string concatenation
        System.out.println("ch = " + ch);
        System.out.println("b = " + b);
        System.out.println("s = " + s);
        System.out.println("i = " + i);
        System.out.println("l = " + l);
        System.out.println("f = " + f);
        System.out.println("d = " + d);
    }
}

코멘트

이 예와 다른 예에서 주석을 사용하는 것에 주목하자.

이러한 주석은 사람이 읽을 수 있도록 제공되는 주석이며 자바 컴파일러에 의해 처리되지 않다.

자바는 두 종류의 주석 - 블록 주석과 인라인 주석 - 을 허용하며,

이는 컴파일러가 무시하는 텍스트를 정의한다.

 

블록 주석(block comment)

시작할 때 /*를 사용하고 닫으려면 */를 사용한다.

특히 /**로 시작하는 주석은 자바독(Javadoc)이라는 프로그램이 이러한 주석을 읽고

자바 프로그램에 대한 문서를 자동으로 생성할 수 있도록 해주는 특별한 형식을 가지고 있다.

1.9.3절에서 자바독 주석의 구문과 해석에 대해 설명한다.

 

인라인 주석(inline comment)
//를 사용하여 인라인 코멘트를 시작하고, 라인 상의 다른 모든 것을 무시한다.

 

이 책에 표시된 모든 코멘트는 실행 코드와 혼동되지 않도록 파란색으로 칠해질 것이다.

예를 들어 다음과 같다:

/*
* This is a block comment.
*/

 

// This is an inline comment.

 

Base 클래스의 출력

Base 클래스(main 메소드) 실행의 출력은 그림 1.2와 같다.

 

그림 1.2: Base 클래스의 출력이다.

flag = true

ch = A

b = 12

s = 24

i = 257

l = 890

f = 3.1415

d = 2.1828


기본 타입 변수는 객체를 참조하지는 않지만

객체 내부의 인스턴스 변수(또는 필드)를 구성하는 경우가 많기 때문에

객체의 컨텍스트에서 유용한다.

예를 들어 Counter 클래스(코드 조각 1.1)에는 int 타입의 단일 인스턴스 변수가 있다.

자바에서 기본 유형의 또 다른 좋은 특징은

기본 타입 인스턴스 변수가 포함된 객체를 생성할 때 항상 초기 값이 주어진다는 것이다

(타입에 따라 0, false 또는 null 문자).


1.1.2 객체

자바에서 new 연산자를 사용하여 정의된 클래스로부터 새로운 객체를 만든다.

new 연산자: 지정된 클래스로부터 새로운 객체를 만들고 그 객체에 대한 참조(reference)를 반환한다.

특정한 종류의 새로운 객체를 만들기 위해서

우리는 그 종류의 객체에 대한 생성자에게 호출하여 new 연산자를 즉시 사용해야 한다.

우리는 (괄호 사이에 인수가 없는) 기본 생성자를 포함하여 클래스 정의에 포함된 모든 생성자를 사용할 수 있다.

그림 1.3에서 우리는 단순히 새로운 객체를 생성하기 위한 것과

이 객체들에 대한 참조를 변수에 할당하기 위한 new 연산자의 여러 가지 해부된 예제를 보여준다.


그림 1.3: new 연산자의 사용 예.

public class Example {
    public static void main (String[] args) {
        Counter c;
        Counter d = new Counter();
        c = new Counter();
        d = c;
    }
}

 

1st Line

Example : the name of this class

 

2st Line

public static void main (String[] args) : standard syntax for declaring a main method

 

3rd Line

Counter c; : declares the variable be of type Counter;

that is, c can refer to any Counter object

 

4rd Line

Counter d : declares the variable d to be of type Counter

= : assigns the reference to the new object to the variable d

new Counter() : creates a new Counter object and returns a reference to it

 

5rd Line

= : assigns the reference to the new object to the variable c

new Counter() : creates a new Counter object and returns a reference to it

 

6rd Line

= : assigns d to reference the same object as c

(the old object d was pointing to now has no variable referencing it)

 

클래스 타입에서 new 연산자를 호출하면 다음 세 가지 이벤트가 발생한다:
• 새 객체가 메모리에 동적으로 할당되고 모든 인스턴스 변수가 표준 기본값으로 초기화된다.

기본값은 객체 변수의 경우 null이고 부울 변수(기본값은 false)를 제외한 모든 기본 타입의 경우 0이다.
• 지정된 매개 변수를 사용하여 새 객체에 대한 생성자를 호출한다.

생성자는 인스턴스 변수에 대한 의미 있는 값을 입력하고

이 객체를 생성하기 위해 수행해야 하는 추가 계산을 수행한다.
• 생성자가 반환된 후, new 연산자는 새로 생성된 객체에 대한 참조(즉, 메모리 주소)를 반환한다.

식이 할당문 형태일 경우, 이 주소는 객체 변수에 저장되므로

객체 변수는 새로 생성된 객체를 참조한다.

 

숫자 객체

우리는 때때로 숫자를 객체로 저장하고 싶지만,

우리가 언급한 것처럼 기본 유형의 숫자는 그 자체가 객체가 아니다.

숫자 클래스(number class): 각 숫자 기본 타입의 래퍼(wrapper) 클래스

표 1.2에서 숫자 기본 타입과 해당 숫자 클래스를

숫자 객체가 생성되고 액세스되는 방법의 예와 함께 보여준다.

자바 5.0 이후로

기본 숫자를 해당 객체를 예상하는 메소드에 전달할 때마다

생성 작업이 자동으로 수행된다.

마찬가지로 해당 액세스 방법은

기본 번호 유형에 해당 Number 객체의 값을 할당하고자 할 때마다

자동으로 수행된다.

 

표 1.2: 자바 숫자 클래스

각 클래스는 해당되는 기본 타입과 그러한 객체를 생성하고

액세스하기 위한 예제 식으로 제공된다.

각 행에 대해 변수 n이 해당 클래스 이름으로 선언된다고 가정한다.

 

Base Type
Class Name
Creation Example
Access Example


byte
Byte
n = new Byte((byte)34);

n.byteValue( )

 

short
Short
n = new Short((short)100);

n.shortValue( )

 

int
Integer
n = new Integer(1045);

n.intValue( )

 

long
Long
n = new Long(10849L);

n.longValue( )

 

float

Float

n = new Float(3.934F);

n.floatValue( )

 

double

Double

n = new Double(3.934);

n.doubleValue( )

 


문자열 객체

문자열: 일부 알파벳(가능한 모든 문자의 집합)에서 오는 문자 시퀀스

문자열을 구성하는 각 문자 c는 문자열 내 인덱스로 참조할 수 있는데,

이는 c 앞에 오는 문자의 수와 동일하다

(따라서 첫 번째 문자는 인덱스 0).

자바에서 문자열을 정의하는 데 사용되는 알파벳은 유니코드 국제 문자 집합이며,

대부분의 문자 언어를 다루는 16비트 문자 인코딩이다.

다른 프로그래밍 언어에서는

더 작은 ASCII 문자 집합

(7비트 인코딩 기반의 유니코드 알파벳의 적절한 부분 집합)을

사용하는 경향이 있다.

또한 자바는 문자열 객체라는 특별한 내장 객체 클래스를 정의한다.

 

예시1)

문자열 P는 "hogs and dogs" 일 수 있다,
길이가 13이고 누군가의 웹 페이지에서 왔을 수 있다.

이 경우, 인덱스 2의 문자는 'g'이고 인덱스 5의 문자는 'a'이다.

 

예시2)

문자열 P는

길이가 16이고 알파벳이 {G, C, A, T}인

DNA 염기 서열 결정에 대한 과학적인 응용에서 왔을 수 있는

문자열 "CGTAATAGTTAATCCG"일 수 있다.

 

연결

문자열 처리: 문자열을 처리하는 것을 포함한다.

연결(concatenation): 문자열을 결합하는 기본 연산

문자열 P와 문자열 Q를 결합하여 P+Q로 표시되며,

문자열 P의 모든 문자 다음에 Q의 모든 문자로 구성된다.

 

자바에서 "+" 연산은 두 문자열에 대해 동작할 때 정확히 이와 같이 동작한다.

따라서 자바에서는 다음과 같은 할당문을 작성하는 것이 합법적이다

Strings = "kilo" + "meters";


이 문은 String 클래스의 객체를 참조하는 변수를 정의하고 "kilometer" 문자열을 할당한다.

(위와 같은 할당문 및 수식에 대해서는 이 장의 뒷부분에서 더 자세히 설명하겠다.)

 

Java의 모든 객체는 객체와 연결된 문자열을 반환하는 toString() 메소드가 내장되어 있다고 가정한다.

String 클래스에 대한 설명은 대부분의 용도로 충분해야 한다.

12.1절에서 String 클래스와 "상대적" StringBuffer 클래스에 대해 더 자세히 설명한다.

 

객체 참조

위에서 언급한 바와 같이 새로운 연산자를 사용하여 객체의 메모리 공간을 할당하고

객체의 생성자를 사용하여 이 공간을 초기화하는 작업을 수행한다. 

그런 다음 일반적으로 참조(reference) 변수에는 주소가 할당된다.

주소(address): 객체의 메모리 공간의 위치

따라서 참조 변수는 어떤 객체에 대한 "포인터"로 간주될 수 있다.

마치 그 변수가 새로 생성된 객체(장치)를 제어하는 데 사용할 수 있는

리모컨의 홀더인 것처럼 말이다.

즉, 그 변수는 객체를 가리키며 객체에게 어떤 작업을 수행하도록 요청하거나

해당 객체의 데이터에 접근하도록 요청하는 방식을 가지고 있다.

그림 1.4에서 이 개념을 보여준다.


그림 1.4: 객체와 객체 참조 변수의 관계를 보여준다. 

객체 참조(즉, 메모리 주소)를 참조 변수에 할당하면

마치 해당 객체의 리모컨을 해당 변수에 저장하는 것과 같다.

이 중에서 특정 메소드 호출을 위해 수행할 실제 메소드를 결정한다.

 

다음 예를 생각해보자:

oven.cookDinner();

oven.cookDinner(food);

oven.cookDinner(food, seasoning)


이 메소드 호출들 각각은 실제로 오븐이 속한 클래스에 정의된 이름과 같은 다른 메소드를 지칭한다.

그러나 자바에서 메소드의 시그니처에는 메소드가 반환하는 타입이 포함되어 있지 않으므로

자바에서는 동일한 시그니처를 가진 두 메소드가 다른 타입을 반환하는 것을 허용하지 않다.


인스턴스 변수

Java 클래스는 인스턴스 변수(instance variable)를 정의할 수 있으며, 이를 필드(field)라고도 한다.

인스턴스 변수: 클래스의 객체와 관련된 데이터를 나타낸다.

인스턴스 변수는

기본 타입(base type)(예: int, float, double) 또는

참조 타입(reference type)(예: 리모콘 유추)일 수 있는 타입(type),

즉 String 인터페이스(섹션 2.4 참조) 또는

배열(섹션 1.5 참조)과 같은 클래스가 있어야 한다.

기본 타입 인스턴스 변수는 해당 기본 타입의 값을 저장하고

클래스 이름으로 선언된 인스턴스 변수는 해당 클래스의 객체에 대한 참조를 저장한다.

 

객체 참조를 리모컨으로 시각화하는 비유를 계속해서, 

인스턴스 변수는 리모컨에서 읽거나 설정할 수 있는 장치 매개 변수와 같다

(텔레비전 리모컨의 볼륨과 채널 컨트롤 등).

어떤 객체 o를 가리키는 참조 변수 v가 주어지면,

접근 규칙이 허용하는 o에 대한 모든 인스턴스 변수에 접근할 수 있다.

예를 들어, public 인스턴스 변수는 모든 사람이 접근할 수 있다.

점 연산자를 사용하여 산술 표현에서 v.i를 사용하는 것만으로

그러한 인스턴스 변수 i의 값을 얻을 수 있다.

마찬가지로, 할당 연산자("=")의 왼쪽에 v.i를 써서

그러한 인스턴스 변수 i의 값을 설정(set)할 수 있다. (그림 1.5 참조)

예를 들어,

Gnome이 public 인스턴스 변수 name과 age를 가진

Gnome 객체를 가리킨다면,

다음과 같은 문장이 허용된다:

gnome.name = "Professor Smythe";

gnome.age = 132;


또한 객체 참조는 참조 변수일 필요는 없다.

또한 객체 참조를 반환하는 모든 식이다.
그림 1.5: 객체 참조를 사용하여

객체의 인스턴스 변수를 가져오고 설정하는 방법을 보여준다

(해당 변수에 대한 액세스가 허용된다고 가정할 때).

 

변수 수식어

어떤 경우에는 객체의 인스턴스 변수 중 일부에 직접 접근하는 것이 허용되지 않을 수도 있다.

예를 들어, 일부 클래스에서 private로 선언된 인스턴스 변수는

해당 클래스 내부에 정의된 메소드에 의해서만 액세스할 수 있다.

그러한 인스턴스 변수는 리모컨에서 직접 액세스할 수 없는 장치 매개 변수와 비슷하다.

예를 들어, 일부 장치에는 공장 기술자가 읽거나 할당할 수 있는 내부 매개 변수만 있다

(사용자는 장치의 보증을 위반하지 않고 해당 매개 변수를 변경할 수 없다).


인스턴스 변수를 선언할 때

그런 변수 수식자를 선택적으로 정의한 다음

변수의 유형과 해당 변수에 사용할 식별자를 정의할 수 있다.

또한 할당 연산자("=")를 사용하여 변수에 초기 값을 선택적으로 할당할 수 있다.

변수 이름에 대한 규칙은 다른 Java 식별자와 동일하다.

변수 유형 매개 변수는 기본 유형일 수도 있고,

이 변수가 이 클래스의 객체에 대한 참조임을 나타내는 클래스 이름일 수도 있다.

마지막으로 인스턴스 변수에 할당할 수 있는 선택적인 초기 값은 변수의 유형과 일치해야 한다.

예를 들어 코드 조각 1.3과 같이 Gnome 클래스를 정의할 수 있다.

 

인스턴스 변수의 범위(scope)(또는 가시성)는 다음 변수 수식어를 사용하여 제어할 수 있다:
public: 공개 인스턴스 변수는 누구나 접근할 수 있다.
protected: 동일한 패키지 또는 해당 하위 클래스의 메소드만 사용할 수 있다
보호된 인스턴스 변수에 액세스한다.
private: 하위 클래스의 메소드가 아닌 동일한 클래스의 메소드만 개인 인스턴스 변수에 액세스할 수 있다.
• 만약 위의 수식어들 중 어느 것도 사용되지 않는다면, 인스턴스 변수는 우호적인 것으로 간주된다.

우호적인 인스턴스 변수들은 동일한 패키지 내의 모든 클래스에 의해 접근될 수 있다.

패키지들은 1.8절에서 더 자세히 논의된다.


범위 변수 수식어 외에도 다음과 같은 사용 수식자가 있다:
static : static 키워드는 해당 클래스의 개별 인스턴스가 아닌 해당 클래스와 연관된 변수를 선언하는 데 사용된다.

static 변수는 클래스에 대한 "전역" 정보를 저장하는 데 사용된다

(예를 들어, 생성된 Gnome 객체의 총 수를 유지하기 위해 static 변수가 사용될 수 있다).

static 변수는 해당 클래스의 인스턴스가 생성되지 않더라도 존재한다.
 final: final 인스턴스 변수는 초기값을 할당해야 하는 변수이며, 그 이후에는 절대 새로운 값을 할당할 수 없다.

만약 기본형이라면 상수이다(그놈 클래스의 MAX_HEIGHT 상수처럼).

객체 변수가 final이라면, 객체 변수는 항상 동일한 객체를 참조할 것이다(그 객체가 내부 상태를 변경하더라도).

 

코드 조각 1.3: Gnome 클래스.

public class Gnome{
  // Instance variables:
  public String name;
  public int age;
  public Gnome gnomeBuddy;
  private boolean magical = false;
  protected double height = 2.6;
  public static final int MAX_HEIGHT = 3;// maximum height
  // Constructors:
  Genome(String nm, int ag, Gnome bud, double hgt) {// fully parameterized
    name = nm;
    age = ag;
    gnomeBuddy = bud;
    height = hgt;
  }
  Gnome() { // Default constructor
    name = "Rumple";
    age = 204;
    gnomeBuddy = null;
    height = 2.1;
  }
  // Methods:
  public static void makeKing (Gnome h) {
    h.name = "King " + h.getRealName();
    h.magical = true; // Only the Gnome class can reference this field.
  }
  public void makeMeKing(){
    name = "King " + getRealName();
    magical = true;
  }
  public boolean isMagical() { return magical; }
  public void setHeight(int newHeight) { height = newHeight; }
  public String getName() { return "I won't tell!";}
  public String getRealName() { return name; }
  public void renomeGnome(String s) { name = s; }
}

 

 Gnome 예제에서 인스턴스 변수의 사용을 주목하자.

변수 이름은 기본 타입이고,

변수 이름은 기본 클래스 String의 인스턴스를 참조하며,

변수 gnomeBuddy는 현재 정의하고 있는 클래스의 객체를 참조한다.

Gnome 클래스에서 인스턴스 변수 MAX_HEIGHT의 선언은

이 두 가지 수식어를 이용하여 다음을 수행한다

고정된 상수 값을 가지는 "변수"를 정의한다.

실제로, 클래스와 연관된 상수 값은 항상 staticfinal로 선언되어야 한다.

 

1.1.3 열거형

자바는 5.0부터 enum이라고 불리는 열거된 타입들을 지원한다.

이러한 타입들은 지정된 이름 집합에서 오는 값을 가져 오는 것만 허용된다.

이러한 타입들은 다음과 같이 클래스 내부에 선언된다:

modifier enum name { value_name0, value_name1, ..., value_namen-1 };


여기서 수식어는 공백, public, protected 또는 private가 될 수 있다.

이 열거형의 이름, name은 임의의 합법적인 자바 식별자가 될 수 있다.

각각의 값 식별자, value_namei는 이 열거형의 변수가 취할 수 있는 가능한 값의 이름이다.

각각의 이름 값은 임의의 합법적인 자바 식별자가 될 수 있지만,

자바 규칙은 이러한 값들은 대개 대문자로 된 단어가 되어야 한다는 것이다.

예를 들어, 다음 열거형 정의는 날짜를 처리해야 하는 프로그램에서 유용할 수 있다:

public enum Day { MON, TUE, WED, THU, FRI, SAT, SUN };


정의가 끝나면 클래스 이름처럼 이와 같은 enum 타입을 사용하여 다른 변수를 정의할 수 있다.

그러나 자바는 열거형에 대한 값 이름을 모두 알고 있기 때문에

문자열 식에 enum 타입을 사용하면 자바는 자동으로 해당 이름을 사용하게 된다.

열거형에는 메소드 valueOf를 포함한 몇 가지 메소드가 내장되어 있다.

메소드 valueOf: 주어진 문자열과 동일한 enum 값을 반환한다.

코드 조각 1.4에서 열거형을 사용한 예를 보여준다.


Code Fragment 1.4: 열거형의 사용 예이다.

public class DayTripper{
  public enum Day {MON, TUE, WED, THU, FRI, SAT, SUN};
  public static void main(String[] args) {
    Day d = Day.MON;
    System.out.println ("Initially d is " + d);
    d = Day.WED;
    System.out.println("Then it is " + d);
    Day t = Day.valueOf("WED");
    System.out.println("I say d and t are the same: " + (d == t));
  }
}

The output from this program is:

Initially d is MON

Then it is WED

I say d and t are the same: true

 

1.2 메소드

자바의 메소드: 개념적으로 다른 고급 언어의 함수 및 프로시저와 유사하다.

일반적으로, 그것들은 (일부 클래스에서) 특정한 대상에 대해 호출될 수 있는 코드의 "덩어리"이다.

메소드는 파라미터를 인수로 받아들일 수 있고,

그것들의 동작은 그것들이 속한 오브젝트와 전달되는 파라미터의 값에 따라 달라진다.

자바의 모든 메소드는 일부 클래스의 본문에 지정된다.

메소드 정의에는 두 부분이 있다:

  1. 시그니처(signiture) - 메소드에 대한 및 파라미터를 정의한다.
  2. 본문(body) - 메소드가 수행하는 것을 정의한다.

메소드는 프로그래머가 물체에 매시지를 보낼 수 있게 해준다.

메소드 시그니처는 그런 메시지가 어떻게 보여야 하는지를 지정하고

메소드 본문은 물체가 그런 메시지를 받았을 때 무엇을 할지 지정한다.


선언 메소드

메소드를 정의하는 구문은 다음과 같다:

modifiers type name(type0 parameter0, ..., typen_1 parametern_1) {

    // method body ...

}

이 선언문의 각 부분은 중요한 용도를 가지며, 이 부분에서 자세히 설명한다.

modifier 부분: 비슷한 의미를 가진 변수에 사용할 수 있는 동일한 종류의 범위 수식어를 포함한다.

선언문의 type 부분: 메소드의 반환 타입을 정의한다.

name: 메소드의 이름이며, 모든 유효한 Java 식별자가 될 수 있다.

매개 변수 및 해당 유형 리스트: 이 메소드에 인수로 전달할 값에 해당하는 로컬 변수를 선언한다.

각 형식 선언 타입 i: 임의의 Java 타입 이름이 될 수 있고

각 매개 변수 i: 임의의 Java 식별자가 될 수 있다.

매개 변수 및 해당 타입 리스트는 비어 있을 수 있으므로

메소드가 호출될 때 이 메소드에 전달할 값이 없음을 의미한다.

클래스의 인스턴스 변수뿐만 아니라 이러한 매개 변수도 메소드 본문 내에서 사용할 수 있다.

마찬가지로 메소드 본문 내에서 이 클래스의 다른 메소드를 호출할 수 있다.


클래스의 메소드가 호출되면

해당 클래스의 특정 인스턴스에서 호출되며 해당 객체의 상태를 변경할 수 있다

(클래스 자체와 관련된 정적 메소드는 제외).

예를 들어, 특정 gnome에서 다음 메소드를 호출하면 해당 메소드의 이름이 변경된다.

public void renameGnome (String s) {
    name = s;
// Reassign the name instance variable of this gnome.

}

 

메소드 수식어

인스턴스 변수와 마찬가지로 메소드 수식어는 메소드의 범위를 제한할 수 있다:
public: 누구나 public 메소드을 호출할 수 있다.
protected: 동일한 패키지 또는 하위 클래스의 메소드만 protected 메소드를 호출할 수 있다.
private: 하위 클래스의 메소드가 아닌 동일한 클래스의 메소드만 private 메소드를 호출할 수 있다.
• 위의 수식어들 중 어느 것도 사용되지 않으면, 그 방법은 친절하다.

친절한 방법들은 오직 같은 패키지의 클래스들의 객체들에 의해서만 호출될 수 있다.

 

위의 수식어 앞에는 다음과 같은 수식어가 추가될 수 있다:
abstract: abstract로 선언된 메소드는 코드가 없다.

그런 메소드의 서명 뒤에는 메소드 본문이 없는 세미콜론이 뒤따른다.

예를 들어 다음과 같다:

public abstract void setHeight (double newHeight);

 

abstract 메소드는 추상적 클래스 내에서만 나타날 수 있다.

우리는 2.4절에서 이 구성의 유용성에 대해 논의한다.
final: 이 메소드는 하위 클래스에서 무시할 수 없다.
static : 클래스 자체와 연관된 메소드이며 클래스의 특정 인스턴스와 연관되지 않다.

static 메소드는 클래스와 연관된 정적 변수의 상태를 변경하는 데 사용할 수도 있다

(이러한 변수가 final로 선언되지 않은 경우).

 

반환 타입

메소드 정의는 메소드가 반환할 값의 타입을 지정해야 한다.

메소드가 값을 반환하지 않으면 키워드 void를 사용해야 한다.

프로시저(procedure): 반환 타입이 void인 메소드

함수(function): 반환 타입이 void아닌 메소드

 

Java에서 값을 반환하려면 메소드가 return 키워드를 사용해야 한다.

다음은 함수인 메소드(Gnome 클래스 내부에서)의 예이다:

public boolean isMagical () {

    return magical;

}

 

자바 함수로 return이 수행되자마자 메소드는 종료된다.
자바 함수들은 오직 하나의 값만을 반환할 수 있다.

자바에서 여러 값을 반환하려면,

복합 객체에서 반환하려는 모든 값을 결합한 다음,

그 복합 객체에 대한 참조를 반환해야 한다.

복합 객체(compound object): 인스턴스 변수에 반환하려는 모든 값이 포함된다.

또한 여러 결과를 "반환"하는 또 다른 방법으로 메소드로 전달되는 객체의 내부 상태를 변경할 수 있다.

 

매개변수

메소드의 매개 변수: 메소드 이름 뒤에 괄호로 둘러싸인 쉼표로 구분된 리스트에서 정의된다. 

매개 변수은 두 부분으로 구성된다.

  1. 매개 변수 타입
  2. 매개 변수 이름

메소드에 매개 변수가 없으면 빈 괄호 쌍만 사용된다.

 

자바의 모든 매개변수는 값으로 전달되는데, 

즉 매개변수를 메소드에 전달할 때마다

그 매개변수의 복사본이 메소드 본체 내에서 사용하기 위해 만들어진다. 

따라서 우리가 int 변수를 메소드에 전달하면 그 변수의 정수 값이 복사된다.

메소드는 복사는 변경할 수 있지만 원본은 변경할 수 없다.

만약 우리가 어떤 메소드에 매개변수로서 객체 참조를 전달하면 그 참조도 복사된다.

우리는 모두 동일한 객체를 참조하는 많은 다른 변수를 가질 수 있다는 것을 기억하자.

메소드 내부의 내부 참조를 변경한다고 해서 전달된 참조가 변경되지는 않다.

 

예를 들어, 만약 우리가 이 매개변수 h를 호출하는 메소드에 Gnome 참조 g를 전달한다면,

이 메소드는 참조 h를 다른 객체를 가리키도록 변경할 수 있지만,

g는 여전히 이전과 동일한 객체를 참조할 것이다.

물론 메소드는 참조 h를 사용하여 객체의 내부 상태를 변경할 수 있고,

이것은 g의 객체도 변경할 것이다.

(g와 h는 현재 동일한 객체를 참조하고 있으므로).

 

생성자

생성자: 새로 생성된 객체를 초기화하는 데 사용되는 특별한 종류의 메소드

자바는 생성자를 선언하는 특별한 방법과 생성자를 호출하는 특별한 방법이 있다.

modifiers name(type0 parameter0, ..., typen_1 parametern_1) {

    // constructor body ...

}


따라서 구문은 기본적으로 다른 메소드의 구문과 동일하지만

몇 가지 중요한 차이점이 있다.

1. 생성자의 이름(name)은 생성하는 클래스의 이름과 동일해야 한다.

    따라서 클래스가 Fish라고 하는 경우 생성자도 Fish라고 불러야 한다.

2. 또한 생성자의 반환 형식을 지정하지 않으므로 반환 형식이 암묵적으로 클래스의 이름과 동일한다.

    위에 수식자로 표시된 생성자 수식어는

    abstract, static 또는 final 생성자가 허용되지 않는다는 점을 제외하고는

    일반적인 방법과 동일한 규칙을 따른다.

 

다음 예는 다음과 같다:

public Fish (int w, String n) {

  weight = w;

  name = n;

}

 

생성자 정의 및 호출

몇 가지 사소한 예외가 있지만, 생성자의 본문은 일반적인 메소드의 본문과 같다.

 

생성자의 본문과 일반적인 메소드의 본문의 차이점

1. 생성자 체이닝(Constructor Chaining)이라는 개념으로,

    2.2.3절에서 설명한 내용이지만 여기서는 중요하지 않다.
2. 생성자 본체에는 반환문이 허용되지 않는다는 것이다.

    생성자 본분는 이 클래스의 객체와 관련된 데이터를 초기화하여

    처음 생성할 때 안정적인 초기 상태에 있도록 하는 데 사용된다.

 

생성자는 고유한 방식으로 호출되는데, 새로운 연산자를 사용하여 호출해야 한다.

따라서 호출 시 이 클래스의 새로운 인스턴스가 자동으로 생성되고 생성자가 호출되어

인스턴스 변수를 초기화하고 다른 설정 작업을 수행한다.

예를 들어 다음과 같은 생성자 호출(myFish 변수에 대한 선언이기도 함)을 생각해 보자:

Fish myFish = new Fish (7, "Wally");


클래스에는 여러 생성자가 있을 수 있지만 각각 다른 시그니처가 있어야 한다
즉, 각각은 사용되는 파라미터의 종류와 개수로 구별되어야 한다.


main 메소드

일부 Java 클래스는 다른 클래스에서 사용하도록 되어 있고,

다른 클래스는 독립 실행형 프로그램으로 되어 있다.

독립 실행형 프로그램을 정의하는 클래스에는

클래스에 대한 다른 특별한 종류의 메소드인 main 메소드가 포함되어 있어야 한다.

독립 실행형 Java 프로그램을 실행하려면

다음 명령을 실행하여 이 프로그램을 정의하는 클래스의 이름을 참조한다:

java Aquarium


이 경우 자바 런타임 시스템은 Aquarium 클래스의 컴파일된 버전을 찾은 다음 

해당 클래스의 특별한 main 메소드를 호출한다.

이 메소드는 다음과 같이 선언되어야 한다:

public static void main(String[] args){

    // main method body ...

}


main 메소드에 매개 변수 args로 전달되는 인수는

프로그램이 호출될 때 주어진 커맨드 라인 인수이다.

args 변수

- String 객체의 배열, 즉 인덱싱된 문자열의 집합이다.

- 첫 번째 문자열은 args[0], 두 번째 문자열은 args[1] 등이다.

- (1.5절에서 배열에 대해 자세히 설명한다.)

 

커맨드 라인에서 Java 프로그램 호출

자바 프로그램은 java 명령어를 사용하여 커맨드 라인에서 호출할 수 있으며, 

그 다음에는 우리가 실행하고자 하는 main 메소드와 임의의 선택적 인수가 뒤따른다.

 

예를 들어, 

Aquarium 프로그램은

수족관에 있는 물고기의 수를 지정하는 임의의 인수를 취하도록 한다.

그런 다음 셸 창에 다음을 입력하여 프로그램을 호출할 수 있다:

java Aquarium 45


45마리의 물고기가 있는 수족관을 원한다고 명시한다.

이 경우 args[0]은 문자열 "45"를 의미한다.

 

클래스 정의에서 main 메소드의 한 가지 좋은 특징은 각 클래스가 독립형 프로그램을 정의할 수 있다는 것이고,

이 메소드를 사용하는 방법 중 하나는 클래스의 다른 모든 메소드를 테스트하는 것아다.

따라서 main 메소드를 철저히 사용하는 것은 자바 클래스의 컬렉션을 디버깅하는 데 효과적인 도구이다.


블록문 및 지역 변수

블록문(statement block): 메소드의 본문은 괄호 "{"와 "}" 사이에서 수행할 문 및 선언의 시퀀스

- 메소드 본문과 다른 블록문은 자체적으로 블록문을 내부에 내포할 수 있다.

- 일부 객체의 메소드를 호출하는 것과 같은 작업을 수행하는 문뿐만 아니라

   블록문에는 지역 변수의 선언이 포함될 수 있다.

 

지역 변수(local variable)

- 이 변수들은 문 본문 내부에서 보통 시작할 때(단, 괄호 "{"와 "}" 사이) 선언된다.

- 인스턴스 변수와 비슷하지만 블록문이 실행되는 동안에만 존재한다.

- 컨트롤 플로우가 해당 블록에서 빠져나오자마자 그 안의 모든 로컬 변수를 더 이상 참조할 수 없다.

- 로컬 변수는 기본 타입(예: int, float, double)이거나 일부 클래스의 인스턴스에 대한 참조일 수 있다.

 

자바의 단일 문 및 선언은 항상 세미콜론, 즉 ";"로 끝난다.
지역 변수를 선언하는 방법에는 두 가지가 있다:

type name;
type name = initial_value;
첫 번째 선언은 단순히 식별자, 이름을 지정된 타입으로 정의한다.

두 번째 선언은 식별자, 그 타입을 정의하고 또한 이 변수를 지정된 값으로 초기화한다.

 

다음은 지역 변수 선언의 몇 가지 예이다:

{
  double r;
  Point p1 = new Point (3, 4);

  Point p2 = new Point (8, 2);

  int i = 512;

  double e = 2.71828;

}

 

1.3 표현식

변수와 상수는 새로운 값을 정의하고 변수를 수정하기 위해 표현식(expression)에서 사용된다.

이 절에서는 자바에서 표현식이 어떻게 작동하는지에 대해 더 자세히 설명한다.

표현식은 리터럴, 변수, 연산자를 사용하는 것을 포함한다.

변수에 대해서는 이미 논의했으므로 리터럴에 초점을 맞춘 다음 연산자에 대해서 자세히 설명하겠다.

 

1.3.1 리터럴

리터럴(literal): 할당이나 다른 식에서 사용할 수 있는 "일정한" 값

자바는 다음과 같은 종류의 리터럴을 허용한다:

• null 객체 참조

(이 참조는 유일한 객체 리터럴이며 일반 Object 클래스에서 가져온 것으로 정의됨).

• 부울: truefalse
• 정수: 176, 또는 -52와 같은 정수의 기본값은 32비트 정수인 int 타입이다.

long 정수 리터럴은 "L" 또는 "l"로 끝나야 하며,

예를 들어 176L 또는 -52l과 같이 64비트 정수를 정의한다.
• 부동 소수점: 3.1415 및 10035.23과 같은 부동 소수점의 기본값은 숫자가 double이라는 것이다.

리터럴을 float이라고 지정하려면 "F" 또는 "f"로 끝나야 한다.

3.14E2 또는 .19e10과 같은 지수 표기법의 부동 소수점 리터럴도 사용할 수 있다.

베이스는 10이라고 가정한다.
• 문자: 자바에서 문자 상수는 유니코드 알파벳에서 가져온 것으로 가정된다.

일반적으로 문자는 단일 따옴표로 둘러싸인 개별 기호로 정의된다.

예를 들어 'a'와 '?'는 문자 상수이다.

또한 Java는 다음과 같은 특수 문자 상수를 정의한다:
     '\n'(새 줄)
     '\t'(탭)
     '\b'(백스페이스)
     '\r'(복귀)
     '\f' (formfeed(폼피드): 새로운 페이지의 시작)

     '\' (백슬래시) 

     '\'' (단일 따옴표) 

     '\"' (쌍따옴표).
• 문자열 리터럴: 문자열 리터럴은 큰 따옴표로 둘러싸인 문자 시퀀스이다.

예를 들어 다음은 문자열 리터럴이다:

 "dogs cannot climb trees"

 

1.3.2 연산자

자바 표현식은 연산자로 리터럴과 변수를 구성하는 것을 포함한다.

우리는 이 절에서 자바의 연산자들을 조사한다.

 

할당 연산자

자바의 표준 할당 연산자는 "="이다. 

인스턴스 변수나 지역 변수에 값을 할당하는 데 사용된다.

구문은 다음과 같다:

variable = expression

여기서 variable은 이 식을 포함하는 블록문에서 참조할 수 있도록 허용된 변수를 나타낸다.

할당 연산의 값은 할당된 식의 값이다.

따라서 i와 j가 모두 int 타입으로 선언된 경우 다음과 같은 할당문을 갖는 것이 옳다:
 i = j = 25;// '=' 연산자가 오른쪽에서 왼쪽으로 평가되기 때문에 작동한다.

 

산술 연산자

자바의 이진 산술 연산자는 다음과 같다:
+ 덧셈
- 뺄셈
* 곱셈

/나눗셈
% 모듈로 연산자

 

모듈로(modulo) 연산자: 정수 나눗셈 후에 남은 나머지이기 때문에 "나머지" 연산자라고도 한다.

종종 모듈로 연산자를 나타내기 위해 "mod"를 사용하며,

정수 q와 0 <= r < n에 대해 n = mq + r이 되도록

공식적으로 n mod m = r로 정의한다.

 

단항 마이너스(-): 산술식 앞에 배치하여 부호를 뒤집을 수 있다.

괄호는 어떤 식으로든 사용하여 식의 순서를 정의할 수 있다.

자바는 괄호가 사용되지 않을 때 식의 순서를 결정하는 데에도

상당히 직관적인 연산자 우선순위 규칙을 사용한다.

자바는 C++와 달리 연산자 오버로딩을 허용하지 않다.

 

증가 및 감소 연산자

자바는 C와 C++와 마찬가지로 증가 및 감소 연산자를 제공한다.

특히 +1 증가(++)과 감소(--) 연산자를 제공한다.

만약 그런 연산자를 변수 참조 앞에 사용한다면,

변수에 1이 추가되고 (또는 차감되고) 그 값이 식으로 읽힌다.

변수 참조 뒤에 사용된다면,

그 값은 먼저 읽히고 그 다음 변수는 1만큼 증가 또는 감소된다.

 

예시)

코드 조각
int i = 8;
int j = i++; 

int k = ++i; 

int m = i−−; 

int n = 9 + i++;
은 8에서 j, 10에서 k, 10에서 m, 18에서 n을 할당하고

i를 값 10으로 남긴다.

 

논리 연산자

Java는 숫자 간의 표준 비교 연산자를 허용한다:

<  미만으로

<= 이하

== 과 동등한

!= 과 동등하지 않은

>= 이상
> 보다 더 큰


연산자 == 및 !=는 객체 참조에도 사용할 수 있다. 

비교의 결과의 종류는 boolean이다.

 

boolean 값에 대해 연산하는 연산자는 다음과 같다:
! not (접두사)
&& 조건부 and
|| 조건부 or


부울 연산자 &&와 ||는 식의 값을 결정할 필요가 없는 경우 

식에서 두 번째 피연산자(오른쪽)를 평가하지 않다.

이 기능은 예를 들어 어떤 조건이 성립하는지

(예를 들어 null이 아닌 참조)를 먼저 테스트한 다음

이전 테스트가 성공하지 않았다면

오류 조건을 생성할 수 있는 조건을 테스트하는 부울 식을 구성하는 데 유용하다.

 

비트 연산자

또한 Java는 정수와 부울에 대해 다음과 같은 비트 연산자(Bitwise Operator)를 제공한다.

비트 단위 보법(접두 단항 연산자)
조금
& 비트 and

|  비트 or

^ 비트 xor

< < 비트를 왼쪽으로 이동하여 0으로 채우기
> > 비트를 오른쪽으로 이동하여 부호 비트로 채우기

>>> 비트를 오른쪽으로 이동하여 0으로 채우기

복합 할당 연산자(Operational Assignment Operator)
자바는 표준 할당 연산자(=) 외에도

연산에 대한 부수적인 효과(side effect)가 있는

여러 다른 할당 연산자를 제공한다.

이러한 다른 종류의 연산자는 다음과 같은 형태이다:
    variable op = expression
여기서 op는 임의의 이항 연산자이다.

위 식은 variable = variable op expression과 같다
variable에 수식(예를 들어 배열 인덱스)이 포함되어 있는 경우, 수식은 한 번만 평가된다.

따라서 코드 조각은
    a [5] = 10;
    i = 5;
    a[i++] += 2;
값이 12인 a[5]를 남기고 값이 6인 i를 남긴다.

 

문자열 연결

연결(concatenation) 연산자(+)를 사용하여 문자열을 구성할 수 있으므로 

String rug = "carpet";
String dog = "spot";
String mess = rug + dog;

String answer = mess + " will cost me " + 5 + "dollars!";

위의 코드는 answer이 문자열을 참조하도록 하는 효과를 가질 것이다

"carpetspot will cost me 5 dollars!"

이 예에서는 문자열 연결 연산에 관여할 때 문자열이 아닌 상수를 문자열로 변환하는 방법도 보여준다.


연산자 우선 순위

자바의 연산자들에게는 괄호가 없을 때 평가 모호성이 나타날 때 

연산이 수행되는 순서를 결정하는 우선순위, 즉 선호도가 주어진다.

예를 들어, 우리는 "5+2*3"이라는 표현식이

21 또는 11의 값을 갖는지 결정하는 방법이 필요하다(자바는 11이라고 말한다).
우리는 표 1.3에서 자바의 연산자들의 우선순위를 보여준다 (부수적으로, C와 같다).

 

표 1.3: Java 우선 순위 규칙이다.

Java의 연산자는 평가 순서를 결정하기 위해

괄호가 사용되지 않는 경우 위 순서에 따라 평가된다.

동일한 라인의 연산자는

Boolean 및 and/or 연산에 대한 조건부 평가 규칙에 따라

왼쪽에서 오른쪽으로 순서대로 평가된다

(오른쪽에서 왼쪽으로 평가되는 할당 및 접두사 연산 제외).

해당 연산은 가장 높은 우선 순위부터 가장 낮은 우선 순위까지 나열된다

(원자 또는 괄호가 있는 표현식을 나타내기 위해 exp를 사용한다).

괄호가 없으면 더 높은 우선 순위 연산자가 낮은 우선 순위 연산자보다 먼저 수행된다.

 

연산자 우선순위 

타입
기호


1

postfix ops prefix ops cast

exp ++ exp--  ++exp  --exp +exp  -exp  ~exp !exp (type) exp

 

2

mult./div.

* / %

3

add./subt.

+−


4

shift

<< >> >>>

 

5

comparison
< <= > >=
instanceof

 

6

equality

== !=


7

bitwise-and

&

 

8

bitwise-xor

^

 

9

bitwise-or

|

 

10

and
&&


11

or

||


12

conditional

        boolean_expression? value_if_true:
        value_if_false


13

assignment
= += -
= *= /= %= >>= <<= >>>=&= ^= | =


이제 표 1.3에 나열된 거의 모든 연산자에 대해 논의했다.

주목할 만한 예외는 조건부 연산자로,

부울 식을 평가한 다음 이 부울 식을 참인지 거짓인지에 따라 적절한 값을 취하는 것이다.

(다음 장에서 연산자 인스턴스의 사용에 대해 설명하겠다.)


1.3.3 식의 캐스팅 및 오토박싱/언박싱

캐스팅(casting): 변수의 종류를 바꿀 수 있는 작업

본질적으로 우리는 한 종류의 변수를 가져와서 다른 종류의 같은 변수로 캐스팅할 수 있다.

캐스팅은 특정 숫자 연산 및 입출력 연산을 수행하는 데 유용할 수 있다.
식을 원하는 타입으로 캐스팅하는 구문은 다음과 같다:
(type) exp
여기서 type은 exp라는 표현을 사용하고자 하는 타입이다.

자바에서 기본적으로 두 가지 타입의 캐스팅을 할 수 있다.

기본적으로 기본 숫자형에 대해서 캐스팅을 할 수도 있고 객체에 대해서 캐스팅을 할 수도 있다.

여기서는 숫자형과 문자열형의 캐스팅을 어떻게 할 것인지에 대해서 이야기하고

2.5.1절에서 객체 캐스팅에 대해서 이야기한다.

예를 들어 나눗셈과 같은 작업을 수행하기 위해서는

intdouble로 캐스팅하는 것이 도움이 될 수 있다.


일반 캐스팅

double에서 int로 캐스팅할 때 정밀도가 떨어질 수 있다.

결과적으로 double 값이 반올림된다는 것을 의미한다.

하지만 우리는 이런 걱정 없이 double을 만들 수 있다.

예를 들어, 다음을 생각해보자:
double d1 = 3.2;
double d2 = 3.9999;
int i1 = (int)d1; // i1은 3 값을 갖는다.

int i2 = (int)d2; // i2는 3 값을 갖는다.

double d3 = (double)i2; // d3은 3.0 값을 갖는다

 

연산자를 사용한 캐스팅

나눗셈처럼 어떤 이진 연산자들은 변수의 종류에 따라 다른 결과를 가질 것이다.

우리는 연산이 의도한 종류의 값에 대해 연산을 수행하는지 확인하기 위해 주의를 기울여야 한다.

예를 들어 정수와 함께 사용하면 나눗셈은 분수 부분을 추적하지 않다.

double과 함께 사용하면 나눗셈은 다음 예제와 같이 이 부분을 유지한다:
int i1 = 3;
int i2 = 6;
dresult = (double)i1 / (double)i2;/ dresult의 값은 0.5이다
dresult = i1 / i2; // dresult의 값은 0.0이다
i1과 i2가 두 배로 캐스팅되었을 때, 실수에 대한 정규 나눗셈이 수행되었음을 주목하자.

i1과 i2가 캐스팅되지 않았을 때, " /" 연산자는 정수 나눗셈을 수행했고 i1 / i2의 결과는 int 0이었다.

그리고 나서 자바는 double 결과에 int 값을 할당하기 위해 암시적 캐스팅(implicit cast)을 수행했다.

다음으로 암시적 캐스팅에 대해 논의한다.


암시적 캐스팅 및 자동 상자/해제

정밀도 손실이 없다면 자바가 할당 변수의 종류에 따라

암시적 캐스팅(implicit cast)을 수행하는 경우가 있다.

예를 들어 다음과 같다:
int iresult, i = 3;
double dresult, d = 3.2;
dresult = i / d; // dresult는 0.9375이다. double에 캐스팅 되었다

iresult = i / d; // 정밀도 손실 -> 컴파일 오류이다
iresult = (int) i / d; // 분수 부분이 손실되므로 i 결과는 0이다

 

자바는 정밀도가 손실된 곳에서는 암시적 캐스트를 수행하지 않으므로 

위의 마지막 줄에 명시적 캐스트가 필요하다.

 

Java 5.0 이후로 Integer이나 Float와 같은 Number 객체와

intfloat과 같은 관련 기본 타입 사이를 이동하기 위한 새로운 종류의 암시적 캐스트가 있다.

Number 객체가 메소드의 매개 변수로 예상되는 경우 해당 기본 타입을 전달할 수 있다.

이 경우 Java는 오토박싱이라는 암시적 캐스트를 수행한다.

오토박싱(autoboxing): 기본 타입을 해당 Number 객체로 변환하는 것

마찬가지로 Number 참조를 포함하는 식에서 기본 타입이 예상되는 경우

해당 Number 객체가 해당 기본 타입으로 변경된다.

마찬가지로 Number 참조를 포함하는 식에서 기본 타입이 예상될 때마다 

Number 객체는 언박싱이라고 불리는 연산에서 해당 기본 타입으로 변경된다.

언박싱(unboxing): Number 객체를 해당 기본 타입으로 변환하는 것

 

오토박싱와 언박싱에 대해 주의해야 할 사항

1. Number 참조가 Null이면 언박싱을 시도하면

    NullPointerException이라는 오류가 발생한다는 것이다.

2. 연산자 "=="는 기본 타입 값의 동일성과 두 개의 Number 참조가 동일한 객체를 가리키는지 여부를 테스트하는 데 모두 사용된다.

     따라서 동일성을 테스트할 때는 오토박싱와 언박싱으로 수행되는 암시적 캐스팅을 피하자.

3. 마지막으로 암시적 캐스팅은 시간이 걸리므로 성능이 문제가 될 경우 이 캐스팅에 대한 의존도를 최소화해야 한다.

 

그런데 자바에서 암묵적 캐스팅만 허용되는 상황이 하나 있는데, 이것이 바로 문자열 연결이다.

문자열이 어떤 객체나 기본 형식과 연결될 때마다 해당 객체나 기본 형식은 자동으로 문자열로 변환된다.

그러나 객체나 기본 형식을 문자열에 명시적으로 캐스팅하는 것은 허용되지 않다.

따라서 다음과 같은 할당은 올바르지 않다:
String = (String) 4.5; // this is wrong!
String t = "Value =" + (String) 13;// this is wrong!
String u = 22; // this is wrong!

 

문자열로 변환을 수행하려면, 

대신 적절한 toString 방법을 사용하거나 

연결 연산을 통해 암시적 캐스트를 수행해야 한다.

 

따라서 다음 문장이 정확하다:

String s = " " + 4.5; //correct, but poor style
String t = "Value = " + 13; //this is good
String u = Integer.toString(22); //this is good