개발 지식 기록/JAVA

[자바의 정석] 개인적인 정리 글(1주차)

엉망진창좌충우돌 2023. 7. 30. 19:52

자바의 정석 책을 사고 조금씩 읽고 있었지만 좀처럼 진도가 나가지 않던 상황이었다. 블로그 글을 쓰면서 이번 기회에 확 끝내야겠다는 다짐을 했다.

 

기존에 아는 내용들은 제외하고, 읽으면서 새롭게 알게 된 부분들과 평소에 자주 헷갈리던 부분들만을 모아서 정리하려 한다.


Chapter 01

chapter 1은 이클립스 설치 등 준비과정의 챕터라 특별하게 정리해야 할 내용은 없다.

Chapter 02

◎ 지역변수는 사용 전에 반드시 초기화가 필요하다. 클래스 변수와 인스턴스 변수는 초기화 생략 가능하다.

 

◎ 자료형 타입별 설명

자료형 저장 가능한 값의 범위 bit byte
boolean false, true 8 1
char '\u0000' ~ '\uffff' (0~2^16-1, 0~65535) 16 2
byte -128 ~ 127 (-2^7 ~ 2^7-1) 8 1
short -32768 ~ 32767(-2^15 ~ 2^15-1) 16 2
int -2,147,483,648 ~ 2,147,483,647 (-2^31 ~ 2^31-1) 32 4
long -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,808 (-2^63 ~ 2^63-1) 64 8
float 1.4E-45 ~ 3.4E38 (1.4*10^-45 ~ 3.4*10^38) 32 4
double 4.9E-324 ~ 1.8E308 (4.9*10^-324 ~ 1.8*10^308) 64 8

◎ 2진수 0b / 8진수 0 / 16진수 0x

◎ p를 이용해서 16진수 지수 형태로 표현할 수 도 있다. p는 2의 제곱을 의미. p의 왼쪽에 16진수를 적고 오른쪽에 지수를 10진수로 적는다.

ex) 0x0.2p-1 = (2*16^-1)*2^-1

 

◎ printf의 사용

지시자 설명
%b 불리언(boolean) 형식으로 출력
%d 10진(demical) 정수의 형식으로 출력
%o 8진(octal) 정수의 형식으로 출력
%x, %X 16진(hexa - demical) 정수의 형식으로 출력
%f 부동 소수점(floating - point)의 형식으로 출력
%e, %E 지수(exponent) 표현식의 형식으로 출력
%c 문자(character) 로 출력
%s 문자열(string)로 출력

숫자는 출력할 공간! -는 좌측정렬! 숫자에 0을 붙이면 빈자리를 0으로 채운다.

%전체자리.소수점아래자리f

ex) %14.10f -> 전체 14자리 중 소수점 아래 10자리

 

◎ 10진 소수점수를 2진 소수점수로 변환하는 법

1. 10진 소수에 2를 곱한다. ex) 0.625 * 2= 1.25

2. 그 결과에서 소수부만 가져다가 다시 2를 곱한다. ex) 0.25*2 = 0.5

3. 소수부가 0이 될 때까지 반복한다. ex) 0.5*2 = 1.0

정수부만을 위에서 아래로 순서대로 적고 '0.'을 앞에 붙인다.

1.25 0.5 1.0 순서이니 0.101(2)이다.

 

◎ 2의 보수 : 더해서 2가 되는 두 수 (2의 보수 관계인 2진수는 10진수로 바꾸면 부호가 다르고 절댓값이 같은 수)

2의 보수 = 1의 보수 +1

 

◎ 특수 문자 다루기

특수 문자 문자 리터럴
tab \t
backspace \b
form feed \f
new line \n
carriage return \r
역슬래쉬 \ \
작은따옴표 \ '
큰따옴표 \ "
유니코드(16진수 문자) \u유니코드(예 : char a ='\u0041')

 

Chapter 03

◎ 주의해야 할 연산자 우선순위

연산자 우선순위 중 같은 논리 연산자 내에서 &와 &&가 |와 ||보다 우선순위가 높다.

비트연산자는 비교 연산자보다 우선순위가 낮다. data & 0xFF == 0 의 경우 0xFF == 0 가 더 우선이다.

쉬프트 연산자는 덧셈 연산자보다 우선순위가 낮다.

 

◎ 피연산자 타입이 int보다 작은 타입이면 int로 변환된다.

그래서 byte 형의 2개의 피연산자를 사칙연산 후 다시 byte형에 담으려면 형변환이 필요하다.

 

◎ 피연산자가 정수형인 경우 나누는 수로 0 사용 불가!!

 

◎결괏값이 자료형의 범위 내에 들어오더라도 계산 과정 중 범위를 넘어가면 오버플로우가 발생한다.

그래서 같은 의미의 식이라도 연산 순서(나누기를 먼저 하는 것과 곱하기를 먼저 하는 것 등)에 따라 결과가 달라질 수 있다.

 

◎ 문자 '0' ~ '9'는 유니코드로 48 ~ 57 문자로 되어있는 수를 숫자로 변환하려면 '0'을 빼면 된다.

'A' ~ 'Z'는 유니코드로 65 ~ 90

'a' ~ 'z'는 유니코드로 97 ~ 122

대문자와 소문자의 변환은 32를 더하고 빼면 된다.(다시 char 형으로 형변환 잊지 말자)

 

%는 나눗셈처럼 0 사용 불가. 나누는 수로 음수도 가능하다. 다만 부호는 무시되고 절댓값으로 나눈 나머지와 같은 결과가 나온다.

 

문자열 비교 시 대소문자 구별 없이 비교하려면 equalsIgnoreCase()

 

논리 연산의 경우 앞(좌측)에서 이미 결괏값이 나온 경우 뒷부분(우측)은 실행되지 않는다.

||연산의 경우 어느 한쪽만 true여도 true이기 때문에 앞에서 true가 나오면 결국 true가 나오니 뒷부분은 계산 없이 지나간다.

&&연산도 한쪽만 false여도 전체가 false이므로 앞에서 false가 나오면 뒤는 평가하지 않는다. 이를 이용해 효율적인 코드를 작성할 수도 있다.

 

비트 연산자 ~는 1의 보수를 얻는다.

 

쉬프트 연산자는 빈자리를 0으로 채운다. 다만 오른쪽으로 이동시킬 때 부호가 음수인 경우 부호를 유지하기 위해 빈자리를 1로 채운다.

x<<n은 2^n,   x>>n은 x/2^n과 같다. 곱셈과 나눗셈 연산자보다 속도가 빠르나 가독성이 떨어지니 잘 선택해야 한다.

 

i *= 10 + j 인 경우 i = i * (10+j)이다. 조심하자!

 

Chapter 04

Switch문

switch(조건식){
	case 값1 : 
    	//조건식 결과가 값 1인 경우 수행될 부분
        break;
	case 값2 : 
    	//조건식 결과가 값 1인 경우 수행될 부분
        break;
	default : 
    	//조건식의 결과와 일치하는 case가 없는 경우 수행
}

break 가 없는 경우 break를 만나거나 switch문이 끝날 때까지 밑으로 계속 실행된다.(의도적으로 break를 빼는 경우도 있다.)

switch문 조건식의 결과는 반드시 정수 또는 문자열이어야 한다.

case문의 값은 정수 상수만 가능하다.

int num, result
final int ONE = 1;

switch(조건식){
	case '1' : 가능. 문자리터럴
    case ONE : 가능. 정수 상수
    case "YES" : 가능. 문자열 리터럴(jdk 1.7부터 가능)
    case num : 불가. 변수는 불가.
    case 1.0 : 불가. 실수도 불가.
    	
}

 

Math.random()은 0.0과 1.0 사이의 범위에 속하는 하나의 double 값 반환.(0은 포함 1은 미포함)

ex) 1~3 사이의 정수를 구하려고 한다면 (int)(Math.random()*3)+1

 

for문은 초기화, 조건식, 증감식, 블록으로 구성된다.

둘 이상의 변수가 필요할 때 콤마를 구분자로 변수를 초기화한다. 이때 두 변수의 타입은 같아야 한다.

ex) for(int i = 1, j=2 ; i <=10 ; i++)

증감식도 쉼표를 이용해서 두 문장 이상을 하나로 연결해서 쓸 수 있다.

ex) for(int i = 1, j=2 ; i<=10 ; i++, j--)

초기화, 조건식, 증감식 모두 생략 가능하다. 이 경우 true로 간주한다.

ex) for(;;)

 

while문의 조건식은 생략 불가

 

Chapter 05

배열의 길이는 int 범위의 양의 정수(0 포함) 길이가 0인 배열도 있다.

 

배열을 바로 출력하면 배열의 주소가 나오지만 char배열은 예외적으로 각 요소가 구분자 없이 출력된다.

ex ) char [] chArr = {'a', 'b', 'c', 'd'};

System.out.println(chArr); //abcd

 

배열의 복사는 for문 보다 System.arraycopy()를 사용하는 것이 효율적이다.

System.arraycopy(num, 0, newNum, 0, num.length);

num [0]에서 newNum [0]으로 num.length개의 데이터를 복사

 

String 클래스는 char 배열에 기능(메서드)을 추가한 것

String객체는 읽을 수만 있을 뿐 내용을 변경할 수는 없다.

 

Chapter 06

인스턴스는 참조변수를 통해서만 다룰 수 있으며, 참조변수의 타입은 인스턴스의 타입과 일치해야 한다.

 

변수는 클래스변수, 인스턴스변수, 지역변수가 있다. 멤버변수를 제외한 나머지 변수들은 모두 지역변수이다.

멤버변수 중 static이 붙은 것은 클래스 변수, 붙지 않은 것은 인스턴스 변수.

 

클래스변수는 모든 인스턴스가 공통된 저장공간(변수)을 공유하게 된다.

클래스가 메모리에 로딩될 때 생성되어 프로그램이 종료될 때까지 유지.

 

인스턴스 변수는 인스턴스가 생성될 때마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 갖는다.

 

메서드의 매개변수는 메서드 내에 선언된 것으로 간주되기 때문에 지역변수다.

매개변수는 같은 타입이어도 타입을 생략할 수 없다.

 

같은 클래스 내의 메서드끼리는 참조변수를 사용하지 않고도 서로 호출이 가능하지만 static메서드는 같은 클래스 내의 인스턴스 메서드를 호출할 수 없다.

 

JVM의 메모리 구조

1. 메서드 영역(method area)

클래스에 대한 정보(클래스 데이터)를 이곳에 저장한다. 이때, 그 클래스의 클래스변수도 이 영역에 함께 생성된다.

2. 힙(heap)

인스턴스가 생성되는 공간. 인스턴스 변수들도 이 공간에 생성된다,

3. 호출스택(call stack)

메서드의 작업에 필요한 메모리 공간을 제공. 메서드가 호출되면 호출스택에 호출된 메서드를 위한 메모리가 할당되며, 메서드가 작업을 수행하는 동안 지역변수(매개변수 포함)들과 연산의 중간결과 등을 저장하는 데 사용된다. 작업을 마치면 할당되었던 메모리 공간은 반환되고 스택에서 제거된다.

(stack이다!! 제일 위에 있는 메서드가 현재 실행 중인 메서드!!)

 

메서드의 매개변수를 기본형으로 선언하면 단순히 저장된 값만 얻지만, 참조형으로 선언하면 주소를 알 수 있기 때문에 값을 읽어 오는 것은 물론 값을 변경하는 것도 가능하다.

 

인스턴스 메서드는 인스턴스 변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드이다. 반면 메서드 중에서 인스턴스와 관계없는(인스턴스 변수나 인스턴스 메서드를 사용하지 않는) 메서드를 클래스 메서드(static 메서드)로 정의한다.

 

클래스 메서드(static메서드)는 인스턴스 변수를 사용할 수 없다.

인스턴스 변수는 인스턴스가 반드시 존재해야만 사용할 수 있는데 클래스 메서드는 인스턴스 생성 없이 호출이 가능하므로 클래스 메서드가 호출되었을 때 인스턴스가 존재하지 않을 수 있다.

 

인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.

메서드 호출 시간이 짧아지므로 성능이 향상된다.

 

static을 붙이는 경우 정리

클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야 하는 것이 있는지 살펴보고 있으면, static을 붙여준다.

작성한 메서드 중에서 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 static을 붙일 것은 고려한다.

 

jdk 1.5부터 동적으로 매개변수를 지정해 줄 수 있다. 이 기능을 '가변 인자'라고 한다.

'타입... 변수명' 형태로 선언하며 가변인자는 매개변수 중에서 제일 마지막에 선언해야 한다.

가변인자는 내부적으로 배열을 이용하는데 메서드 호출 시 배열이 새로 생성된다. 편리하지만 비효율적이니 꼭 필요한 경우만 사용하자.

 

생성자는 인스턴스가 생성될 때 호출되는 인스턴스 초기화 메서드이다.

1. 생성자의 이름은 클래스의 이름과 같아야 한다.

2. 생성자는 리턴값이 없다.

 

생성자가 하나도 정의되지 않는 경우 컴파일러는 자동적으로 기본 생성자를 추가하여 컴파일한다. 만약 생성자가 하나라도 정의되어 있다면 기본생성자는 자동으로 추가되지 않는다.

 

생성자에서 다른 생성자 호출하기

생성자의 이름으로 클래스 이름 대신 this를 사용한다.

한 생성자에서 다른 생성자를 호출할 때는 반드시 첫 줄에서만 호출이 가능하다.

 

this - 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다.

모든 인스턴스 메서드에 지역변수로 숨겨진 채로 존재한다.

this(), this(매개변수) - 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다.

 

클래스 초기화 블록 - 클래스 변수의 복잡한 초기화에 사용된다.

인스턴스 초기화 블럭 - 인스턴스 변수의 복잡한 초기화에 사용된다.

클래스 초기화 블록은 클래스가 메모리에 처음 로딩될 때 한번만 수행되며, 인스턴스 초기화 블럭은 생성자와 같이 인스턴스를 생성할 때 마다 수행된다. 생성자보다 인스턴스 초기화 블럭이 먼저 수행된다.

 

인스턴스 변수의 초기화는 주로 생성자를 사용하고, 인스턴스 초기화 블록은 모든 생성자에서 공통으로 수행돼야 하는 코드를 넣는데 사용한다.

Car(){
	count++;
    serialNo = count;
    color = "White";
    gearType = "Auto";
}
Car(String color, String gearType){
	count++;
    serialNo = count;
    this.color = "color";
    this.gearType = "gearType";
}
//인스턴스 초기화 블럭을 사용하여 코드 중복 제거
{
	count++
    serialNo = count;
}
//static이 붙으면 클래스 초기화 블럭이다.
/*
static {
	count++
    serialNo = count;
}
*/
Car(){
    color = "White";
    gearType = "Auto";
}
Car(String color, String gearType){
    this.color = "color";
    this.gearType = "gearType";
}

 

◎ 클래스 변수의 초기화 순서 : 기본값 -> 명시적 초기화 -> 클래스 초기화 블럭

인스턴스 변수의 초기화 순서 : 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블럭 -> 생성자

class InitTest{
	static int cv = 1;
    int iv = 1;
    //이게 명시적 초기화
    static {
    	cv = 2;
    }//클래스 초기화 블럭
    {
    	iv = 2;
    }//인스턴스 초기화 블럭
    InitTest(){
    	iv = 3;
    }//생성자
}

 

◎ 클래스 변수는 항상 인스턴스 변수보다 항상 먼저 생성되고 초기화된다.

'개발 지식 기록 > JAVA' 카테고리의 다른 글

[메서드 정리] Math  (0) 2023.08.06
[메서드 정리] String  (0) 2023.08.06
[메서드 정리] Integer  (0) 2023.08.06
Arrays.sort()와 Collections.sort()  (0) 2023.07.30
String vs StringBuffer vs StringBuilder  (0) 2023.07.25