[WhiteShip][2주차] 자바 데이터 타입, 변수 그리고 배열
Codestates BE 42 : Study, Commercise 01 Java
2주차 : 자바 데이터 타입, 변수 그리고 배열
목차
- 프리미티브 타입 종류와 값의 범위 그리고 기본 값
- 프리미티브 타입과 레퍼런스 타입
- 리터럴
- 변수 선언 및 초기화하는 방법
- 변수의 스코프와 라이프타임
- 타입 변환, 캐스팅 그리고 타입 프로모션
- 1차 및 2차 배열 선언하기
- 타입 추론, var
프리미티브 타입 종류와 값의 범위 그리고 기본 값
✅ 타입
어떤 값의 유형 및 종류
- 해당 메모리가 메모리에 어떻게 저장되고, 프로그램에서 어떻게 처리되어야 하는지를 명시적으로 알려줌
- 타입에 따라 값이 차지하는 메모리 공간의 크기와, 값이 저장되는 방식이 결정
기본(프리미티브) 타입 : 저장하고자 하는 값을 그대로 저장
참조(레퍼런스) 타입 : 저장하고자 하는 값을 임의의 메모리 공간에 저장한 후, 그 메모리 공간의 주소를 저장
프리미티브 타입과 레퍼런스 타입
✅ 기본 타입(primitive type)
- 실제 값을 저장하는 공간으로 스택(Stack) 메모리에 저장된다.
- 컴파일 시점에 담을 수 있는 크기를 벗어나면 에러를 발생시키는 컴파일 에러가 발생한다.
⏺ 종류
정수 타입(byte,short,int,long),실수 타입(float,double),문자 타입(char),논리 타입(boolean)
⏺ 데이터 크기와 기본값
기본값이 있기 때문에 'Null'이 존재하지 않는다.
- 만약, Null을 넣고 싶다면 래퍼 클래스를 활용
cf) Wrapper Class(래퍼 클래스) 8개의 기본 타입에 해당하는 데이터를 객체로 포장해 주는 클래스.
래퍼 클래스는 각각의 타입에 해당하는 데이터를 인수로 전달받아, 해당 값을 가지는 객체로 만들어 준다.
래퍼 클래스는 모두 java.lang 패키지에 포함되어 제공된다.
기본타입 : 래퍼 클래스
byte : Byte
short : Short
int : Integer
long : Long
float : Float
double : Double
char : Character
boolean : Boolean
래퍼 클래스는 산술 연산을 위해 정의된 클래스가 아니므로, 인스턴스에 저장된 값을 변경할 수 없다.
단지, 값을 참조하기 위해 새로운 인스턴스를 생성하고, 생성된 인스턴스의 값만을 참조할 수 있다.
cf) 인스턴스
설계도를 바탕으로 소프트웨어 세계에 구현된 구체적인 실체
-> 객체를 소프트웨어에 실체화하면 그것을 '인스턴스'라고 부른다.
설계화된 인스턴스는 메모리에 할당된다.`
- 과거에는 메모리 용량이 넉넉하지 않아 필요에 따라 변수의 자료 범위를 변경해야 했지만, 현재는 메모리 용량이 부족한 경우가 거의 없기 때문에 정수형을 사용할 때 일반적으로 ìnt형을 사용
- 1byte=8bit 컴퓨터는 2진수 언어이므로 한자리에 0 혹은 1이 들어갈 수 있다.
제일 앞은 음수 혹은 양수를 표현해야 하므로 1bit를 사용하면 남은 7bit로는 '2의 7제곱 = 128개'의 숫자를 표현할 수 있다. - ⏩ 1byte로는 -128~127의 표현이 가능
⏺ 유의사항
정수형 타입
- 결정할 때, 사용하려는 데이터의 최대/최소 표현 범위를 고려해야 한다.
- 범위를 벗어난 데이터를 저장하면 오버플로우(overflow) 또는 언더플로우(underflow)가 발생해 엉뚱한 값이 저장될 수 있기 때문이다.
- 오버플로우의 경우, 해당 데이터 타입의 최소값으로 값이 순환된다. ex) byte : 128 -> -127로 표현된다.
- 언더플로우의 경우, 최소값을 넘어가면 해당 데이터 타입의 최대값으로 값이 순환된다. ex) byte : -129 -> 127로 표현된다.
cf) 오버플로우(overflow) : 해당 타입이 표현할 수 있는 '최대 표현 범위'보다 큰 수를 저장할 때 발생하는 현상
언더플로우(underflow) : 해당 타입이 표현할 수 있는 '최소 표현 범위'보다 작은 수를 저장할 때 발생하는 현상
✅ 참조 타입(reference type)
객체의 주소를 저장, 8개의 기본형을 제외한 나머지 타입. 무언가를 저장할 때, 저장하고자 하는 것이 존재하는 위치를 저장.
- 어떤 값이 저장된 주소를 값으로 갖는다. (=데이터가 저장된 곳을 나타내는 주소값이 저장된다.)
- 빈 객체를 의미하는 'Null'이 존재한다.
- 힙(Heap) 메모리에 실제 Object가 저장, 스택(Stack) 메모리에 Object를 가리키는 참조타입 변수가 저장된다.
- 문법 상으로는 에러가 없지만 실행시켰을 때 에러가 나는 런타임 에러가 난다. ex) 객체나 배열을 Null값으로 받으면 NullPointException이 발생하므로 변수값을 넣어야 한다.
예시
public class Example {
public static void main(String[] args) {
int primitive = 1;
Object reference = new Object(); //객체 저장
//참조타입 변수 = 객체;
System.out.println(primitive);
System.out.println(reference);
}
}
Task :Test.main()
1
java.lang.Object@626b2d4a //객체의 주소값 ...`
primitive 변수 : 1 이라는 값 그 자체 저장.
=> 기본 타입은 값 그 자체가 변수에 저장되기 때문에 출력 결과는 기본타입변수가 저장하고 있는 값 1이 그대로 출력된다.
reference 변수 : 저장하고자 하는 것이 존재하는 위치를 저장. (like 주소).
객체를 어떤 변수에 저장한다면 그 변수에는 객체가 존재하는 메모리 주소를 값으로 가진다. 즉, 주소값이 변수에 저장.
cf) 래퍼 클래스 http://www.tcpschool.com/java/java_api_wrapper 타입 https://gbsb.tistory.com/144?category=735872
리터럴
✅ 리터럴 (Literal)
문자가 가리키는 값(데이터) 그 자체
int num;
num = l;
num에 할당하고 있는 1이 리터럴이다.
float weight = 74.5f;
finallong LIGHT_YEAR = 9460730472580L;
float = 9460730472580.0F;
double = 9460730472580.0D;
- float 타입 변수에 실수형 리터럴을 할당 시 리터럴 뒤에 접미사 f를 붙여야함
- long 타입 변수에 정수형 리터럴을 할당 시 리터럴 뒤에 접미사 L을 붙여야함 (소문자도 가능하지만 숫자와 혼동 되어 비추)
⏺ 정수 리터럴
byte, short, int, long
10진수 : 소수점이 없는 정수 리터럴
8진수 : 0으로 시작하는 리터럴
16진수 : 0x / 0X로 시작, 0~9 a~f로 구성된 리터럴
⏺ 실수 리터럴
float, double
10진수 실수 : 소수점이 있는 리터럴
10진수 지수와 가수 : E/e가 숫자 뒤에 존재하는 리터럴
⏺ 논리 리터럴
boolean (true, false)
⏺ 문자 리터럴
char
작은 따옴표( ' ' )로 묶인 하나의 텍스트
- 자바는 유니코드로 문자를 저장함.
char c1 = 'c';와 같이 문자 리터럴을 문자형 변수에 할당하면, c1 에는 영문자 c의 유니코드 숫자 값이 저장 된다.
이스케이프 문자
\t | 수평 탭 | 0x0009 |
\n | 줄 바꿈 | 0x000a |
\r | 리턴 | 0x000d |
\" | 큰 따옴표 표시 | 0x0022 |
\' | 작은 따옴표 표시 | 0x0027 |
\\ | \ 역슬래쉬 표시 | 0x005c |
\u16진수 | 16진수에 해당하는 유니코드 | 0x0000 ~ 0xffff |
변수 선언 및 초기화하는 방법
✅ 변수 (Variable)
- 데이터의 저장과 참조를 위해 할당된 메모리 공간에 붙인 이름
- 메모리 공간의 활용/ 할당 및 접근을 위한 이름
- 변수의 선언 : 메모리 공간의 할당
💡 컴퓨터는 메모리에 데이터를 저장
메모리는 1byte크기의 데이터를 저장할 수 있는 메모리 셀들이 모여서 만들어짐.
각 메모리셀엔 고유 번호가 오름차순으로 적혀있는데, 이 고유번호를 메모리 주소라고 함.
⏺ 변수를 사용하는 이유 (WHY)
문제점 1. 저장해야 할 값이 많을 때, 사람이 메모리주소를 식별하기 어려움
문제점 2. 시스템 운영에 꼭 필요한 데이터 공간에 실수로 덮어 쓸 가능성도 존재함.
문제점 3. 추상화되지 않은 코드는 비효율적임.
해결 : 변수라는, 사람이 식별 가능한, 값을 저장할 수 있는 메모리 공간을 확보함.
⏺ 선언
변수를 사용하기 위해 변수를 만들어 줌
변수 선언 방법 : [변수타입 변수명]
int num;
int - 4byte 메모리공간을 확보, num으로 명명
⏺ 할당
변수에 값을 저장하는 것.
대입연산자 (=) 사용
num = 1;
num이라는 변수에 1을 할당해라
- 초기화되지 않은 변수는 프로그램 안전성을 위해 사용할 수 없다.
⏺ 선언과 동시에 초기화
int num1 = 10;
int a = 100, b = 200;
- 서로 다른 타입들은 동시 초기화 불가능
- 이미 선언된 변수를 동시에 초기화 할 수 없다.
⏺ 변수 명명 규칙
0) 사용목적에 맞는 작명이 중요함. (사람에게 잘 읽힐 수 있게)
- 일반적으로 카멜케이스(camelCase) 사용 helloWorld
int camelCase;
2) 영문자 , 숫자 , _ , $ : 가능
3) 대소문자 구별
4) 숫자로 시작하는 변수명 : 사용불가
5) 자바의 예약어(reserved word) : 사용불가 void
네이밍 컨벤션 공식문서
변수의 스코프와 라이프타임
✅ scope of a variable ( 변수의 스코프 )
- 범위
- 변수에 엑세스 할 수 있는 프로그램의 영역 또는 섹션
- 자바에서 변수 선언시 해당 변수가 접근이 가능한 범위가 있다.
- 변수의 범위에 대한 포괄적인 관례는 변수가 선언된 블록 내에서만 접근 할 수 있다는 것이다.
✅ lifetime of a variable (변수의 라이프타임)
- 수명
- 변수가 메모리에서 얼마나 오래 살아있는지
⏺ 변수의 스코프와 라이프타임을 결정짓는 공통된 요소
- 변수가 어떻게 정의되었는가
- 변수가 어디서 정의되었는가
✅ 선언된 위치에 따른 변수의 종류 및 각 변수들의 스코프와 라이프타임
public class scope_and_lifetime {
int num1, num2; //Instance Variables
static int result; //Class Variable
int add(int a, int b){ //Local Variables
num1 = a;
num2 = b;
return a+b;
}
public static void main(String args[]){
scope_and_lifetime ob = new scope_and_lifetime();
result = ob.add(10, 20);
System.out.println("Sum = " + result);
}
}
⏺ 인스턴스 변수
1) 특징
- 클래스 내부에서 선언되었지만 메서드 블록 외부에서 선언된 변수
- 클래스의 인스턴스를 생성할 시점에 만들어짐
- → 인스턴스 변수의 값을 읽어오거나 저장하기 위해서는 먼저 인스턴스를 생성해야함
- 인스턴스는 독립적인 공간을 가지므로 다른 인스턴스가 서로 다른 값을 가질 수 있다.
- 인스턴스마다 고유한 상태를 유지해야하는 속성의 경우, 인스턴스 변수로 선언한다.
2) scope
- 정적 메서드를 제외한 클래스 전체
3) lifetime
- 클래스의 인스턴스를 생성할때 생성 인스턴스가 메모리에 머무를때까지
⏺ 클래스 변수
- 클래스 내부, 메서드 블록 외부에 선언되고 static 으로 선언된 변수
- 인스턴스 변수에 static 이 붙은 형태
- 클래스 변수는 모든 인스턴스가 공통된 저장공간(변수)를 공유하게 된다.
- 한 클래스의 모든 인스턴스들이 공통적인 값을 유지해야하는 속성의 경우 클래스 변수로 선언한다.
- 클래스변수는 클래스가 메모리에 로딩될때 생성되어(따라서 메모리에 한번만 올라간다.) 프로그램 종료까지 유지
- 인스턴스를 생성하지 않고도 클래스이름.클래스변수명 의 형태로 사용 가능
- public 을 붙이면 같은 프로그램 내의 어디서나 접근 가능한 전역변수의 성격을 갖는다.
2) scope
- public 적용시 : 프로그램 내의 어디서나 접근 가능
- (클래스이름.클래스변수명)
- public 미적용시 : 같은 Class 내부라면 어디서나
- (클래스 변수는 모든 인스턴스가 공통된 저장공간(변수)를 공유하게 된다.)
3) lifetime
- 클래스가 메모리에 로딩될때 생성
- 프로그램 종료 시 까지
⏺ 지역 변수
- 인스턴스 또는 클래스 변수가 아닌 모든 변수
- (ex : 메서드 내의 변수, 매개변수, loop 문 내의 변수, 스코프 내의 변수 등 )
2) scope
- 선언된 블록 내
3) lifetime
- 선언된 블록에 제어가 넘어올때 생성
- 지역변수가 선언된 블록에서 제어가 떠날때까지
타입 변환, 캐스팅 그리고 타입 프로모션
Type Casting 형변환의 넓은 의미
- 변수나 리터럴(상수)의 타입을 다른 타입으로 변환시키는 것
✅ Type Casting 캐스팅
- 명시적 타입 변환
- 형변환 연산자를 사용
double d = 85.4;
// ( 변환하고 싶은 타입 ) 피연산자
int score = (int) d;
주의 💢💢
- 형변환 연산자는 그저 피 연산자의 값을 읽어서 지정된 타입으로 형변환 하고 결과를 반환할 뿐이다.
- 위 코드에서 변수 d 의 값은 형변환 후에도 변하지 않는다.
- primitive type (기본형) 에서 boolean 을 제외한 나머지 값들은 서로 형변환 가능
⏺ 정수형간 형변환
- 작은 타입에서 큰 타입으로 변환할 경우 값 손실이 발생하지 않으며 메모리에서 남는 공간은 0(일반적인 경우) 또는 1(변환하려는 값이 음수인 경우) 로 채워진다.
- Integer.toBinaryString(int i) 를 사용하여 10진수 정수를 2진수 정수로 변환한 문자열 획득 가능
- 큰 타입에서 작은 타입으로 변환할 경우 부족한 공간만큼 잘려나간다.
- 값손실에 주의
⏺ 실수형간 형변환
- 참고
- 정수와 유사하나 큰범위에서 작은 범위로 변환할 때 오차발생 (데이터가 버려질때 반올림 수행으로 인함 )
- float 타입의 범위를 넘는 값을 float 으로 형 변환하는 경우 +-무한대 또는 +-0을 결과로 얻는다.
⏺ 정수형 ↔ 실수형 간의 형변환
- 정수를 실수로 변환 시
- 실수형으로 인한 오차가 발생할 수 있음에 유의
- 표현범위가 넓어 오차가 적은 double 을 사용하자
- 실수를 정수로 변환시
- 형변환시 실수형의 소수점 이하 값은 버려진다.
- primitive type 과 reference type(참조형) 간의 형변환은 불가능하다.
- 참조형간의 형변환은 가능
⏺ 참조형 타입과 참조형 타입의 형변환
- 상속관계가 아닌 클래스간의 형변환은 불가능
- 참조변수의 형변환을 통해 참조하고 있는 인스턴스에서 사용할 수 있는 멤버의 범위를 조절하는 느낌으로 사용한다.
- 객체지향 - 다형성과 관련된 내용
- 다형성
- 여러가지 형태를 가질 수 있는 능력
- 조상클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조할 수 있도록 하였다는 뜻
- 같은 타입의 인스턴스라도 참조변수의 타입에 따라 사용할 수 있는 맴버의 갯수가 다르다.
- 단, 참조변수가 사용할 수 있는 멤버의 개수는 인스턴스의 맴버 개수보다 같거나 적어야한다.
- 조상타입의 참조변수로 자손타입의 인스턴스를 참조할 수 있다.
- 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수 없다.
- 다형성
// Class FireEngine 은 Class Car 를 상속받는다.
Car car = null;
Car rearCar = new Car();
FireEngine fe = new FireEngine();
FireEngine fe2 = null;
FireEngine fe3 = null;
car = fe; // 자동 형변환 진행 car = (Car) fe;
fe2 = (FireEngine) car; // 형변환 생략 불가능
fe3 = (FireEngine) rearCar; // 에러 : ClassCastException
// 조상타입의 인스턴스를 자손타입의 참조변수로 참조하는것은 허용되지 않는다.
- 자손타입 → 조상타입 으로 형변환
- Up-casting
- 형변환 생락 가능
- 조상타입 → 자손타입 으로 형변환
- Down-casting
- 형변환 생략 불가능
- car = fe; // 자동 형변환 진행 car = (Car) fe; fe2 = (FireEngine) car; // 형변환 생략 불가능
✅ Type Promotion
- 묵시적 타입 변환
- 자동 형변환
- 서로 다른 타입간의 대입이나 연산을 수행 시 원칙적으로 타입을 일치시켜야 하지만 경우의 따라 편의상의 이유로 이를 생략 가능
- 이 경우 컴파일러가 생략된 형변환을 자동적으로 추가하여 이루어진다.
- 그러나 자동형변환을 수행하려고 해도 형변환이 불가능한 상황이라면 에러가 발생한다.
- ex : 좁은 데이터형에 큰 데이터를 넣으려 시도할때 incompatible type
- 명시적 형변환을 사용한 경우 에러가 발생하진 않지만 값 손실이 발생한다.
- 컴파일러가 개발자의 의도적인 행동이라고 간주
- 두 타입이 다른 연산에서 빈번히 발생한다.
- 연산과정에서 자동적으로 발생하는 형변환을 산술변환이라고 함
- 표현의 범위가 더 넓은 타입으로 형변환을 통해 타입을 일치시킨 후 연산을 수행
- → 값손실의 위험을 최소화 하기 위함
- 자동 형변환 규칙
- 서로 다른 두 타입 중 기존 값을 최대한 보존할 수 있는 타입으로 자동 형변환한다.
- 표현의 범위가 더 넓은 타입으로 형변환하여 값손실의 위험을 최소화
- 따라서 의도적으로 작은 타입으로 형변환 하기위해선 형변환 연산자를 사용해야한다.
- 서로 다른 두 타입 중 기존 값을 최대한 보존할 수 있는 타입으로 자동 형변환한다.
1차 및 2차 배열 선언하기
✅ n차원 배열의 선언
- 차원이란 축의 갯수
- 배열의 요소가 또 다른 배열인 경우
- 배열의 중첩 정도에 따라 1차원 배열, 2차원 배열, 3차원 배열
⏺ 1차원 배열
- 축이 하나인 배열
- 중첩된 요소가 없는 배열
type[] 배열명 = new type[];
type[] 배열명 = new type[]{};
type[] 배열명 = {값, ...};
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3 at App.main(App.java:33)
- 모든 배열은 인덱스로 접근, 인덱스 0부터 길이의 -1 인덱스까지 존재
⏺ 2차원 배열
- 축이 두 개인 배열
- 중첩된 요소가 하나있는 배열
type[][] 배열명;
배열명 = new 타입[][];
타입[][] 배열명 = new 배열명[][]'
배열명 = {{}, ...}
타입 추론, var
✅ 타입추론이란?
타입추론은 개발자가 변수의 타입을 명시하지 않아도, 컴파일러가 변수의 타입을 대입된 리터럴로 타입을 추론.
✅ var
- 자바 10부터 지원.
- 선언과 동시에 초기화가 필수.
- null이 할당될 수 없다.
- 키워드가 아니기 때문에 변수명으로 할용가능.
- 지역변수로만 이용가능.(멤버변수(필드), 메소드의 매개변수(파라미터), 리턴타입으로 사용 불가)
- 컴파일에 추론하기 때문에 runtime에는 추가 연산이 없어 성능 영향 x💡 컴파일 되면 타입이 바뀔 일이 없음!!
- 배열에 사용불가. 💡 동일한 타입만 들어갈 수 있는데, 타입을 모르기 때문.
- 다이아몬드 연산자<> 에 타입 명시 안 하면 <Object>로 추론. 💡 다이아몬드 연산자란? 자료형 데이터 타입에 타입을 추론할 수 있도록 도와주는 연산자
- (람다 사용시 정확한 타입 명시 필요.)
⏺ var 쓰는 이유
- 데이터의 타입을 유추할 수 없어 변수 명명에 더욱 신경씀.
- forEach에서 사용시 타이핑이 더 간결해지고, Object 타입을 단정할 필요 x
- (익명 클래스에서 사용시, 선언한 이후에는 변수가 바뀔 일이 없기 때문에 편리)
- (람다에는 파라미터 어노테이션을 넣을 수 없는데, 넣고 싶다면 따로 메소드를 만들거나 익명 클래스로 정의해야함.)
references
남궁석 - 자바의 정석
https://www.learningjournal.guru/article/programming-in-java/scope-and-lifetime-of-a-variable/
https://itmining.tistory.com/20
https://codechacha.com/ko/java-variable-scope/
남궁석 - 자바의 정석
http://www.tcpschool.com/java/java_datatype_typeConversion
https://93jpark.tistory.com/124