-
2주차 과제: 자바 데이터 타입, 변수 그리고 배열Programming/Java live study 2020. 12. 24. 02:09
목표
자바의 프르미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힌다.
학습할 것
- 프리미티브 타입 종류와 값의 범위 그리고 기본 값
- 프리미티브 타입과 레퍼런스 타입
- 리터럴
- 변수 선언 및 초기화하는 방법
- 변수의 스코프와 라이프타임
- 타입 변환, 캐스팅 그리고 타입 프로모션
- 1차 및 2차 배열 선언하기
- 타입 추론, var
1. 프리미티브 타입 종류와 값의 범위 그리고 기본 값
출처 : github.com/kksb0831/Practice_project/blob/master/Java_Study_02.md
타입 할당되는 메모리 크기 기본값 데이터의 표현 범위 논리형 boolean 1 byte false true, false 정수형 byte 1 byte 0 -128 ~ 127 short 2 byte 0 -32,768 ~ 32,767 int 4 byte 0 -2,147,483,648 ~ 2,147,483,647 long 8 byte 0L -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 실수형 float 4 byte 0.0F -3.4E38 ~ 3.4E38 double 8 byte 0.0 -1.7E308 ~ 1.7E308 문자형 char 2 byte 유니코드 ‘\n0000’ 0 ~ 65,535 총 8 가지의 기본형 타입이 정의되어 있다. 기본형에는 기본값이 정해져 있기 때문에 null 값이 존재하지 않는다. 실제 값은 stack 메모리에 저장되며 메모리의 크기보다 큰 값을 넣으려고 하면 컴파일 에러가 발생한다.
정수형의 경우 첫 번째 비트는 부호를 나타내고 나머지 n - 1 비트는 수를 표현하는데 사용된다.
실수형의 경우 값을 부호, 지수, 가수로 나누어 저장된다. 그렇기 때문에 같은 크기임에도 훨씬 큰 범위를 표현할 수 있고 실수형은 원래 저장하려던 값과 실제 저장한 값이 오차가 날 수 있다. 그렇기 때문에 오차없는 자리 수인 정밀도가 굉장히 중요하기 하고, 정밀도를 계산하는 방법은 가수 부분의 데이터 크기에 관련되어 있다.
2. 프리미티브 타입과 레퍼런스 타입
출처: github.com/kksb0831/Practice_project/blob/master/Java_Study_02.md
2.1 프리미티브 타입
- 총 8가지의 기본형 타입이 있다. 기본형은 기본값을 가지고 있기 때문에 Null이 존재하지 않는다. 만약 Null을 넣고 싶으면 Wrapper class를 활용해야 한다.
- 실제 값을 저장하는 공간이기 때문에 Stack 메모리에 저장된다.
- 컴파일 시점에 담을 수 있는 크기를 벗어나면 컴파일 에러가 발생한다.
- 기본형은 객체가 아니다.
2.2 레퍼런스 타입
- 프리미티브 타입을 제외한 타입들은 모두 레퍼런스 타입이다.
- 빈 객체를 의미하는 Null이 존재한다.
- 값이 저장되어 있는 곳의 주소값을 저장하는 공간으로 Heap 메모리에 저장된다.
- 문법상으로 에러가 없지만 실행시에 에러가 나는 런타임 에러가 발생할 수 있다. 객체나 배열이 Null을 값으로 받고 사용하면 NullPointException이 발생하므로 값을 넣어야 한다.
타입 기본값 할당되는 메모리 크기 배열 Array Null 4 byte 객체의 주소값이 들어 간다. 열거 Enumeration Null 4 byte 객체의 주소값이 들어 간다. 클래스 Class Null 4 byte 객체의 주소값이 들어 간다. 인터페이스 Interface Null 4 byte 객체의 주소값이 들어 간다. 2.3 데이터를 저장하고 생성하는 위치
프리미티브 타입의 경우 Java에서 정의되어 있는 데이터 타입으로 변수를 선언할 때 메모리에 고정된 크기로 저장되고 변수에 데이터의 값을 저장한다.
레퍼랜스 타입의 경우 변수를 선언할 때 크기가 정해져 있지 않고 값이 변수에 할당 될 때 저장할 메모리에 대한 주소가 저장된다.
프리미티브 데이터타입의 경우 Thread가 가지고 있는 stack 영역에 생성되고 레퍼랜스 타입은 heap 영역에 생성된다.
public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } }
public class MemoryTest { public static void main(String[] args) { int i = 10; double d = 10.12; Person person = new Person("최기현", 25); } }
프리미티브 타입의 i와 d, 레퍼런스 타입의 person을 그림으로 표현하였다.
3. 리터럴
- 프로그램에서 직접 표현한 값.
- 종류에는 정수, 실수, 문자, 특수 문자, 논리, 문자열 리터럴이 있다.
3.1 정수 리터럴
모든 임의의 정수 값은 정수 리터럴이다. 1, 2, 3, 10, 25 등등
- 8진수는 01, 023, 012 등 표현한다. 그렇기 때문에 12와 012는 서로 다르게 인식될 수 있다.
- 16진수는 0x23, 0X12, 0xAE 등 표현한다. 10 ~ 15는 A B C D E가 대신한다.
- 모든 정수형 데이터는 기본적으로 int 형이기 때문에 long 데이터 자료형에 long 리터럴을 지정하기 위해 숫자 뒤에 l이나 L을 붙인다. 1L, 2L 등등 이렇게!
int decimal = 30; // 일반적인 형태 10진법 int ocatal = 031; // 제일 앞에 0 이 붙으면 8진법 int heaxaDecimal = 0x1a; // 0x가 붙으면 16진법 int binary = 0b11010; // 0b가 붙으면 2진법
3.2 실수 리터럴
- 소수점 이하를 가지는 10진 값들이다. 10.13, 3.141592 등등
- 기본형은 double 타입이다. 숫자 뒤에 d나 D를 추가할 수도 있다. 10.13d, 10.13D
- float는 숫자 뒤에 f나 F를 추가해야 한다. 10.13f, 10.13F
- 지수도 표현 가능하다. e나 E를 붙인다. 10E-1, 10e2
double d1 = 0.1; // 0.1 double d2 = 1E-1; // 0.1 float f = 0.1f; // 0.1
3.3 문자 리터럴
- 문자 한 개를 표현하는 것이다. ‘a’, ‘ㅋ’
- 유니코드를 표현할 수도 있다. \u 다음에 네 자리 16진수로 2바이트의 유니코드를 표현한다. 문자 A를 표현하면? ‘\u0041’
char c = 'a';
3.4 특수 문자 리터럴
특수 문자 설명 `\b’ 백스페이스 ‘\t’ 탭 ‘\n’ 다음 줄로 넘어감 ‘\f’ 폼 피드 ‘\r’ 캐리지 리턴 ‘\’’ 단일 인용 부호 ‘\”’ 이중 인용 부호 ‘\’ 백 슬래시 3.5 논리 리터럴
- 참을 의미하는 true
- 거짓을 의미하는 false
boolean t = true; boolean f = false;
3.6 문자열 리터럴
- 문자열 리터럴은 “abcd”같이 이중 인용 부호를 사용하여 표현한다.
- 기본 타입의 리터럴이 아니다. Java에서 문자열은 String class의 객체이기 때문이다.
String a = "abcd";
3.7 [더 알아보기] 상수와 리터럴
상수 constant
- 정수를 포함하여 다양한 데이터가 올 수 있고, 객체가 올 수도 있다. 말 그대로 데이터가 변하면 안된다.
- 참조 변수를 상수로 지정하면 참조변수가 가리키는 인스턴스 안의 데이터 까지도 변하지 않을 것을 기대하지만 참조변수가 변하지 않는다는 의미이고 그 주소가 가리키는 데이터는 상수가 아니다. Java에서는 final로 표현한다.
- final String s = “abcd”’;
리터럴 literal
- 데이터 그 자체를 뜻한다.
- 변수에 넣는 변하지 않는 데이터 자체를 의미한다.
- int a = 1을 예시로 들면 1이 리터럴이 된다.
그렇다면 인스턴스(클래스 데이터)는 리터럴이 될 수 있을까? 답은 아니오 이다. 왜냐하면 객체 안에 값이 언제든지 바뀔 수 있기 때문이다. 하지만 데이터가 변하지 않도록 설계한 immutable class를 들어보았을 것이다. 해당 클래스는 한번 생성하면 객체 안의 데이터가 변하지 않는다. 변하는 상황이 생기면 새로운 객체를 만들어서 리턴한다. Java의 String이 그 예이다. 이를 객체 리터럴이라고 표현하기도 한다. 그렇기 때문에 VO class도 immutable 하기 때문에 리터럴이 될 수 있다.
4. 변수 선언 및 초기화하는 방법
4.1 변수 선언
- [타입] [변수이름];
- 변수의 이름은 자바 식별자의 규칙을 지켜야 한다. 식별자는 변수나 상수 메소드 클래스 등을 구분할 수 있는 이름이다.
int a;
위 코드는 변수를 선언한 것이다. 저장할 공간을 확보하고 해당 공간의 이름을 a라고 칭한다.
4.2 Java 식별자 규칙
- 첫 문자가 문자나 ‘_’, ‘$’의 특수문자로 시작되어야 한다. 숫자로 시작할 수 없다.
- 첫 문자가 아니라면, 문자나 ‘_’, ‘$’의 특수문자 그리고 숫자로 구성될 수 있다.
- Java의 예약어는 식별자로 사용할 수 없다.
- Java의 식별자는 대소문자를 구분한다.
- 식별자 길이는 제한이 없고 공백은 포함할 수 없다.
4.3 Java 일반적인 관례
- 클래스 이름은 첫 글자를 대문자로 정의. 명사를 사용
- 메소드 이름은 소문자의 동사로.
- 변수는 소문자의 명사
- 상수는 모든 단어가 대문자인 파스칼 표기법을 사용 대문자의 명사
- 여러 단어가 있으면 낙타 등처럼 내려갔다 올라가는 모양을 표현하는 카멜 표기법을 사용
- 이외로 언더바를 사용하여 단어를 구분 짓는 스네이크 표기법이 있다.
4.4 Java의 예약어
자바의 예약어 사용시 주의점
- const, goto 예약어는 현재는 자바에서 사용되지 않으며, 식별자로 사용 할 수 없다.
- 자바의 예약어는 소문자로 이루어져 있고 대소문자를 구분하므로, TRUE, FALSE, NULL은 자바 예약어가 아니다.
- C, C++언어에서 변수의 길이를 표현했던 sizeof 예약어는 자바에서 더 이상 사용되지 않는다.
- assert는 j2sdk .14버전부터 추가된 예약어이다.
- True와 False는 boolean 형 상수
- Null은 참조형 상수로서 참조하는 곳이 없음을 의미한다.
4.5 초기화 하는 방법
- 변수를 선언하고 처음으로 값을 저장하는 것!
- 아직 scope에 대해 언급하지 않았지만, 멤버변수(인스턴스 변수, 클래스 변수)는 초기화를 하지 않아도 변수의 자료형에 맞게 기본값으로 초기화가 된다. 하지만 지역변수는 사용하기 전에 반드시 초기화를 해야 한다.
- 멤버 변수의 초기화 방법에는 3가지가 있다.
- 명시적 초기화 (explicit initialization)
- 생성자 (constructor)
- 초기화 블록 (initialization block)
- 인스턴스 초기화 블록 : 인스턴스변수 초기화
- 클래스 초기화 블록 : 클래스 변수 (static 변수) 초기화
4.5.1 명시적 초기화, 생성자
- 변수 선언과 동시에 초기화 하는 것
- 기본형은 int door = 4;
- 참조형은 생성자를 활용하여 String s = new String();
4.5.2 초기화 블럭
class InitClass { static { } // 클래스 초기화 블럭 { } // 인스턴스 초기화 블럭 }
- 복잡한 초기화 작업이 필요할 때 사용한다.
- 클래스 초기화 불럭은 클래스 변수 초기화에 사용된다. 클래스가 메모리에 처음 로딩될 때 한번만 수행된다. 클래스가 처음 로딩될 때 클래스 변수들이 자동적으로 메모리에 만들어지고 나서 바로 클래스 초기화 블럭이 클래스 변수들을 초기화 한다.
- 인스턴스 초기화 블럭은 인스턴스 변수 초기화에 사용된다. 생성자와 같이 인스턴스를 생성할 때 마다 수행한다. 생성자가 실행되기 전에 인스턴스 초기화 블럭이 먼저 실행된다. 하지만 주로 생성자를 사용하기 때문에 잘 사용하지 않는다.
4.6 [더 알아보기] 생성자의 특징
- 값을 반환하지 않는다. 생성자는 인스턴스를 생성해주는 역할을 하는 특수한 메소드이다. 하지만 반환값이 있다면 엉뚱한 객체가 생성될 수 있다. 그렇기 때문에 반환 타입과 return을 메소드 정의에 포함하지 않는다.
- 생성자의 이름은 클래스의 이름과 동일하다.
5. 변수의 스코프와 라이프타임
출처 : catsbi.oopy.io/6541026f-1e19-4117-8fef-aea145e4fc1b
5.1 변수의 스코프
- 사용되는 모든 변수들은 사용가능한 범위를 가지고 있다. 그것이 변수의 스코프이다. 다양한 스코프를 가진 변수들이 있는데 하나씩 알아보자. 스코프에 대해 알아보기 전에, 우선 static이 붙은 변수 및 메소드와 아닌 것의 차이를 확실히 알아야 한다.
클래스 vs 객체 vs 인스턴스
static을 좀 더 쉽게 이해하기 위해 3개의 차이를 간단히 보고 넘어가자.
- 클래스는 간단히 얘기하면 객체를 만들 수 있는 설계도 이다.
- 객체는 설계도로 구현된 대상을 의미한다.
- 그 객체가 메모리에 할당되어 실제로 사용되면 그때부턴 인스턴스라고 부른다.
public class Circle { // 클래스 ... } public class Main { public static void main(String[] args) { Circle circle; // 객체 circle = new Circle(); // 메모리에 할당되었기 때문에 인스턴스 } }
public class VariableScope { int globalvariable = 10; // 인스턴스 변수 static int staticVariable = 10; // (static)클래스 변수 public void methodScope(int parameterValue) { int localvariable = 10; // 지역 변수 } public static void main(String[] args) { int localVariable = 10; VariableScope variableScope = new VariableScope(); System.out.println(variableScope.staticVariable); // 인스턴스를 사용한 접근 System.out.println(VariableScope.staticVariable); // 클래스를 사용한 접근 } }
변수의 종류 선언 위치 생성 시기 클래스 변수 클래스 영역 클래스가 메모리에 올라갈 때 인스턴스 변수 인스턴스가 생성되었을 때 지역 변수 클래스 영역 이외의 영역 변수 선언문이 수행되었을 때 인스턴스 변수
- 클래스 영역에 선언되고 클래스의 인스턴스를 생성할 때 만들어진다. 인스턴스 변수 값을 읽어오거나 저장하기 위해서 먼저 인스턴스를 생성해야 한다.
클래스 변수
- 멤버 변수에 static 키워드가 붙는 경우 클래스 변수가 되고, 한 클래스의 모든 인스턴스가 값을 공유한다. 클래스 변수는 인스턴스를 생성하지 않고 클래스가 올라간 시점 부터 생성되기 때문에 인스턴스는 언제 어디서든 접근이 가능하다.
혹은 클래스를 사용하여 바로 접근이 가능하다.
지역 변수
- 메소드 내에 선언되어 메소드 내에서만 사용가능하다. for문이나 while 같은 반복문의 경우 해당 블록 내에 선언된 지역 변수는 블록을 벗어나면 소멸된다.
for () { ... } while () { ... }
{ int a; } { int a; }
해당 블럭내에서만 유효하기 때문에 다른 블럭에서는 같은 이름의 지역 변수를 선언해도 컴파일 에러가 나지 않는다!
5.2 라이프타임
라이프타임은 말 그대로 메모리에서 살아있는 시간을 말한다.
static 변수인 클래스 변수를 제외한 인스턴스 변수들은 객체가 생성되고 메모리에 살아 있는 동안은 여전히 살아 있다.
클래스 변수는 클래스가 처음 로딩된 후 프로그램이 끝날 때 까지 살아 있다.
loop나 블럭 내에 있는 지역변수들은 변수 선언 이후 부터 블럭을 벗어날 때 까지 살아 있다.
- 초기화 시점
분류 초기화 시점 클래스 변수 클래스가 처음 로딩될 때 단 한번 초기화 인스턴스 변수 인스턴스가 생성될 때 마다 각 인스턴스 별로 초기화 - 초기화 순서
분류 초기화 순서 클래스 변수 기본값 -> 명시적 초기화 -> 클래스 초기화 블록 인스턴스 변수 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블록 -> 생성자
6. 타입 변환, 캐스팅 그리고 타입 프로모션
6.1 타입 변환
타입을 다른 타입으로 바꾸는 것을 타입 변환이라고 한다. Java의 기본형에서는 boolean 타입을 제외하고는 자유롭게 타입 변환을 할 수 있다.
Java 연산은 피연산자들을 같은 타입으로 만든 후 수행되는 것을 권장한다. 이유는 큰 타입을 작은 타입으로 변환하면 데이터의 손실을 유발할 수 있기 때문이다.
타입 변환에는 두 가지 방식이 있다.
1. 묵시적 타입 변환 - 묵시적 타입 변환은 컴파일러가 자동으로 수행해주는 타입 변환이다. Java에서 데이터 손실을 최소화하는 방향으로 묵시적 타입 변환을 진행한다.
2. 명시적 타입 변환 - 명시적 타입 변환은 더 작은 타입으로 변환할 때 강제적으로 명시하여 타입을 변환해 준다. 데이터 손실을 막을 순 없다.
int value1 = 10; long value2 = value1; // 묵시적으로 타입 변환이 일어난다.
long value1 = 10; int value2 = (int) value1; // 명시하여 타입 변환한다.
6.2 캐스팅
레퍼런스 타입을 타입 변환을 하려면 상속 관계여야 한다.
-
up casting - 사자(자식) class를 동물(부모) class로 변환하는 것은 자연스럽다.
-
down casting - 동물(부모) class를 사자(자식) class로 변환하는 것은 부자연 스럽다. 오류 발생 가능성이 늘어난다 추가적으로 up casting으로 레퍼런스 타입으로 선언된 변수에 자식 타입을 참조하게 되면 다형성 측면에서는 매우 유리하지만, 부모 타임에 있는 public method만 사용이 가능해진다.
6.3 타입 프로모션
크기가 더 작은 자료형을 더 큰 자료형에 대입할 때, 자동으로 작은 자료형이 큰 자료형으로 변환되는 현상. 자동적으로 일어난다.
int a = 20; double b = a; // 별다른 컴파일 오류를 보이지 않는다.
7. 1차 및 2차 배열 선언하기
7.1 1차원 배열
int[] arr1 = {1, 2, 3, 4, 5};
arr1은 실제 값이 저장되어 있는 메모리의 주소값을 가진다.
7.2 2차원 배열
int[][] arr2 = {{1, 1}, {2, 2}};
arr2는 실제 값이 저장되어 있는 메모리의 주소를 가리키는 배열의 주소를 가지고 있다.
8. 타입 추론, var
출처 : catsbi.oopy.io/6541026f-1e19-4117-8fef-aea145e4fc1b
8.1 타입 추론
Java 컴파일러에서 탑입을 추론하는 것을 Type Inference라고 한다. 타입추론을 하기 위해서는 메소드 호출과 호출 시점에 사용하는 매개변수를 결정하기 위한 선언부를 살펴본다. 추론 알고리즘을 통하여 매개변수 타입을 결정하고 가능하다면 결과가 할당되는 타입이나 반환 타입을 추론한다.
static <T> T pick(T a1, T a2) { return a2; } public static void main(String[] args) { Serializable d = pick("d", new ArrayList<String()); }
8.2 generic 메소드
타입추론 덕분에 generic 메소드를 사용할 때 보통의 메소드 처럼 특정 타입을 명시하지 않고 호출할 수 있다.
8.3 Generic 클래스
Generic 클래스의 생성자를 호출하기 위해 필요한 type arguments를 비어 있는 type withness(<>, the diamond)로 대체할 수 있다.
List<String> list = new ArrayList<>();
8.4 var
Java 10에서 var라는 Local Variable Type-Inference가 추가되었다. 이 키워드는 local variable 이고, 선언과 동시에 초기화가 이루어져야 한다. 컴파일러가 초기화 값을 보고 타입을 유추하기 때문이다. var를 이용하면 기존의 엄격한 타입 선언 방식에서 컴파일러에게 타입추론 책임을 위임한다.
String s = "Hello Java9"; var s = "Hello Java10";
References.
github.com/kksb0831/Practice_project/blob/master/Java_Study_02.md
'Programming > Java live study' 카테고리의 다른 글
6주차 과제: 상속 (0) 2020.12.24 5주차 과제: 클래스 (0) 2020.12.24 4주차 과제: 제어문 (0) 2020.12.24 3주차 과제: 연산자 (0) 2020.12.24 1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가. (0) 2020.12.24