Notice
Recent Posts
Recent Comments
Link
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags
more
Archives
Today
Total
관리 메뉴

개발자입니다

[비트캠프] 38일차(8주차3일) - Java(클래스, public, import, main(), javadoc, 애노테이션, 리터럴, 부동소수점) 본문

네이버클라우드 AIaaS 개발자 양성과정 1기/Java

[비트캠프] 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"); // \ 문자를 출력시키는 문자

 

 

 


 

조언

 

*

 

 


 

과제

 

/