본문 바로가기
java

[Java] 변수, 연산자 : 기본이지만 잘 모르면 에러의 근원

by jinbro 2017. 9. 2.
[앞으로 포스팅하는 내용]
- 자바 기본 systax를 공부하고 중요한 부분만 포스팅할 것 : 알아둬야할 규칙, 자바 프로그래밍에 있어 꼭 알아둬야할 점 등


[Hello World 그리고 syntax]
- 프로그래밍 언어 첫번째 실행 단계인 Hello World 띄우기
public class Hello{

public static void main(String[] args){
System.out.println("Hello World!");
}
}

=> 클래스와 메서드 : 메서드는 단독으로 작성될 수 없고, 클래스 내부에 존재해야함
=> 클래스명의 첫번째는 항상 대문자, 클래스명과 파일명은 일치해야함
=> JVM이 기계어로 번역 후 실행시킬 때 main()을 찾아 실행함 : 이를 엔트리(Entry) 포인트라 함


[변수]
- 가장 기본이지만 중요함, 조금 상세하게 다룸
- Variable, 하나의 값을 저장할 수 있는 메모리 공간 : 중요합니다 메모리 상 어떻게 저장되는지
- 변수명 : 메모리 주소에 붙여진 이름 - 변수 이름을 통해서 메모리 주소에 접근
- 초기화 : 변수에 초기값을 집어넣는 것 - 값이 저장되어있지않은 메모리 공간에 값을 채워넣음
- 리터럴 : 직접 입력한 값을 변수에 저장, 값의 종류에 따라 OO리터럴이라 함(예시 - 정수 리터럴)
=> 주의할 것
(1) 01, 02 처럼 0으로 시작하는 리터럴은 8진수로 간주됨
(2) 소수점이 있는 리터럴은 10진수
(3) 작은따옴표('')는 문자 리터럴 , 큰따옴표("")는 문자열 리터럴

- 블록레벨스코프 : 변수의 유효범위는 중괄호( { .... } ) 내에서 유효 : 중괄호 내에서만 해당 변수 사용
=> 자바스크립트는 기본적으로 함수레벨스코프
=> 전역, 지역변수 구분
(1) 전역변수 : 클래스 전체에서 사용할 수 있도록 클래스 블록에 선언된 변수
(2) 지역변수 : 메서드 내에서만 사용할 수 있도록 메서드 블록에 선언된 변수

- 타입 : 모든 변수에는 타입이 있음(데이터형), 타입 선언함으로 데이터형을 나타내고, 무엇을 할 수 있을지 나타냄
(1) primitive type
(1-1) 정수타입(메모리크기 - byte 단위) : byte(1), char(2), short(2), int(4), long(8)
- byte 단위 : 1bitx8 = 8bit를 묶어 1byte라 함, 1bit(최소 메모리 단위)는 0과 1을 나타냄위
- 메모리크기가 크면 클수록 더 넓은 범위를 나타낼 수 있음 : 바꿔말해 int로 저장할 수 있는 데이터를 long으로 저장하면 메모리 낭비
- 범위 계산 : 1byte == -2의 n-1승 ~ 2의 n-1승-1(0을 포함해서 -1)
- 범위를 초과할 경우 Type mismatch 에러 발생
- byte : 바이너리 데이터 처리할 때 사용(이미지, 색상정보, 파일 등), 최상위비트(맨 앞)로 양/음을 구분(0/1) 나머지 7개 비트가 정수값
- byte, short, int, long의 경우 연산에 의해 변수에 저장된 값이 범위를 넘어서면 최소값부터 다시 연산을 시작
- char : 모든 문자 유니코드로 처리, 각국의 문자들과 코드값을 매핑한 것, 음수 없음, char 변수에 특정문자 코드값을 할당해도됨
- char : 빈 문자열을 할당하기위해 ''를 하면 안됨 - 컴파일 에러 발생, 반드시 유니코드를 포함해야함(유니코드: 32)
- int : 자바 정수 연산 기본타입, byte / short 와는 성능차이 별로없음(연산하면 int로 변환되기때문에), long과는 차이가 있지
- int : int형 변수에 어떤 진수값으로 저장된다고해도 2진수로 변환되어서 저장
- long : 큰 정수 연산을 위해 사용, 값 저장할 때 컴파일러에 알리는 목적으로 값L 혹은 값l(알파벳 L)을 붙임(int를 넘을땐 반드시 사용)

(1-2) 실수타입 : float(4), double(8)
- 소수점이 있는 실수 데이터를 저장하는 타입
- 부동소수점 방식 저장 : (+, -) 0.1234 x 10의 n승, 부호와 n(지수)와 0.1234(가수)를 메모리 내에서 나눠서 저장
- 부호, 지수와 가수가 저장되는 공간을 각각 나눠서 저장 : 할당되는 메모리크기는 int/long과 같지만 더 넓은 범위 저장
- float : double이 기본 타입이기때문에 double과 구분을 위해 값 뒤에 f나 F를 붙임
- double : float보다 지수 저장 크기가 큼(더 큰 지수를 저장), 기본 실수 연산 타입

(1-3) 논리타입 : true(1), false(1)

(2) reference type
- 참조 타입 변수
- 변수가 클래스 기반의 인스턴스 주소값을 가리킴
- 변수의 메모리에 값을 저장하지않고 인스턴스의 주소값(특정 객체)을 저장 : 참조하는 형태
- 표준 클래스 + 사용자 정의 클래스
- 앞으로 무지하게 많이 만날 것


- 형변환 : 자동 / 강제형변환이 있음
(1) 자동 : (상대적) 메모리 크기가 작은 데이터타입 -> 메모리 크기가 큰 데이터타입
- byte < char, short < int < float < long < double
- int - float, long - double은 각각 같은 크기지만 float와 double이 더 넓은 범위 표현
- char의 경우 int로 자동형변환 될 경우 유니코드값이 저장됨

(2) 강제 : 캐스팅이라함, (상대적) 메모리 크기 큰 -> 메모리 크기 작은
- 예를들어 int -> byte, int의 마지막 1byte 메모리에 저장된 데이터를 byte로 데이터 저장 : 데이터 손실
- byte a = (byte)intVal;
- 값이 손실되지않으면서 메모리 저장 크기를 줄일 때 사용 : 일련의 연산 과정 후 값이 작아지면...
- 손실 방지하기 : 자료형 Wrapper Class.MIN_VALUE, MAX_VALUE (Byte, Integer, Double 등)
- float와 double - int 변환 : 안정적으로 형변환을 위해서 double을 사용하는 것이 좋음

(3) 연산에서 자동형변환
- 상대적으로 메모리가 큰 데이터타입으로 형변환되어서 연산
- 예시 : int + double 연산이라면, int가 double로 변환되고 결과값도 double
=> 메모리로 보면 알지! : double은 8byte, int는 4byte -> int를 double로 변환(빈 byte는 0으로)

- 알아야할 것 : 피연산자(연산자에 의해 연산되는 데이터)는 4byte 단위로 저장함
=> 4byte보다 작은 크기 데이터타입(byte, short, char) 연산할 때 조심
=> 연산을 모두 다 한 후 결과값이 작을 때 4byte보다 작은 크기 데이터타입 변수에 저장


[연산자]
(1) 종류
- +, -, *, /, %
- ++, --
- +=, -=, *=, /=, =, ==, !=, >, >=, <, <=, instanceof
- !, &&, ||, ^(베타적 논리합 : 2개 중 하나가 true, 하나가 false일 때 true)
- (조건식) ? A : B (삼항연산자 : 조건식의 boolean 타입 결과값에 따라 A, B 둘 중 하나가)
- 비트연산자 : ~(비트 반전 연산, 0을 1로 1을 0으로), &, |, ^
- 쉬프트(비트) : >>, <<, >>> (비트를 좌우로 밀어서 이동)

(2) 우선순위
- 산술연산자는 우리가 알고 있는 그대로
- && 보다는 >, < 가 높음
- 괄호( (...) )를 사용하면 우선순위를 사용자 지정할 수 있음

(3) 주의할 것 + 팁
- 연산을 할 때에는 피연산자의 타입을 일치시켜놓고 연산을 함!
- JVM이 32비트 단위로 계산 : 정수 타입은 int로 변환(long이 있을경우 long으로) 연산
- 부호연산자의 산출타입은 int
- 증감연산자를 사용할 때 다른 연산자도 있다면 증감연산자의 위치에 따라 연산이 바뀔 수 있음
=> ++x + 10 : x에 저장된 값이 연산 전 증가, x++ + 10 : x에 저장된 값이 연산 후 증가
=> x가 1일 때 앞의 결과 : 12, 뒤의 결과 : 11
=> 단독으로 있을 때에는 위치 상관없음
=> += 과 ++은 같은 바이트코드로 변환됨 : 동일합니다, 연산 2번, 1번 상관없습니다

- 비트 반전 연산자를 사용하면 최상위 비트도 반전되므로 부호가 바뀜 : 양/음(0/1), int 산출
=> Integer.toBinaryString() : 정수값을 32비트(4byte)의 바이너리코드로 리턴

- 연산 -> 데이터 저장(각각 분리되어있음) + 데이터 타입에 맞춰 연산함
=> int a=10, b=4; double c=a/b; 결과값은 2.5일까? 아님 2.0임
=> a와 b가 /에 의해서 연산되는 피연산자 : 피연산자 모두 int 타입, int로 연산 -> 2.5지만 소수점 자르고 2
=> 연산한 후 = 대입 연산자에 의해 double 타입 c 변수에 2가 저장 : 2.0이 저장
=> 하나의 연산으로 봐서는 안됨 : 대입연산자는 가장 우선순위가 낮은 연산자
=> 2.5가 되려면 피연산자 둘 중 하나가 실수타입의 변수여야함 혹은 캐스팅

- 연산 결과가 데이터타입보다 오버되면 쓰레기값이 장착
=> try, catch + 메서드 입력 - 결과값으로 오버플로우 체크하고 연산하기
=> ArithmeticException 처리

- 부동소수점 타입(float, double)은 0.1을 정확히 표현X : 필요에 따라 모두 연산 후 부동소수점 타입으로 변환
=> 예시 : 0.3을 0.299999999999993으로 표현함

- 부동소수점을 입력받을 때 NaN 체크하는 것이 좋음
=> Double.inNaN(데이터) : == 으로 체크하면 안됨(false를 리턴)
=> NaN은 연산이 됨 그러나 결과값이 쓰레기값..

- 문자열 비교
=> 같은 문자열을 저장하고 있다면 같은 객체 주소값을 가리키는 것
=> 그러나 new String으로 새롭게 메모리 할당하여 저장된 문자열 데이터는 앞 전 문자열과는 다른 주소값
=> 값만 비교한다면 : 기준문자열.equals(비교문자열)

- 비트 연산 : 정수 타입만 연산가능(비트 단위로 연산하기때문 - 변환)
=> float, double X 



[예시코드]

public class Variable{
public static void main(String[] args){
/* 범위 초과 */
byte var1 = 127;
var1 += 1;
System.out.println(var1);

/* unicode */
char var2 = 65;
System.out.println(var2);

/* search unicode */
char var3 = 'c';
int var4 = var3;
System.out.println(var4);


/* String */
String var5 = "박진형";
System.out.println(var5);

/* char empty */
char var6 = 32;
System.out.println(var6);


/* long을 사용할 땐 값 뒤에 L을 */
long var7 = 2416464413121L;
System.out.println(var7);


/* float 사용할 땐 뒤에 f를 : 기본 연산 타입이 double */
float var8 = 3.14f;
System.out.println(var8);


/* boolean */
boolean var9 = true;
if(var9){
System.out.println("TRUE");
} else{
System.out.println("FALSE");
}


/* 자동형변환 : 작은 메모리 크기 -> 큰 메모리 크기 타입으로 자동 변환(값 손실x) */
byte var10 = 10;
int var11 = var10; // 00000000 00000000 00000000 00001010 (1byte -> 4byte)

/* 자동형변환2 : int -> float, 같은 크기이지만 float이 더 넓은 범위 표현 */
int var12 = 10;
float var13 = var12;
System.out.println(var13);

char var14 = 'a';
int var15 = var14;
System.out.println(var15);

int var16 = 10;
byte var17 = (byte)var16;
System.out.println(var17);

double var18 = 3.14;
int var19 = (int)var18;
System.out.println(var19);

int var20 = 126;
if(Byte.MIN_VALUE < var20 || Byte.MAX_VALUE > var20){
byte var21 = (byte)var20;
System.out.println(var21);
}

/* float : 가수 부분 23비트, int 32비트 - 표현범위가 좁아 값 손실 가능성이 있음, double 52비트 */
int var21 = 123456780;
int var22 = 123456780;

float var23 = var21;
var21 = (int)var23;
System.out.println("결과값 : " + (var21-var22));


double var24 = 10.5;
int var25 = 5;
int var26 = var25 + (int)var24;
System.out.println(var26);


byte var27 = 10;
int result = var27 + var27;


/* 부호 연산자 : int */
short var28 = 100;
int var29 = -var28;

/* 증감연산자 */
int var30 = 10;
int var31 = 10;
int result2 = ++var30 + 10; // 21
int result3 = var31++ + 10; // 20
System.out.println(result2 + ", " + result3);

/* 비트 반전 연산자 */
int var32 = 100;
System.out.println(Integer.toBinaryString(var32)); //앞이 0이면 모두 생략(붙여줘야함)
System.out.println(Integer.toBinaryString(~var32));


/* 연산자는 각각 연산 */
int var33 = 10, var34 = 4;
double var35 = var33 / var34;
double var36 = (double)var33 / var34;
System.out.println(var35 + ", " + var36);


/* 문자 연산 */
char var37 = 'a' + 1;
//char var38 = var37 + 1; 요로코롬 연산하면 int로 변환


/* 연산 전 데이터타입 일치 */
float var38 = 1f;
double var39 = 10;
double var40 = var38 + var39;


/* 문자열 */
String var41 = "진형";
String var42 = "진형";
String var43 = new String("진형");
System.out.println(var41 == var43);
System.out.println(var41.equals(var43));

boolean var45 = true;
boolean var46 = false;

if(var45^var46){
System.out.println("TRUE + FALSE");
} else {
System.out.println("!!!");
}

char var47 = 'a';
String msg = (var47>64) ? "TRUE" : "FALSE";
System.out.println(msg + ", " + (int)var47);



int var48 = 615;
System.out.println((var48/100)*100);


double var49 = 5.0;
double var50 = 0.0;

double var51 = var49%var50;

if(Double.isNaN(var51)){
System.out.println(var51);
} else {

}
}
}


댓글