오버플로우(overflow)란 변수가 담을 수 있는 값의 범위를 벗어나는 데이터를 담았을 때 발생하는 현상을 오버플로우라고 한다.
자료형 별 값의 최대 범위를 벗어나는 경우 발생한 carry를 버림처리 하고 sign bit를 반전시켜 최소값으로 순환시키는 현상이다.
byte num1 = 127;
System.out.println("num1 : " + num1); //127 : byte의 최대 저장 범위
num1++; //1 증가
System.out.println("num1 overflow : " + num1); //-128 : byte의 최소 저장 범위
byte num2 = -128;
System.out.println("num2 : " + num2); //-128 : byte의 최소 저장 범위
num2--; //1 감소
System.out.println("num2 underflow : " + num2); //127 : byte의 최대 저장 범위
자바 형변환(casting) 이란 변수 또는 리터럴을 다른 타입으로 변환하는 것을 말한다.
형변환을 하는 이유는 프로그램에서 변수에 값을 넣거나(대입) 연산(산술연산)을 수행할 때는 같은 타입끼리만 가능하기 때문이다.
컴파일러가 자동으로 수행해주는 타입 변환이다. 데이터 손실 가능성이 없는 경우 자동으로 타입을 맞춰준다.

/* 1. 정수끼리의 자동 형변환 */
/* 점점 더 큰 자료형으로 데이터를 옮겨도 문제 없이 자동 형변환 처리 된다. */
byte bnum = 1;
short snum = bnum;
int inum = snum;
long lnum = inum;
/* 연산 시에도 자동으로 큰 쪽 자료형에 맞춰서 계산한다. */
int num1 = 10;
long num2 = 20;
//int result1 = num1 + num2; //자동으로 큰 쪽 자료형인 long으로 변경 후 계산하기 때문에 int형 변수에 값을 담을 수 없다.
long result1 = num1 + num2; //int + long은 서로 다른 자료형이라 데이터 손실이 발생하지 않는 int-> long 변환을 자동 수행 후 연산한다.
System.out.println("result1 : " + result1);
/* 2. 실수 끼리의 자동 형변환 */
float fnum = 4.0f;
double dnum = fnum;
/* 연산 시에도 자동으로 큰 쪽 자료형에 맞춰서 계산된다. */
double result2 = fnum + dnum;
System.out.println("result2 : " + result2);
/* 정수를 실수로 변경할 때 소수점 자리수가 없어도 실수형태로 표현이 가능하다. 이 때 데이터 손실이 없기 때문에 자동 형변환이 가능하다.
* 실제 값을 저장하는 매커니즘을 가진 것과 달리 실수형은 지수부와 가수부를 따로 나눠서 작성하기 때문에
* 바이트 크기 보다 훨씬 더 많은 값을 표현할 수 있다.
* */
//long eight = 888888888888888888888; //이것도 지동으로 형변환 된 것이다. (int 범위 벗어나면 에러 발생)
long eight = 8;
float four = eight;
System.out.println("four : " + four);
/* 따라서 실수와 정수의 연산은 실수로 연산 결과가 반환된다. */
float result3 = eight + four;
System.out.println("result3 : " + result3);
char ch1 = 'a';
int charNumber = ch1;
System.out.println("charNumber : " + charNumber);
/* int로 type이 정해지지 않은 리터럴 형태의 정수는 char 형 변수에 기록 가능하다. */
char ch2 = 65;
System.out.println("ch2 : " + ch2);
형변환(casting) 연산자를 이용한 강제적으로 수행하는 형변환이다.
자동형변환의 조건과 정 반대인 경우 강제 형변환을 사용한다.
큰 자료형 -> 작은 자료형으로는 강제 형 변환이 필요하다.
/* 1. 정수 끼리의 강제 형변환 */
long lnum = 8;
//int inum = lnum; //데이터 손실 가능성을 컴파일러가 알려준다. (에러남)
int inum = (int) lnum; //변경하려는 자료형을 명시하여 강제 형변환을 해야 함
short snum = (short) inum;
byte bnum = (byte) snum;
/* 2. 실수 끼리의 강제 형변환 */
double dnum = 8.0;
//float fnum = dnum; //데이터 손실 가능성을 컴파일러가 알려준다. (에러남)
float fnum = (float) dnum;
System.out.println(fnum);
float fnum2 = 4.0f;
//long lnum2 = fnum2; //float는 4byte, long은 8byte임에도 자동 형변환 불가능 (소수점 자리 이하 데이터 손실 가능성)
long lnum2 = (long) fnum2; //강제 형변환의 의미는 '내가 데이터 손실을 감안할테니 형변환 해줘~' 라는 의미이다.
char ch = 'a';
byte bnum2 = (byte) ch; //당연히 char 자료형보다 작은 크기이니 강제형변환을 해야 한다.
short snum2 = (short) ch; //같은 2byte이지만 부호비트(sign bit)로 인한 값의 범위가 다르기 때문에 강제 형변환을 해 주어야 한다.
/* 추가적으로 정수를 char 자료형에 강제 형변환해서 대입하기 테스트 */
int num1 = 97;
int num2 = -97;
char ch2 = (char) num1;
char ch3 = (char) num2; //음수도 강제 형변환 하면 대입할 수 있다.
System.out.println("ch2 : " + ch2);
System.out.println("ch3 : " + ch3);