개발자입니다
[비트캠프] 38일차(8주차3일) - Java(클래스, public, import, main(), javadoc, 애노테이션, 리터럴, 부동소수점) 본문
[비트캠프] 38일차(8주차3일) - Java(클래스, public, import, main(), javadoc, 애노테이션, 리터럴, 부동소수점)
끈기JK 2022. 12. 28. 10:29
Maven 프로젝트의 표준 디렉토리 구조로 소스 파일 관리
프로젝트 홈 > src > main > java 폴더에서 > p1 > px > C.java 에 파일 둔다.
↓ 컴파일 하면
bin > main 폴더에서 > p1 > px > C.class 가 생성된다.
shell script
개발자가 terminal에 명령 입력하면 OS에서 실행한다.
terminal을 shell Interpreter라 한다.
Windows : Batch Script(.bat), PowerShell
Unix : zsh, bash, bsh, csh, ksh, sh
AppleScript, ...
shell script에도 for 문이 있다. 아래와 같이 입력하면 폴더를 따라 들어가면서 .java 파일을 컴파일 한다.
C:\Users\bitcamp\git\bitcamp-ncp\myapp\src>set outputdir="C:\Users\bitcamp\git\bitcamp-ncp\myapp\bin\main"
C:\Users\bitcamp\git\bitcamp-ncp\myapp\src>for /d /r %v in (*) do javac -d %outputdir% %v\*.java
클래스 블록의 공개여부
public 키워드는 공개 여부를 지정한다. public의 의미는 다른 패키지에서 이 클래스를 사용할 수 있다는 것이다. 공개 클래스의 파일명은 반드시 클래스명과 같아야 한다. (class A 로 선언하면 A.java 로 이름 지어야 한다)
같은 package 에서 접근할 경우 공개 되어있지 않아도 되지만, 해당 package 외부에서 접근하려면 public class에게만 접근할 수 있다.
public 과 non-public
p1/B.class 가 public이면 다른 곳에서 접근 가능하다.
p2/C.class 가 public이 없으면 A.class 에서 접근 불가하다.
public 클래스는 다른 패키지의 클래스에서 접근 가능하다.
다른 패키지 클래스에 접근
A 클래스에 접근하려면 A obj; 로 해야한다.
p1.B 클래스에 접근하려면 p1.B obj; 로 해야한다. (p1 : 패키지 명)
패키지에 소속된 클래스를 사용할 때는 반드시 패키지를 지정해야만 컴파일러가 찾을 수 있다.
※컴파일
$ javac -classpath bin/main A.java
# -classpath = -cp
# bin/main : 패키지 및 .class 파일이 들어있는 폴더
-classpath 사용법
javac -classpath bin/main 에서 bin/main은 루트 패키지가 들어있는 폴더이어야 한다.
bin/main/p1 처럼 패키지 경로를 직접 지정할 수 없다.
$ javac -d bin/main -classpath bin/main src/main/java/A.java
다른 패키지의 클래스 사용과 import 문
A ~ p2.px.aaaaa.bbbbb.ccccc.ddddd.D 클래스가 있다. 이를 접근하려면
A obj; ~ p2.px.aaaaa.bbbbb.ccccc.ddddd.D obj5; 처럼 사용해야 한다.
위와 같이 귀찮게 사용하지 않으려면 import 해서 사용한다.
import p1.B; 처럼 소속을 밝힌 후에 B obj2; 이런식으로 사용한다.
다른 패키지의 동일한 클래스 명을 import 할 수 없다. 하나만 import 하고 다른 하나는 직접 접근해야 한다.
import는 가져오는게 아니라 그 경로를 가리키는 것이다. B 를 p1.B 로 변경해서 컴파일한다.
-sourcepath
사용하는 클래스의 소스 파일이 있다면 -classpath로 경로를 지정할 필요가 없다.
$ javac -d bin/main -sourcepath src/main/java src/main/java/A.java
위에서 -sourcepath src/main/java 는 A.java를 컴파일 할 때 A 클래스가 사용하는 다른 클래스의 소스 파일 경로를 알려준다. = A.java를 컴파일 할때 A가 사용하는 클래스의 소스 파일도 함께 컴파일 된다.
main()
Java App.의 entry point(진입점)
$ java A 에서
java는 (bytecode 인터프리터 = bytecode player = JVM)
A 는 클래스를 지칭할 때 확장명을 적으면 안된다.
① A 클래스 코드를 메모리에 적재(loading)
② bytecode 검증
③ main() 호출
public static void main(String[ ] args) { } *args 변수명은 달라도 된다.
main() 의 형식을 반드시 지켜야한다. main() 의 형식 = 메서드 형식(Method Signature) = function prototype
이렇게 하면 오류 난다.
C:\Users\bitcamp\git\bitcamp-ncp\myapp>java A
Error: Could not find or load main class A
Caused by: java.lang.ClassNotFoundException: A
class A 내부에 class main 을 추가 해야한다.
-classpath
루트 패키지와 클래스가 들어있는 디렉토리 경로
자바 컴파일러와 JVM은 클래스를 찾을 이 옵션의 경로를 따라간다.
main 메서드는 형식이 지정되어 있다.
C:\Users\bitcamp\git\bitcamp-ncp\myapp>java -classpath bin/main A
Error: Main method not found in class A, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
public static void main(String[] args) 를 입력한다.
소스 파일 인코딩
VSCode 에서 A.java 로 저장한다. UTF-8 인코딩 되어있다. 이를 A.class 로 javac.exe 가 컴파일 한다. 여기서 javac.exe 컴파일러가 소스 파일을 읽을 때, 소스 파일의 인코딩 문자집합이 OS의 기본 문자 집합과 같은 것이라 간주한다.
운영체제별 기본 문자 집합은 다음과 같다.
Windows : MS949 (컴파일시 오류 발생)
Unix, macOS, Linux : UTF-8
-encoding
-encoding UTF-8 추가로 소스 파일의 인코딩을 알려준다.
javadoc 문서 추출하기
## 실습
1) Java Document 만들기
- javadoc.exe 도구를 사용하여 자바 소스 파일에서 Javadoc 주석을 추출하여 HTML 파일을 생성해 보자.
javadoc
-encoding [소스 파일의 문자집합]
-charset [생성될 HTML 파일의 문자집합]
-d [생성된 파일을 놓아둘 디렉토리]
-sourcepath [자바 소스 경로] [자바 패키지]
예) $ javadoc -encoding UTF-8 -charset UTF-8 -d javadoc -sourcepath src/main/java com.eomcs.basic.ex02
2) Javadoc으로 생성한 HTML 문서 확인하기
- /javadoc 디렉토리를 보면 자바 소스 파일에서 추출한 Javadoc 으로 만든 HTML 문서를 확인할 수 있다.
C:\Users\bitcamp\git\bitcamp-ncp\eomcs-java-lang\app>javadoc -encoding UTF-8 -charset UTF
-8 -d javadoc -sourcepath src/main/java com.eomcs.lang.ex02
// com.eomcs.basic.ex02
/**
* 클래스에 대한 설명
* @author eomjinyoung
*
*/
public class Exam0200 {
HTML을 브라우저에서 확인할 수 있다.
# 주석 - 애노테이션(annotation)
- 클래스, 변수(필드, 아규먼트, 로컬 변수), 메서드 선언에 붙이는 주석이다.
- 컴파일러나 JVM에서 사용할 주석이다.
- 컴파일 한 후에도 클래스 파일(.class)에 주석을 유지할 수 있다.
- 클래스 파일을 메모리에 로딩할 때 주석도 함께 로딩할 수 있다.
- 실행 중에 클래스와 함께 로딩된 주석을 추출할 수 있다.
- '프로퍼티=값' 형태로 값을 설정한다.
## 애노테이션 문법
- 작성 방법
@애노테이션명(프로퍼티명=값,프로퍼티명=값,...)
예1) @Override
예2) @SuppressWarnings(value="deprecation")
예3) @SuppressWarnings(value={"unchecked", "deprecation"})
## @Override
- 수퍼 클래스에서 상속 받은 멤버를 재정의 한다는 것을 컴파일러에게 알린다.
- 컴파일러는 오버라이딩 규칙을 준수하는지 검사한다.
- 만약 오버라이딩 규칙을 따르지 않는다면 컴파일 오류를 발생시킬 것이다.
@Override
public String toString() {
return "Exam12";
}
Literal
정수 리터럴
10진수, 8진수, 2진수, 16진수를 위와 같이 표현한다.
int는 4byte, long은 8byte 이다.
JavaScript와 다르게 정수 리터럴의 메모리 크기가 있다. 표현할 수 있는 값의 범위가 있다.
100 (4byte 정수) : 약 -12억 ~ +21억까지 표현 가능
100L, 100l (8byte 정수) : 약 -900경 ~ +900경까지 표현 가능
데이터 타입과 리터럴
- 자바 기본 데이터 타입(Primitive Data Type)
- 정수
- 4byte 리터럴(int) 100
- 8byte 리터럴(long) 100L 100l
- 부동소수점
- 4byte 리터럴(float, 단정도) 3.14f 3.14F
- 8byte 리터럴(double, 배정도) 3.14
- 논리 : 4byte 리터럴 true false
- 문자 : 2byte 리터럴 'A' '가'
'AAA'
- 정수
- 문자열 : 객체 "Hello"
값을 메모리에 저장
정수를 2진수로 변환해서 전기적 신호(on/off)로 메모리에 저장한다.
정수를 2진수로 encoding(변환) 할때 4가지 방법이 있다.
- Sign-Magnitude(지수부)
- 1's 보수
- ※2's 보수
- Excess-K (가수부)
부동소수점(실수)는 2진수로 바꿀때 IEEE-754 명세에 따라 변환한다.
논리는 true(1) false(0) 으로 변환한다. 한 개는 4byte, 배열은 1byte이다. (Oracle JVM 명세서 참조)
문자는 UTF-16 으로 인코딩하여 2진수로 변환한다.
문자열은 9.x 버전 미만에서 char(2byte) 배열, 9.x 버전 이상부터 byte(1~3byte) 배열을 사용해서 2진수로 변환한다.
부동소수점 → IEEE-754 명세
12.375 를 2진수로 변환하고 전기신호로 변환해 메모리에 저장한다.
12.375 를 2진수로 할때 12는 1100이다. .375는 2를 계속 곱하고 소수점 앞 자리 가져오는 것을 반복하면 .011 이다.
합치면 1100.011 (2진수) 이다. 앞에 1 하나만 남도록 소수점 자리를 옮긴다. 그럼 1.100011 × 23 로 표현된다.
점 앞의 1을 버린다. 그럼 가수부는 100011 이다. Sign-magnitude 방식으로 저장된다.
지수부에서 2의 승수는 (메모리비트수 -1) 로 계산한다. Excess-k = 2(8-1) - 1 = 128 - 1 = 127 로 계산한다. 127을 bias값 = Excess-k 값이라 한다. 지수부 3 + bias값 = 3 + 127 = 130 으로 지수부는 1000 0010 이다.
메모리 32비트에 맨 앞 부호비트 1비트, 지수부 8비트, 가수부 23비트 저장된다. 가수부는 값을 앞부터 채우고 뒤는 0으로 채운다.
이를 16진수 변환하면 (양수) 0x41460000 (음수) C1460000 이다.
다음 검색어 사이트에서 확인 가능 (ieee 754 converter) : https://www.h-schmidt.net/FloatConverter/IEEE754.html
예제 소스 정리
# 정수 리터럴 - 자릿수 표기
- 정수를 읽기 쉽도록 밑줄(underscore; _)을 숫자 사이에 삽입할 수 있다.
2진수, 8진수, 10진수, 16진수 모두 가능하다.
System.out.println(12783406);
System.out.println(1278_3406);
System.out.println(12_783_406);
// 모두 12783406
# 정수 리터럴 - 메모리 크기에 따른 표기법
- 정수를 저장할 메모리의 크기를 지정할 수 있다.
- 메모리의 크기에 따라 표현할 수 있는 정수의 크기가 다르다.
//## 4바이트 또는 8바이트 정수의 최대값과 최소값
//자바에서는 각 데이터 유형에 따라 최대/최소 값을 알아볼 수 있도록 특별한 명령을 제공한다.
System.out.println(Integer.MAX_VALUE); // 4바이트로 표현할 수 있는 정수 최대값
System.out.println(Integer.MIN_VALUE); // 4바이트로 표현할 수 있는 정수 최소값
System.out.println(Long.MAX_VALUE); // 8바이트로 표현할 수 있는 정수 최대값
System.out.println(Long.MIN_VALUE); // 8바이트로 표현할 수 있는 정수 최소값
# 부동소수점 리터럴 - 유효자릿수
- 정수처럼 메모리 크기(4바이트 또는 8바이트)에 따라 표현할 수 있는 부동소수점의 범위가 다르다.
- 단 IEEE 754 명세에 따라 2진수로 변환되기 때문에
정확하게 '소수점 이상 얼마까지 소수점 이하 얼마까지' 식으로 정의할 수 없다.
대신 '유효자릿수'라는 방식으로 대략적으로 값의 범위를 표현한다.
//## 4byte(float) 부동소수점의 유효자릿수
//소수점을 뺀 후 7자리 숫자까지는 거의 정상적으로 저장된다.
System.out.println(999.9999f);
System.out.println(999999.9f);
System.out.println(9.999999f);
System.out.println("----------------------------");
//유효자릿수가 7자리를 넘어가는 경우 값이 잘려서 저장될 수 있다.
System.out.println(987654321.1234567f);
System.out.println(9.876543211234567f);
System.out.println(987654321123456.7f);
System.out.println("----------------------------");
//## 8byte(double) 부동소수점의 유효자릿수
//소수점을 뺀 후 16자리 숫자까지는 거의 정상적으로 저장된다.
System.out.println(987654321.1234567);
System.out.println(9.876543211234567);
System.out.println(987654321123456.7);
System.out.println("----------------------------");
//유효자릿수가 16자리를 넘어가는 경우 값이 잘려서 저장될 수 있다.
System.out.println(987654321.12345678);
System.out.println(9.8765432112345678);
System.out.println(987654321123456.78);
System.out.println("----------------------------");
//## 부동소수점을 저장할 때 정확하게 저장되지 않는 예
System.out.println(7 * 0.1); //결과: 0.7000000000000001
//- 이유
// - IEEE-754 규격에 따라 부동소수점을 2진수로 바꾸다보면
// 정확하게 2진수로 딱 떨어지지 않는 경우가 있다.
// CPU, OS, 컴파일러, JVM의 문제가 아니다.
// - IEEE-754의 방법에 내재되어 있는 문제다.
//- 해결책
// - 시스템에서 필요한 만큼 소수점 이하 자리수를 적절히 짤라 사용하라!
실행
999.9999
999999.9
9.999999
----------------------------
9.8765434E8
9.876543
9.876543E14
----------------------------
9.876543211234567E8
9.876543211234567
9.876543211234568E14
----------------------------
9.876543211234568E8
9.876543211234567
9.876543211234568E14
----------------------------
0.7000000000000001
## 결론!
- 32비트(float) 메모리에 부동소수점을 저장할 때는 유효자릿수 7자리까지는 거의 가능하다.
- 64비트(double) 메모리에 부동소수점을 저장할 때는 유효자릿수 15자리까지는 거의 가능하다.
- 그래서 32비트 float을 단정도(single-precision)라 부르고,
64비트는 두 배 정밀하게 값을 저장한다고 해서 배정도(double-precision)이라 부른다.
### 부동소수점을 2진수로 표현하는 방법
- 자바에서 부동소수점의 정규화는 "IEEE 754-1985" 명세에 따른다.
- 메모리 크기와 비트의 구성
=> 32비트 float 타입(32-bit single-precision; 단정도)
[부호비트(1)][지수부(8)][가수부(23)]
=> 64비트 double 타입(64-bit double-precision; 배정도)
[부호비트(1)][지수부(11)][가수부(52)]
- 부호비트(sign bit)
음수는 1, 양수는 0.
- 지수(exponent)
127 bias를 사용한다. 즉 2의 지수 값에 127을 더한 결과 값을 사용한다.
- 가수(fraction/mantissa)
sign-magnitude 방식으로 저장한다.
1.xxxx 값에서 소수점 왼쪽에 있는 1을 제외한 나머지 수를 사용한다.
가수부에 남는 비트가 있다면 0으로 채운다.
# 문자의 리터럴
- 작은 따옴표 ''를 사용하여 문자를 표현한다.
// 자바는 문자를 메모리에 저장할 때 Unicode 규칙에 따라
// 2바이트 코드로 저장한다.
// => 'A' : 0x0041
// => 'B' : 0x0042
// => '1' : 0x0031
// => '가': 0xac00
//
// println()
// - 출력 값으로 문자 코드가 주어지면 해당 코드의 문자를
// 폰트 파일에서 찾아 출력한다.
// - 만약 폰트 파일에 해당 코드의 문자가 없으면 출력하지 못한다.
//
//작은 따옴표를 사용하여 문자를 표현한다.
System.out.println('A');
System.out.println('가');
// 직접 문자를 적는 대신에 그 문자에 부여된 코드 값을 지정할 수 있다.
// 문자에 대해 부여된 값을 '문자 코드(character code)'라 부른다.
// 코드 값은 사용하는 문자 집합에 따라 다르다.
// 자바는 '유니코드(UTF-16BE; UCS2)' 라는 문자집합을 사용한다.
// \ u 뒤에 문자에 부여된 코드 값을 16진수로 적는다.
// u는 소문자로 적어야 한다.
System.out.println('\u0041'); // A
System.out.println('\uac00'); // 가
System.out.println('\uAC00'); // 가 (16진수는 대소문자를 구분하지 않는다)
// \ 바로 뒤에 8진수로 적을 수 있다.
// 단, 0 ~ 377 범위의 8진수만 가능하다.
System.out.println('\101'); // A
System.out.println('\122'); // R
System.out.println('\377'); // ÿ
//System.out.println('\477'); // 컴파일 오류!
// 유니코드 값을 직접 적는 경우는
// 보통 키보드로 문자를 직접 입력할 수 없을 때이다.
System.out.println('\u4eba'); // 사람을 뜻하는 '인(人)'이라는 한자의 문자 코드
System.out.println('\u00a9'); // copyright를 뜻하는 '©' 문자 코드
System.out.println('\u03c0'); // 수학의 파이 기호 'π'
System.out.println('\u03a3'); // 수학의 시그마 기호 'Σ'
실행
A
가
A
가
가
A
R
ÿ
人
©
π
Σ
# 문자의 리터럴 - 문자 집합(character set)
- 자바는 문자를 다룰 때 2바이트 값으로 다룬다.
- 즉 각각의 문자는 규칙에 따라 0 ~ 65535까지의 값으로 메모리에 저장된다.
- 각 문자를 표현하기 위해 정의된 값을 '문자 코드(character code)'라 부른다.
- 각 문자에 부여된 문자 코드의 집합을 '문자 집합(chararacter set)'이라 부른다.
- 자바가 사용하는 문자 집합은 '유니코드(Unicode)'이다.
//## 문자 'A'의 문자 코드를 직접 사용하여 문자를 출력하기
//유니코드 문자집합에서 문자 'A'의 문자 코드는 65 이다.
//println()에 숫자를 그냥 전달하면 일반 숫자인줄 알고 그대로 출력한다.
System.out.println(65);
//println()에 전달하는 값이 일반적인 수가 아니라 문자 코드임을 지정해야 한다.
//숫자 앞에 (char) 를 붙여 이 숫자가 평범한 숫자가 아니라 문자의 UCS-2 코드 값임을 알려줘라.
// (char)문자코드
System.out.println((char)65);
//보통 문자 코드를 표현할 때 16진수를 사용한다.
System.out.println((char)0x41);
//한글 '가'를 문자 코드를 이용하여 출력하기
System.out.println((char)0xAC00);
//'가' 다음 문자 출력하기
System.out.println((char)(0xAC00 + 1));
//영어 대문자 모두 출력하기
//첫 번째 알파벳의 코드 값만 안다면 + 연산자를 이용하여 출력할 수 있다.
for (int i = 0; i < 26; i++) {
System.out.print((char)(i + 65) + ",");
}
# 논리값 리터럴
- 참, 거짓을 표현할 때 사용한다.
//참을 표현할 때는 true, 거짓을 표현할 때는 'false'이다.
//자바는 대소문자를 구분하기 때문에 반드시 소문자로 작성해야 한다.
System.out.println(true);
System.out.println(false);
//비교 연산의 결과는 논리값이다.
System.out.println(4 < 5);
System.out.println(4 > 5);
//논리 연산의 결과는 논리값이다.
System.out.println(true && false);
System.out.println(true || false);
// 작은 따옴표가 알려준 유니코드 값 비교하기
System.out.println(65 == 'A');
System.out.println(65 == 'B');
// 숫자를 true/false로 변환할 수 없다.
// System.out.println((boolean)1); // 컴파일 오류!
# 논리 값을 메모리에 저장할 때 크기
- 4바이트 int 메모리에 저장한다. (JVM 명세서 참조)
- 배열 값인 경우 1바이트 메모리에 저장한다. (JVM 명세서 참조)
- true는 1, false는 0 값으로 저장한다.
- 그렇다고 직접 정수 값을 지정해서는 안된다.
- c언어의 경우 자바의 true, false 처럼 논리 값을 표현하는 키워드가 없다.
# 문자열 리터럴
- 자바의 기본 타입이 아니라 객체이다.
- 객체란? 여러 데이터들의 덩어리이다.
- 표기법
큰 따옴표(double quote) 안에 문자들(문자열)을 작성한다.
예) "홍길동", "임꺽정", "hello"
// 문자열 리터럴 기본 예
System.out.println("ABC가나다");
// 문자열에 유니코드를 포함할 수 있다.
System.out.println("\u0041BC\uac00나다");
# 이스케이프 문자(escape character) = 문자 제어 코드
- 화면에 출력하는 문자가 아니라 문자 출력을 제어하는 문자이다.
- 제어 문자
\n - Line Feed(LF), 0x0a
\r - Carrage Return(CR), 0x0d
\f - Form Feed, 0x0c
\t - Tab, 0x09
\b - Backspace, 0x08
\' - Single Quote, 0x27
\" - Double Quote, 0x22
\\ - Backslash, 0x5c
System.out.println("Hello,world!");
System.out.println("Hello,\nworld!"); // 줄바꿈 문자
System.out.println("Hello,\rabc"); // 커서(cursor)를 처음으로 돌리는 문자
// 커서란? 문자를 출력할 위치를 가리키는 것.
System.out.println("Hello,\b\b\bworld!"); // 커서를 뒤로 한 칸 이동시키는 문자
System.out.println("Hello,\tworld!"); // 탭 공간을 추가시키는 문자
System.out.println("Hello,\fworld!"); //
System.out.println("Hello,\"w\"orld!"); // " 문자를 출력시키는 문자
System.out.println("Hello,'w'orld!"); //"" 안에서 ' 문자는 그냥 적는다.
System.out.println('\''); // ' 문자를 출력시키는 문자
System.out.println('"'); // '' 안에서 " 문자는 그냥 적는다.
System.out.println("c:\\Users\\user\\git"); // \ 문자를 출력시키는 문자
조언
*
과제
/
'네이버클라우드 AIaaS 개발자 양성과정 1기 > Java' 카테고리의 다른 글
[Java] 예제 소스 정리 - 연산자(산술, 논리, 비트, 조건, 증감, 할당) (0) | 2022.12.29 |
---|---|
[Java] 예제 소스 정리 - 변수(원시 변수, 레퍼런스 변수, 형변환) (0) | 2022.12.29 |
[비트캠프] 39일차(8주차4일) - Java(변수, 메모리), myapp-01~02 (0) | 2022.12.29 |
[비트캠프] 37일차(8주차2일) - Java(gradle 디렉토리 구조와 사용, Eclipse IDE 준비, 소스 및 class 파일) (0) | 2022.12.27 |
[비트캠프] 36일차(8주차1일) - Java 개요, 설치, SpringBoot 개념 및 설치 (0) | 2022.12.26 |