Search
*️⃣

Java (On Going…)

Category
BlogPost
Venue
Backbone
Text
PPT

Preliminary

컴퓨터 구조

일반적으로 RAM의 메모리 주소를 참조해서 데이터를 읽어 register에 옮긴 후 CPU의 ALU가 연산 후 다시 RAM에 데이터를 write하는 방식
JAVA에서는 메모리 주소를 직접 참조하지는 않음

Programming Basic & Setup

고급어 vs. 저급어 & JVM

고급어 vs. 저급어
(CPU 접점에 전기 신호(+5v)를 넣으면 1, 그렇지 않으면 0)
저급어: CPU가 인식 할 수 있는 명령어
고급어: 사람이 이해하기 용이한 문자열 표기로 정의한 것이 고급어
디지털 회로
회로의 출력 (e.g., 1 and 1 → 1 & 1 and 0 → 0)을 활용해 사칙연산 구현이 가능
기계어
전선에 0(0),1(+5v)의 신호를 일정 단위로 줌 → 주파수
CPU에서 성능 측정을 위해 hz를 사용하는 이유
JVM
컴퓨터에서 물리적인 CPU/RAM을 가상화해서 application program이 사용하도록 구현할 수 있음
(가상화 기술)
JAVA는 가상화 기술을 기반으로 구현되는데
JAVA.exe라는 s/w가 h/w를 virtual로 구현함
JAVA(고급 프로그래밍언어)를 실행하면 Java byte code가 JVM 기계어로 번역
JVM은 실제 h/w가 실행시킬 수 있는 기계어로 번역
JAVA의 가상화 기반 구현은 아래의 장단점을 동시에 가져옴
JAVA 코드는 JVM의 권한/실행 범위로 실행 범위가 제한됨 (보안성 강화, 성능 희생)
JVM에만 호환시켜주면 어떤 플랫폼(OS)에서도 동작이 원활 (application 개발 원활)

컴파일러와 인터프리터

컴파일러
고급어 소스코드를 기계어로 번역하는 프로그램
전체 소스코드를 모두 기계어로 변환한 후 실행
성능 최적화가 용이
인터프리터
고급어 소스코드를 직접 실행하는 프로그램이나 환경을 의미
보통 한번에 한 줄 단위 (i.e., 구문 단위)로 실행
성능 (특히 속도)면에서 컴파일러 방식보다 느림

상수와 변수

상수
소스코드를 작성하는 시점/연산식을 기술하는 시점(컴파일 타임)에 값이 정해진 수
리터럴: 프로그램에서 직접 사용되는 값
int age = 25; // 25가 리터럴 상수 float pi = 3.14; // 3.14가 리터럴 상수 char grade = 'A'; // 'A'가 리터럴 상수
C
복사
심볼릭: 프로그램에서 값이 변경되지 않도록 선언된 식별자
const int MAX_STUDENTS = 100; // 심볼릭 상수 #define PI 3.14159 // 매크로를 이용한 심볼릭 상수
C
복사
변수
소스코드를 작성하는 시점에 값이 정해지지 않는 수
개발자가 메모리를 사용하는 가장 일반적인 방법

JDK & JRE

JDK
JRE를 포함
컴파일러 등 프로그램 개발도구가 포함
언어버전과 일치
JRE (Java Runtime Environment)
런타임 실행 모듈 (.exe)
Java 프로그램을 실행하는데 필요한 패키지
(JVM, 각종 명령, 클래스 라이브러리)

환경변수

환경변수 상속 구조:
최상위에 시스템 환경변수 존재
그 아래 사용자 환경변수(~/.zshrc에 설정한) 존재
모든 프로세스는 부모 프로세스로부터 환경변수를 상속
IntelliJ가 환경변수를 인식하는 과정:
IntelliJ를 실행하면 새로운 프로세스가 생성
이 프로세스는 시스템 환경변수와 사용자 환경변수를 모두 상속
따라서 JAVA_HOME과 같은 사용자 환경변수도 자동으로 인식

Java Basic

build & compile

build: compile
.java 소스코드를 .class (jaca byte code)로 번역
.class를 모듈이라고 하며 linker로 여러 모듈을 link해서 활용
run : link + runtime
JVM의 Class loader가 절차에 따라 bytecode 로딩 후 메모리에 적재
추가 클래스 파일도 로드하고 링크 (실행전에 링크 발생)
public class Main { public static void main(String[] args) { System.out.println("Hello World"); } }
Java
복사
Main {}: Class / scope
void main {} : method / 구문

JVM

JAVA 특징
JVM 기반에서 작동하는 OOP언어
Native code (os+cpu에 의존적)의 가장 큰 특징인 메모리 관리(반환의 의무)와 책임이슈를 구조적으로 제거
OS에 대한 의존성 없음
컴파일러, 인터프로터 특징을 모두 가짐
JVM
class loader: .class (java byte code)를 loading
loading → linking → initialization
runtime data are: memory
heap: new 명령어로 생성한 객체가 생성되는 메모리 영역
pc register: (현재까지 실행된) 구문 위치를 저장해주는 register
stack area, pc register: thread
execution engine: cpu를 활용해 진정한 실행을 담당
JIT compiler: Java bytecode를 실제 기계어로 번역
JVM이 반복되는 코드를 발견할 경우 효율을 높일 목적으로 사용
실행 기록을 모아 자주 사용되는 코드에 주로 적용

CPU 수준의 자료형

정수
bit수에 따라 표현 범위 결정
2의 보수를 더하는 방식으로 뺄셈 구현
IEEE 754 기반 (정밀도 희생)
실수단정도 (float)
배정도 (double, 소수점 이하 15번째 자리까지 유효)
특수정도
사용자 정의 자료형
class로 정의
string
boolean

실수형과 부동소수점 오차

실수형은 IEEE(Institute of Electrical and Electronics Engineers, 전기전자 기술자협회)가 규정한 표준을 사용
소수점 이하 정보를 표시할 수 형식
부동 소수점 표현
100.0
10.0 * 10
1.0 * 10^2
→ 같은 값에 대한 표현 → 두 정수 사이에는 무수히 많은 실수가 존재하기 때문에 일정 수준이 오류(부동소수점 오차)를 인정
float (32bit)냐 double (64bit)에 따라서 같을 수도 다를 수도 있음
float (32bit)이면 같다고할 수도 하지만 double (64bit)이면 다르다고
python으로 확인
import numpy as np # 더 작은 차이를 가진 숫자로 시도 x = 1.000000001 # 1과 더 작은 차이 y = 1.0 # float32로 비교 a = np.float32(x) b = np.float32(y) print("float32 values:") print(f"{x} -> {a}") # 이 경우 a는 1.0으로 표현될 것 print(f"{y} -> {b}") print("float32 comparison:", a == b) # True가 나올 것 print("\nfloat64 values:") c = np.float64(x) d = np.float64(y) print(f"{x} -> {c}") # c는 1.000000001로 유지 print(f"{y} -> {d}") print("float64 comparison:", c == d) # False가 나올 것
Java
복사

Java의 자료형

#### 기본형 (Primitive type)
stack 영역에 존재
→ float은 정밀도가 떨어지기 때문에 가능하면 사용하는거 권장 X
→ java는 utf-8형태의 유니코드 인코딩을 활용
→ boolean은 숫자 X
#### 유도형 (Non-Primitive type or Derived Type)
Java에서 객체로 언급하는 대상
new 연산을 통해 Heap영역에 동적할당 GC에 의해서 관리
String
문자열을 다루기 위한 클래스
Class
Array, List, Queue, Stack
Interface
#### 그 외 (C 기준으로)
무치형
void
함수형
testFunc(int a)

객체, 클래스, 인스턴스, 참조 - 용어정리

객체
특정 목적을 가진 코드와 연산에 필요한 자료(변수), 함수(메서드)들을 한 세트로 묶어 구현할 대상
클래스 (객체를 구현하는 문법)
java에서는 객체를 클래스로 기술
인스턴스
특정 자료형에 대한 변수 / 클래스 인스턴스에 접근할 수 있는건 참조자
→ int a;
(a는 int 형식에 대한 인스턴스)
→ String hello = new String(”Hello”);
(hello는 새로 생성된 String 클래스 인스턴스에 대한 참조자)

문자와 문자배열 및 인코딩

ASCII vs UNICODE
ASCII
영문 알파벳을 사용하는 문자 인코딩 표준
7비트를 사용하여 총 128개의 문자를 표현
영문 대소문자, 숫자, 특수기호, 제어문자를 포함
(1bit를 추가해서) 1바이트 체계로 매우 단순하고 가벼운 구조
UNICODE
전 세계의 모든 문자를 일관되게 표현하고 다룰 수 있도록 설계된 국제 표준 코드
각 문자마다 고유한 코드 포인트를 부여하여 중복이나 충돌 X
UTF-8, UTF-16 등 다양한 인코딩 방식을 통해 구현
한글, 한자, 아랍어 등 전 세계의 문자를 포함하는 통합 문자 체계
문자 vs 문자열
문자: 영문 혹은 한글 한 글자를 ‘문자’로 규정
→ char형은 한 문자(유니코드:2byte)를 저장하기 위한 자료형
→ char형은 정수 형식에 속함
문자열: 문자를 연이어진 배열 형태로 나열하면 ‘문자(배)열’
→ char형 자료가 여럿 연이어진 배열 형태가 ‘문자열’

변수 이름 - 식별자 / 변수 종류 및 사용

변수
연산식을 기술하는 시점에 값이 정해지지 않은 수
구체화하지 않았거나 앞으로 변경될 가능성이 있는 수 (혹은 미지의 수)
개발자가 메모리를 사용하는 가장 일반적인 방법
→ JVM의 메모리
stack: LIFO 선형구조
heap:
구체적으로 결정되는 값에 따라 연산의 내용이 달라질 수 있는 원인으로 작용
형식 이름 ; → 선언
형식 이름 = 값; → 정의
상수
연산식을 기술하는 시점에 값이 정해진 수
값이 확정되어 앞으로 변할 가능성이 없는 수
리터럴 (상수)
‘A’, “Hello”, 3, 3.4F, 123.45
심볼릭 상수
final
변수 종류 및 사용
지역변수
접근성에 따른 분류
static 선언이 없다면 자동변수이며 stack 사용
매개변수
함수 매개변수로 접근성은 지역
인스턴수 변수
클래스 변수 (참조자) + new → heap 영역
stack에서의 push/pop & class 변수의 heap 영역 존재
{ int a; int b; { int c; { int d; String hello = new String; } } }
Java
복사
int a; int b; 가 stack에 가장 먼저 순차적으로 stack push되고 int d; 가 가장 마지막에 push된다.
([int a; int b; int c; int d; ])
→ } scope가 끝나면 stack에서 pop이 이루어진다.
new String은 heap 영역에서 클래스 변수를 생성한다.
hello 가 참조자로써 클래스 변수를 가르키고 있는데, }를 지나면 참조관계가 사라진다.
→ 그럼 new String은 참조관계가 사라진다. 이를 GC가 파악하고 memory에서 지워버린다.

콘솔 / 키코드 값 읽기 / Java 인코딩 규칙 / Scanner

CLI(Command Line Interface) 기반 HCI(Human Computer Interface)는 키보드 입력으로 구현
→ 키보드는 전선의 결합으로 되어있으며 압력이 가해졌을 시 scanning 된게 감지됨
→ 키보드 입력값을 표준값으로 변경; keycode
keyboard → [I/O buffer] → CPU/RAM
CPU/RAM → [I/O buffer] (flush) → monitor
콘솔 입력 keycode 값 읽기
System.in.read()
ABC 입력
[A,B,C]
입력된 값을 읽어서 1byte로 반환
⇒ 영문 keycode 값 읽기
import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { int keycode; keycode = System.in.read(); System.out.println(keycode); keycode = System.in.read(); System.out.println(keycode); keycode = System.in.read(); System.out.println(keycode); } } ''' I/O = [] -> 'wait' 입력: ABCD I/O = [65, 66, 67,68, 10] 65 66 67 '''
Java
복사
⇒ 한글 keycode 값 읽기 (unicode!)
가’에 대한 UTF-8 인코딩 결과
UTF-8은 유니코드 값을 1~4바이트로 가변 인코딩 (e.g., 가는 3바이트)
Java에서 문자열의 끝은 NULL이 아님(※C개발자 주의)
import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { int keycode; keycode = System.in.read(); System.out.println(keycode); keycode = System.in.read(); System.out.println(keycode); keycode = System.in.read(); System.out.println(keycode); } } ''' I/O = [] -> 'wait' 입력:I/O = [234, 176, 128, \n] 234 176 128 '''
Java
복사
Java 인코딩 규칙
Java 환경에서 문자열은 UTF-16 BE(Big Endian)로 인코딩
문자열 처리 과정에서는 UTF-16 BE를Modified UTF-8로 변경해 처리
문자열의 끝인 NULL(0x0000)은 본래 UTF-8 규칙으로 인코딩 시 0이지만 Modified UTF-8로 인코딩할 경우0xC080
Scanner
→ I/O buffer에서 연속된 byte를 int 혹은 double로 해석해야 하는 경우 사용하는 클래스
Scanner s = new Scanner
s.nextInt()
s.nextDouble
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner s = new Scanner(System.in); /* 키보드로 타자친걸 Scanner로 해석하겠다. */ int a = s.nextInt(); double b = s.nextDouble(); System.out.println("a: " + a); System.out.println("b: " + b); } } ''' 3 3.4 a: 3 b: 3.4 '''
Java
복사

문자열 입/출력

10 test를 입력한다고 할때, 실질적으로 버퍼를 통해 전달되는 것은
→ ‘1’, ‘0’, ‘ ‘ ,’t’, ‘e’, ‘s’, ‘t’ ‘\n’이며 마지막 개행문자를 제외하고 인식
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String tmp = sc.nextLine(); > 개행문자가 나올때까지 읽는거 System.out.println(tmp); } }
Java
복사
위의 nextLine() 과 달리 whitespace 기준으로 끊어서 전달하는 next() 도 존재한다.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner("Hello\r512\ntest\tTEST"); System.out.println(sc.next()); System.out.println(sc.next()); System.out.println(sc.next()); System.out.println(sc.next()); } }
Java
복사
next() 를 호출하면 개행문자가 buffer에 남아서 코드가 의도된 대로 실행이 되지 않을 수 있다.
input: 10
→ “1”, “0”만 next()가 처리 “\n”는 버퍼에 남음 > 아무 처리 없이 nextLine()호출하면 의도하지 않게 새로운 입력을 코드가 처리할 수 없게 됨
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner sc = new Scanner(System.in); int data = sc.nextInt(); sc.nextLine(); System.out.println("data: "+data); String tmp = sc.nextLine(); System.out.println("tmp "+tmp); } }
Java
복사

형식문자와 이스케이프

이스케이프 시퀀스
형식문자
%d 10진수(정수형)
%c 유니코드 한 문자
%s 문자열
%f 실수형
%t 날짜시간
%x 16진수
import java.util.Scanner; public class Main { public static void main(String[] args){ double data = 123.345; System.out.printf("%f, %f\n", data, -data); System.out.printf("%.1f, %.2f\n", data, data); System.out.printf("%.3f, %.4f\n", data, data); System.out.printf("%012.2f\n", data); } } ''' 123.345000, -123.345000 123.3, 123.35 123.345, 123.3450 000000123.35 '''
Java
복사

Calculator

연산자 기본 이론

연산자는 CPU 연산과 직결되는 문법
연산자 자체는 하나의 항
연산자의 우선순위와 결합성
연산산자 결합성: 우선순위가 같은 경우 어떤 것을 먼저 연산할 것인지 나타내는 것
3+4+5 연산에서 두 덧셈 연산은 우선 순위가 같고 L → R이므로 3+4를 먼저 수행

산술연산자

대표적인 2항 연산자
연산의 결과로 임시결과 발생
3+4+5
3+4의 임시결과인 7의 형식을 주의할 필요가 있음 (추후 연산에 활용됨)
정수 간 나눗셈의 결과는 반드시 정수가 되며 소수점 이하는 절사 (정보가 유실됨)
형승격 (Type Promotion)
이형 간의 연산을 가능하게 하는 것
임시결과에서 피연산자 표현범위 이상의 표현을 가능하게 함
표현범위 더 넒은 걸 따라가도록
(문자열과 숫자 연산의 결과는 문자)
→ 5/2는 정수간 연산이라 정수를 임시 결과로 저장하지만
import java.util.Scanner; public class Main { public static void main(String[] args){ double result = 5/2; System.out.println("Result :" + result); } } ''' Result :2.0 '''
Java
복사
→ 5.0/2는 type promotion으로 2.5으로 저장
import java.util.Scanner; public class Main { public static void main(String[] args){ double result = 5.0/2; System.out.println("Result :" + result); } } ''' Result :2.5 '''
Java
복사
→ Integer의 최댓값에 +=1을 하면 음수로 바뀌지만 long type으로 promotion하면 더 넓은 범위 표현가능
import java.util.Scanner; public class Main { public static void main(String[] args){ int max = Integer.MAX_VALUE; System.out.println("int max: " + max); System.out.println("int max: " + (max + 1)); System.out.println("long max: " + (max + 1L)); } } ''' int max: 2147483647 int max: -2147483648 long max: 2147483648 '''
Java
복사
→ 문자열과 정수 연산 결과는 문자열
import java.util.Scanner; public class Main { public static void main(String[] args){ System.out.printf("5 +5 = %d\n", 5 +5 ); System.out.println("5 +5 = " + 5 +5); } } ''' 5 +5 = 10 5 +5 = 55 '''
Java
복사
나누기 연산
5 - 2 → count+=1
3 - 2 → count+=1
1 →  remainder
따라서, 0으로 나누면 Endless 빼기 연산에 빠질 수 있음 (자체적으로 막지만, 실행될 경우 cpu 터짐)

대입연산자

대입 연산자
단순 대입연산자는 두 피연산자 중 오른쪽 피연산자(r-value)의 값을 왼쪽 피연산자(l-value)에 저장하는 연산자
l-value (메모리) = r-value
l-value에는 overwriter가 발생하며 기존 값이 사라짐
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner s = new Scanner(System.in); int a = 10; int b; b = a; System.out.println(b); } }
Java
복사
→ 이름이 a인 변수에서 값을 read해서 이름이 b인 변수에 overwrite해라
final
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner s = new Scanner(System.in); int a = 10; final int b = 30; //read only -> 상수화 b = a; System.out.println(b); } }
Java
복사
변수이나 한 번 정한 값이 바뀌지 않도록 강제로 상수화
변수가 특정시점에 상수화되었음
// read only만 가능해짐 (l-value가 불가능해짐)
컴파일러가 코드를 최적화 할 수 있도록 도와주며 코드의 직관성(읽기 좋은 코드) 및 유지보수성을 높여 줌
심볼릭 상수를 정의하기 위한 문법

복합대입연산자

+= -= *= %= /= &= |= ^= ~=
기능상 단순 대입 연산자와 산술 연산자, 비트 연산자가 조합된 연산자