[JAVA] 변수(Variable) 정리

DongGyu Jung·2021년 12월 29일
0

자바(JAVA)

목록 보기
2/60
post-thumbnail

🏃‍♂️ 들어가기 앞서..

본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕

*해당 교재의 목차 순서와 구성 내용을 기준으로 작성하며
부족할 수 있는 내용은 추가적인 검색을 통해 채워나갈 예정입니다.



앞서 알아보았던 1주차 (1) 글에서 언급했듯이
하나의 Java 애플리케이션에는 main 메서드 포함한 클래스가 무조건 하나는 있어야한다.

그렇기 때문에
사소한 출력문 하나라도 class를 만들어주며
메인 메소드인 public statuc void main(String args[])이 필요하다.

▣ 출력

출력 이후, 줄바꿈 하지않는 System.out.print()
출력 이후, 줄바꿈 하는 System.out.println()을 사용한다.

class Print {
  public static void main(String args[]) {
    System.out.print("Hello") ; // Hello
    System.out.println("Hello") ; // Hello & 줄바꿈
  }
}

숫자를 넣어 연산식을 작성하여도 계산된 값이 출력된다.

class Print {
  public static void main(String args[]) {
    System.out.print("hello") // hello 출력
    System.out.print(1+2) // 3 출력
    System.out.print("1+2") // 1+2 출력
  }
}

여기서 주의해야할 점은
위에 작성한 '+' 이외에도 다양한 연산자를 사용할 수 있지만
그 중 '/ '를 사용할 때,
정수 / 정수 는 결과가 정수로 나온다
(ex. 5/3 을 출력하면 1이 출력됨. )

📕 변수 (Variable)

간단하게 "하나의 값을 저장할 수 있는 저장공간"

변수를 선언하고 값을 대입하는 방법을 알아보자.

// 선언하는 방법
// [변수타입] [변수이름] ;
int x ; // 선언
x = 5 ; // 대입

int x = 5 // 선언 & 대입

같은 이름의 변수를 다른 값을 다시 대입할 땐,
[변수타입]을 다시 앞에 붙일 필요 없다.

위에서 살펴본 출력까지 활용해보면

class AssignmentOperation {
  public static void main(String args[]) {
    int x = 10 ;
    int y = 5 ;
    System.out.print(x+y); // 15
    System.out.print(x-y); // 5
    System.out.print(x*y); // 50
    System.out.print(x/y); // 2
    
    x = 5 // 기존 값 10은 지워지고 5가 새롭게 대입됨.
    System.out.print(x+y); // 10
  }
}

◎ 타입(Type)

변수 명 앞에 작성되는
변수 타입에 대해 알아보자.

타입(Type)분류설명
int숫자정수 저장
long숫자정수 저장_20억이 넘을 때 long
float숫자실수 저장_7자리
double숫자실수 저장_15자리
char문자문자(글자) 저장
String문자여러 문자(문자열_단어,문장) 저장

변수를 선언할 때, 저장할 값의 종류에 맞는 것을 선택해야 한다.
( 달라도 허용되는 경우도 있긴 함. )


※ 상수 (Constant)

우리가 기존에 알고있던 '상수'라는 단어와 개념이 다르다.

여기서의 상수(Constant)
변수와 마찬가지로
"값을 저장할 수 있는 공간"이긴 하지만
변수와 달리
한 번 저장하면 다른 값으로 변경할 수 없다.

이 상수를 선언하는 방법은 어렵지 않다.
앞서 살펴본 변수 선언할 때 작성한 변수타입 앞
final을 붙여주기만 하면 된다.

final int ONLY_TEN ;
ONLY_TEN = 10 ; // 처음이자 마지막 대입 성공
ONLY_TEN = 20 ; // 에러 

※ 리터럴 (Literal)

생소할 수 있지만
기존에 우리가 알고 있던 상수가 바로
리터럴(literal) 이다.

변수에 대입되는 값이 리터럴이고
당연히 리터럴의 type에 의해 변수 type 또한 결정되기 때문에

변수와 같이 리터럴에도 type이 있다.

위에서 살펴봤듯이
정수형과 실수형은 여러 타입이 존재하는데
이를 위해 리터럴에 접미사를 붙인다.

정수형의 경우,
[Long타입] 엔 접미사 lL
없으면 [int 타입]

2, 8, 16진수 리터럴도 저장할 수 있는데
이를 분류할 때, <8진수>는 0을 붙이고
<16진수>는 0x 혹은 0X 를 붙인다.

// (JDK 1.7~) 정수형 리터럴 중간에 구분자 '_' 삽입 가능 -> 큰 숫자 가독성 증가

long mega = 100_000_000_000L ; // (20억 이상) long mega = 100000000000L
long hex = 0xFFFF_FFFF_FFFF_FFFFL ; // (0x 접미사) long hex = 0xFFFFFFFFFFFFFFFFL

int octTen = 010 ; // 10 -> 8진수 
int hexTen = 0x10 ; // 10 -> 16진수 

실수형의 경우,
[Float타입] 엔 접미사 fF
[Double타입] 엔 접미사 dD 생략 가능
(double이 실수형에서 기본자료형이기 때문)

float pi = 3.141592f ; // [필수] 
double rev = 0.9876d ; 

※ 문자열

문자 관련 리터럴을 다룰 때, 예상치 못한 독특함이 기다리고 있었다.
위에서도 언급했는데
글자단위로 취급하는 문자(Char)타입과
단어, 문장 등과 같은 문자열(String) 타입이 있다.

여기서 이 두 타입의 리터럴 구분 기준은 바로
따옴표다.
[char타입] = 작은 따옴표 (' ')
[String타입] = 따옴표 (" ")

또 한 가지 더!!
주의해야 할 것이 있다.
[String타입]아무런 문자를 넣지 않는 것허용하지만
[char타입]허용하지 않는다 (공백으로 빈 값으로 초기화 하는 것 가능)

String name = "Java";
char ch = 'J' ; // 'Java' 불가능

String str = "" ; // 허용
char ch = '' ; // 에러
char ch = ' ' ; // 공백(blank)를 사용하면 가능

원래 이 String클래스 Class이기 때문에
객체를 생성하는 연산자 new를 붙여 사용해야하지만
아래와 같이 간단히 표현하는 것을 허용한다.

String name = new String("Java"); // new 연산자로 String 객체 생성
String name = "Java" ; // 이 또한 허용

더 나아가 문자열(String)에 대해 더 알아보자.

문자열을 합칠 때
덧셈(+)을 사용할 수 있다.

2개 이상의 덧셈 대상 중
하나라도 문자열이라면 나머지 모두 문자열로 변환하여 결합한다.

String name = "Ja" + "va" ; // Java 
String str = name + 8.0 ; // Java8.0

7 + " " // "7 "
" " + 7 // " 7"
7 + "7" // "77"

// 단, 앞서서 숫자 리터럴이 연속적으로 나오는 경우
// 숫자들 간 계산이 우선적으로 이루어진다.
7 + 7 + " " // "14 "
" " + 7 + 7 // " 77"
7 + " " + 7 // "7 7"


(잠깐 잠깐)
🚩 두 변수의 값 바꾸기
두 변수의 값을 바꾸는 과정을 이렇게 짚고 넘어가는 이유가 있다.
java를 처음으로 배우는 사람이라면 바로 받아들이면 되지만
필자같은 경우처럼 Python 언어를 먼저 배운 후,
Java를 접한 경우라면 조금 헷갈릴 수도 있는 부분이다.

Python의 경우
메모리에 있는 해당 값을 참조하는 형식이기 때문에
서로 다른 값을 가진 두 변수끼리 값을 바꾸는 방법은 매우 간단하다.

a = 10
b = 20

a, b = b, a

print(a)
> 20
print(b)
> 10

끝이다.
(너무 허무한 것 같기도 하고... 민망쓰)

하지만 Java의 경우
두 변수의 값을 바꾸는 과정에서
임시로 한 변수의 값과 동일한 값을 잠깐 담아놓을 장소(변수)가 필요하다.

class Change {
  public static void main(String args[]) {
    int x = 10 ;
    int y = 20 ;
    System.out.println("x = " + x); // "x = 10"
    System.out.println("y = " + y); // "y = 20"
    
    int tmp = x ; // x -> tmp _ 잠깐 tmp 변수 안에 x를 옮겨놓음. 
    
    // x와 tmp는 10 _ x = 10, y = 20, tmp = 10
    x = y ; // y -> x _ x = 20, y = 20, tmp = 10
    y = tmp ; // tmp -> y _ x = 20, y = 10, tmp = 10
    
    System.out.println("x = " + x); // "x = 20"
    System.out.println("y = " + y); // "y = 10"
  }
}


printf() 출력

맨 처음 살펴봤던 것은 단순 입력 인자 출력이였다면
printf() 출력은 추가된 f만 보면 알 수 있듯이 포맷팅(formatting)을 활용한 출력 방법이다.

이 출력 방법은
이번에도 Python에서 배웠던 내용과 비교하자면

#어....이거 사실대로 적어도 되는건감..
name = "동규"
age = 22
height = 170.0

print("이름 : %s"%name)
> 이름 : 동규
print("이름 : %s, 나이 : %d, 키 : %f"%(name, age, height))
> 이름 : 동규, 나이 : 22,: 170.0

위와 같은 형식과 비슷하다고 생각하면 된다.

보이는 것과 같이 %가 많이 붙어있는데
큰 따옴표 안에있는 %s, %d 등과 같은 것들을
지시자(specifier)라고 부른다.

이 포맷팅에서의 해당 요소들은 언어들간에 큰 차이가 없다.

  • %d : 10진(decimal) 정수 형식 지정

  • %f : 부동 소수점(floating-point) 형식 지정 (소수점 아래 6자리까지만)

  • %f : 부동 소수점(floating-point) 형식 지정 (소수점 아래 6자리까지만)

  • %x : 16진(decimal) 정수 형식 지정

  • %c : 문자(charactor) 형식 지정

  • %s : 문자열(String) 형식 지정

  • %n : 사실 이 지시자는 값에 대한 출력 형식 지정이 아닌 줄 바꿈 지시자이다.
    (아마 흔히 \n으로 알고 있을 수도 있지만 안전한 방법은 %n 방법이다. -> 앞서 알아본 System.out.println의 개행 기능을 이 지시자로 대체)

	// printf 연습
        String url = "github.com/yummygyudon";
        
        System.out.printf("[%s] %n", url) ;
        > [github.com/yummygyudon] 
        
        //숫자는 총 출력할 길이를 정해놓는 것 : 몇 글자를 쓰던 부족한 부분은 공백으로 채울 예정
        // 30자를 넘지 못할 경우 : 남은 자리 공백 출력
        // 30자를 넘기는 경우 : 그대로 양쪽 모두 공백없이 문자열 그대로 출력
        System.out.printf("[%30s] %n", url) ; // 오른쪽에  공백
        System.out.printf("[%-30s] %n", url) ; // 왼쪽에  공백 ('-' 는 좌측 끝)
	> [        github.com/yummygyudon] 
	> [github.com/yummygyudon        ] 

        //'.'을 통해 제한 걸기 ( 넘기면 자름 _ 위와 다른 점)
        System.out.printf("[%.8s] %n", url) ; // "왼쪽"에서부터 8글자만
        // System.out.printf("[%8.s] %n", url) -> 왼쪽에서만 가능
        > [github.c] 

        float f1 = .10f;// 0.10 = 1.0e-1
        float f2 = 1e1f;// 0.10 = 1.0e-1
        float f3 = 3.14e3f;// 3140.0 = 3.140000e+3
        double d = 1.23456789 ;

        // 기본적으로 %f는 소수점 아래 6자리 까지출력
        // f , e , g 3가지방법으로 실수형값 출력 가능
        System.out.printf("f1 = (f 버전)%f , (지수 버전)%e , (간략)%g %n", f1, f1, f1 ) ;
        System.out.printf("f2 = (f 버전)%f , (지수 버전)%e , (간략)%g %n", f2, f2, f2 );
        System.out.printf("f3 = (f 버전)%f , (지수 버전)%e , (간략)%g %n", f3, f3, f3 );
        > f1 = (f 버전)0.100000 , (지수 버전)1.000000e-01 , (간략)0.100000 
	> f2 = (f 버전)10.000000 , (지수 버전)1.000000e+01 , (간략)10.0000 
	> f3 = (f 버전)3140.000000 , (지수 버전)3.140000e+03 , (간략)3140.00 
        
        // 자동으로 7자리 반올림되서 6자리까지만 출력
        System.out.printf("double타입 d = (f 버전)%f %n", d); //1.234568
        > double타입 d = (f 버전)1.234568 

        // 출력하고픈 자릿수까지 지정해주기
        // %(전체자리).(출력할 점 아래 자리)f  _ 넘치는 자리는 알아서 -> 0 (소수점 아래) / 공백(양수 자리)으로 채워서 출력
        // 양수 자리 : 점 기준 (좌측)-(우측) , 소숫점 아래 : (우측)
        System.out.printf("내 입맛대로 d = (점 아래 10자리까지) %14.10f %n", d) ; //  1.2345678900
        System.out.printf("내 입맛대로 d = (점 아래 10자리까지) %12.9f %n", d) ; //1.234567890
        > 내 입맛대로 d = (점 아래 10자리까지)   1.2345678900 
	> 내 입맛대로 d = (점 아래 10자리까지)  1.234567890 

※ 입력 받기 (Scanner)

간단하게 사용하는 모듈은 java.util.Scanner이다.
Scanner 클래스 객체 생성 & 사용

  • Scanner 클래스 객체 생성
import java.util.Scanner ;

Scanner scanner = new Scanner(System.in) ;
  • 입력값 원하는 값 타입으로 변환
...
String input = scanner.nextLine() ;  // 우선 nextLine()으로 입력받은 값 문자열로 저장
int num = Integer.parseInt(input) ; // [Integer모듈의 parseInt함수로 int값 변환

...

Scanner클래스에는 nextInt()nextFloat() 같은 직시 변환 메서드가 있다.

※ 정수형 오버플로우(overflow)

오버플로우(Overflow) : 해당 타입(Type)이 표현할 수 있는 값의 범위를 넘어서는 것

우선 해당 부분을 이해하기 위해서는
정수를 표현하기 위한 자료형들의 크기를 알아야 한다.

⊙ 정수 자료형 크기 비교

기본적으로 알고있어야하는 내용은 "1Byte = 8 Bit" 이다.

컴퓨터에서는 덧셈만 가능하기 때문에
음수 표현을 위해 2의 보수를 사용하고 있다.
(A-B를 A+(B 2의 보수)의 방식으로 한다고 생각하면 쉽다.)

2의 보수는
1의 보수에 1을 더한 값이다.

즉, 2의 보수로 뺄셈을 한다면
빼려는 값의 1의 보수에 1을 더한 값을 A에 더하게 되는 것인데
위와 같은 뺄셈 시,
자리올림이 발생한다면 올림된 그 부분만 제외한 나머지 부분이 결과값이 된다.
(이 부분은 밑에서 최솟값, 최댓값에서 활용한다 _ 2진수 0000, 1111의 형태로 따지기 때문)

선언했을 때 해당 자료형 크기만큼 메모리를 할당된다.
각 비트(Bit)엔 2^n개 (n은 Bit)의 수를 저장할 수 있다.
(양/음수 범위 : 각 2^n-1개 _반반씩 나눠지기 때문에 /2 가 됨.)

범위는 0까지 양수의 축에 포함되어서
양수의 범위는 해당 제곱수값보다 1이 작다.

타입(Type)저장가능 범위크기(Bit)크기(Byte)
byte-128 ~ 127 (총 256)81
short-32,768 ~ 32,767
(총 65536)
162
int -2,147,483,648 ~ 2,147,483,647 _각 약 20억 정도324
long-2^63 ~ 2^63648

기본 정수 자료타입은 int로 계산되기 때문에
양수이든 음수이든 20억 단위가 넘어가는 정수를 입력할 땐 꼭 long 타입이라고 언급해야한다.
(char(문자)도 short처럼 2바이트이지만 문자는 음수가 없어 "0 ~ 65535( 2^16 -1 )" 범위를 가짐. )

위에 설명한 내용들을 토대로 설명해보자면
0000~9999까지만 측정 가능한 기기에서 10000이 측정이 되게되면
5번째 자리의 1은 버려지고 0000만 출력되어 보여진다.

심지어 보이는 것만 이렇게 보이는 것이 아니라
0000이 출력된 이후, 추가 계산을 할 때
5째 자리의 값이 무엇인지 궁금해하지도 않으며 [x]0000의 상태에서 시작된다.
(10000 or 20000... -> 0000 출력 (최솟값) -> -1 계산 -> 9999 출력 (최댓값) )

즉, 어쨋거나 저쨋거나 최솟값은 0000이고 최댓값은 9999로 고정이 되는 것이다.
가장 중요한 부분은 "(최댓값 +1) = 최솟값 & (최솟값 -1) = 최댓값" 이라는 사실이다

오버플로우가 발생하더라도 에러가 발생하는 것은 아니지만
발생하지 않도록 충분한 크기의 타입을 선택해 사용하는 것이 바람직하다.

하나만 더 짚고 넘어가자면
부호없는 정수같은 경우
음수에 해당하는 값이 없기 때문에 0부터 시작하여 양수 최댓값까지의 범위라면

부호있는 정수의 경우는
0을 중앙으로 최댓값(최고 양수)부터 최솟값(최저 음수)까지의 범위이다.

※ 타입(Type) 간 변환

  • 숫자 ▶ 문자(char)
    : (char)([int, double..] + '0') ("(char)"을 붙이고 문자 0을 더함 )

  • 문자(char) ▶ 숫자
    : [char] - '0' ( 문자 0을 빼줌 )

  • 숫자 ▶ 문자열(String)
    : [int, double..] + "" (빈 문자열)

  • 문자열(String) ▶ 숫자
    : "parse"계열 함수 사용 _ Integer.parseInt([String]) or Double.parseDouble([String])

  • 문자열(String) ▶ 문자(char)
    : [String].charAt(0)

  • 문자(char) ▶ 문자열(String)
    : [char] + "" (빈 문자열)

0개의 댓글