일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- auto.create.topics.enable
- throwable
- yield
- 자바스터디
- System.in
- 브릿지 메소드
- 합병 정렬
- 람다식
- 접근지시자
- 정렬
- System.err
- System.out
- 함수형 인터페이스
- 익명 클래스
- 상속
- docker
- 바운디드 타입
- annotation processor
- raw 타입
- junit 5
- 제네릭 타입
- github api
- 제네릭 와일드 카드
- 로컬 클래스
- 스파르타코딩클럽
- Study Halle
- 자바할래
- 프리미티브 타입
- Switch Expressions
- 항해99
- Today
- Total
코딩하는 털보
STUDY HALLE - 2주차 본문
STUDY HALLE
2주차 : 자바 데이터 타입, 변수 그리고 배열
목표
자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다.
학습할 것
- 프리미티브 타입 종류와 값의 범위 그리고 기본 값
- 프리미티브 타입과 레퍼런스 타입
- 리터럴
- 변수 선언 및 초기화하는 방법
- 변수의 스코프와 라이프타임
- 타입 변환, 캐스팅 그리고 타입 프로모션
- 1차 및 2차 배열 선언하기
- 타입 추론, var
프리미티브 타입 종류와 값의 범위 그리고 기본 값
Data Type | Size | Range of Values | Default Value |
---|---|---|---|
byte | 1 byte | -128 to 127 | 0 |
short | 2 bytes | -32,768 to 32,767 | 0 |
int | 4 bytes | -2,147,483,648 to 2,147,483,647 | 0 |
long | 8 bytes | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | 0L |
float | 4 bytes | upto 7 decimal digits | 0.0f |
double | 8 bytes | upto 16 decimal digits | 0.0d |
boolean | 1 bit | true or false values | false |
char | 2 bytes | 0 to 65535 ('\u0000' ~ 'uFFFF') | '\u0000' |
프리미티브 타입과 레퍼런스 타입
프리미티브 타입은 리터럴을 대입할 수 있는 위 8가지 데이터 타입이며,
레퍼런스 타입은 프리미티브 타입 외의 모든 타입(클래스, 인터페이스, 배열, 리스트)이다.
이 둘의 궁극적인 차이점은
프리미티브 타입 같은 경우 변수 선언시 할당되는 메모리 공간에 실제 값을 담아 놓지만,
레퍼런스 타입은 다른 곳을 참조하는 주소 값을 담아 놓는다는 것이다.
public class Hello {
public static void main(String args[]) {
Student student;
student = new Student();
System.out.println(student);
}
}
[/Users/ijeong-in/Documents]> javac Hello.java
[/Users/ijeong-in/Documents]> java Hello
Student@6504e3b2
프리미티브 타입은 기본값이 있어서 선언 할 때 초기화를 하지 않더라도 기본값을 사용하지만
레퍼런스 타입은 별도의 기본값이 없기 때문에 그냥 선언하면 'null'이 된다.(참고로 프리미티브 타입은 'null'이 될 수 없다.)
레퍼런스 타입 변수가 'null'이라는 것은 해당 변수가 아무것도 참조하고 있지 않다는 의미이다.
public class Hello {
Student student;
int i;
}
public class Test {
public static void main(String args[]) {
Hello hello = new Hello();
System.out.println(hello.student);
System.out.println(hello.i);
}
}
[/Users/ijeong-in/Documents]> javac Test.java
[/Users/ijeong-in/Documents]> java Test
null
0
리터럴
리터럴 : 프로그램에서 사용하는 모든 숫자, 값, 논리 값이며 '데이터' 그 자체를 의미한다.
리터럴은 변수에 대입할 수 있으며 변하지 않는다.
int num = 10; //변수 num을 리터럴 10으로 초기화
모든 리터럴은 메소드 영역의 런타임 상수 풀(runtime constant pool)에 저장 된다.
일반적인 클래스는 변하는 성질을 가지므로 리터럴을 대입할 수 없지만,
Java에서 제공되는 불변 클래스인 String 등은 객체의 데이터가 변하지 않으므로 리터럴을 대입할 수 있다.
상수 : '변하지 않는다'는 속성은 리터럴과 같으나 상수는 변하지 않는 '데이터'가 아닌 '참조 값'이다.
- Java에서는 상수를 위해 변수 생성에 final 키워드를 사용한다.
int final num = 10; //상수 num
변수 선언 및 초기화
변수는 _선언_이 필요하다.
선언 방법 :
자료형 변수이름;
(ex) int age;
package variable;
public class VariableTest {
public static void main(String[] args) {
int age, count; //선언
age = 30; //초기화
int age_2 = 20; //선언과 동시에 초기화
System.out.println(age);
System.out.println(age_2);
}
}
‘=’표시는 같다는 의미가 아니고 대입의 의미이다. (l-value=r-value : r-value를 l-value에 대입)
그렇기 때문에 언제든지 변수는 바뀔 수 있다.
선언은 여러 변수를 한번에 할 수 도 있고
int age, count;
선언과 동시에 초기화(대입)할 수도 있다.
int age_2 = 20;
선언은 해당 변수형의 크기 만큼 메모리를 사용한다.
(ex int age; -> 4byte 메모리 점유)
변수이름은…
- 숫자로 시작할 수 없다.
- 특수문자는 ‘_’와 ‘$’만 가능하다.
- 예약어는 쓸 수 없다. (ex : while, for, int, etc…)
- 쓰임에 맞게 명명해야 가독성이 좋다. (줄여서 약어로 쓰지 말자.)
되도록 소문자로 시작하고 단어가 바뀔때 대문자를 사용한다. (camel notation)
변수의 스코프와 라이프 타임
변수의 스코프 : 특정 변수를 사용할 수 있는 범위이자 변수가 선언된 블럭이다.
- 블럭 == "{ }"
- 동일한 스코프 내에서 동일한 이름의 변수를 사용할 수 없다.
public class Student {
public int id = 1;
public String global = "GLOBAL";
// id, global 변수의 스코프는 Student 클래스이다.
// 이렇게 클래스에서 어디서나 사용할 수 있는 변수를 '전역 변수'라고 한다.
// (static 메서드에서는 사용할 수 없다.)
public static String stat = "STATIC";
// 전역 변수 중에서 static 키워드가 달린 변수를 '정적 변수'라고 한다.
// 정적 변수는 static 메서드에서도 사용할 수 있으며 외부에서 객체 생성 없이 사용할 수 있다는 특징이 있다.
public void getLocal() {
String local = "LOCAL";
// local 변수의 스코프는 getLocal() 메서드이다.
// local 변수는 getLocal() 메서드 내에서만 사용할 수 있다.
// 이렇게 특정 메소드나 생성자, 초기화 블럭, 반복문 내부에서만 사용할 수 있는 변수를 '지역 변수'라고 한다.
}
public static void getStat() {
System.out.println(stat);
//System.out.println(global);
//static 메서드에서 전역 변수는 사용할 수 없지만 정적 변수는 사용할 수 있다.
}
for (int i = 0; i < 10; i++) {
int forNum = i; //이 반복문 내에서만 사용할 수 있다.
}
{
int block = 100; //이 블럭 내에서만 사용할 수 있다.
}
//global = local; //컴파일 에러
//id = forNum; //컴파일 에러
//id = block; //컴파일 에러
}
public class Test {
public static void main(String args[]) {
System.out.println(Student.stat); //클래스를 생성하지 않아도 정적 변수는 참조할 수 있다.
Student student = new Student(); //전역 변수는 클래스를 생성하면 참조할 수 있다.
System.out.println(student.id);
System.out.println(student.global);
//System.out.println(student.local); //지역 변수는 참조할 수 없다.
//System.out.println(student.forNum);
//System.out.println(student.block);
}
}
변수 라이프 타임 : 변수가 메모리에서 살아있는 기간이다.
- 전역 변수의 라이프 타임 : 객체가 생성되고부터 메모리에서 사라질 때 까지
- 정적 변수의 라이프 타임 : 프로그램 시작부터 종료까지
- 지역 변수의 라이프 타임 : 블록이 실행된 후 부터 종료될 때 까지
타입 변환, 캐스팅 그리고 프로모션
타입 변환 : 형 변환이라고도 하며 변수의 타입을 변환하는 것이다. 다만 형 변환의 궁극적인 목적은 변수 타입의 변환이 아닌 OOP의 다형성에 활용하기 위함이다. 형 변환의 방향에 따라 캐스팅과 프로모션으로 나뉘어진다.
프로모션 : 작은 수 -> 큰 수, 덜 정밀한 수 -> 더 정밀한 수로 대입되는 경우이다.
- 특별한 명시를 하지 않아도 JVM이 알아서 변환해줄 수 있다.(묵시적 형 변환)
- 업캐스팅이라고도 한다.
캐스팅 : 큰 수 -> 작은 수, 더 정밀한 수 -> 덜 정밀한 수로 대입되는 경우이다.
변환 될 자료 형을 명시해야한다.(명시적 형 변환)
자료 손실이 발생할 수 있다.
다운캐스팅이라고도 한다.
package variable;
public class ImplicitConversion {
public static void main(String[] args) {
byte bNum = 10;
int iNum = bNum; //더 큰수로 묵시적 형 변환(byte -> int)
System.out.println(bNum);
System.out.println(iNum);
int iNum2 = 20;
float fNum = iNum2; //더 정밀한 수로 형 변환(int -> float)
System.out.println(fNum);
double dNum;
dNum = fNum + iNum; //더 정밀한 수로 형 변환 2회 i->f->d
System.out.println(dNum);
}
}
package variable;
public class ExplicitConversion {
public static void main(String[] args) {
int i = 1000;
//byte bNum = i;
byte bNum = (byte)i; //명시적 형 변환(int -> byte)
System.out.println(Integer.toBinaryString(i)); //1111101000
System.out.println(bNum); //-24 (1110 1000), 왼쪽 2bit 데이터 유실
double dNum = 1.2;
float fNum = 0.9F;
//int iNum1 = dNum + fNum;
int iNum1 = (int)(dNum + fNum);
int iNum2 = (int)dNum + (int)fNum;
System.out.println(iNum1); //데이터 유실 2.1 -> 2
System.out.println(iNum2); //데이터 유실 1.2+0.9 -> 1+0
}
}
1차 및 2차 배열 선언
배열(Array) : 동일한 자료형의 순차적 자료 구조.
ex) 학생 100명에 대한 학번 변수
배열 선언
int[] arr = new int[10]; //int 10개 = 40byte length=10, 0~9
int arr[] = new int[10];
배열은 fixed length이다.
만약 배열의 길이를 늘리고 싶다면, 더 긴 배열을 선언한 뒤 값을 복사해야 한다.배열은 연속적이어야 한다. (중간에 비어있으면 안된다.)
데이터가 들어가거나 빠질때 추가적인 작업이 필요하다.
배열을 사용하는 가장 큰 이유 : 인덱스 연산자 'Array[ ]'
arr[4] //arr배열의 다섯번째 값 추출, 추출이 편하고 속도가 빠름
package array;
public class ArrayTest {
public static void main(String[] args) {
int[] arr = new int[10]; //기본자료형 Array
int[] arr2 = new int[] {1,2,3}; //선언과 동시에 초기화 가능
int[] arr3 = {1,2,3}; //위와 동일
int total = 0;
for (int i=0;i<arr.length;i++) {
System.out.println(arr[i]); //0으로 10개가 초기화되어 있음
}
for (int i=0,num=1;i<arr.length;i++,num++) { //배열 arr의 모든 요소를 1씩 증가하도록 변경
arr[i]=num;
}
for (int i=0;i<arr.length;i++) {
System.out.println(arr[i]);
}
for (int i=0;i<arr.length;i++) { //배열 요소 합 구하기
total += arr[i];
}
System.out.println(total);
double[] dArr = new double[5];
int count = 0;
dArr[0] = 1.1; count++;
dArr[1] = 2.1; count++;
dArr[2] = 3.1; count++;
double mtotal = 1;
for (int i=0;i<count;i++) { //count를 통해 직접 초기화 한 값만 곱
mtotal *= dArr[i];
System.out.println(dArr[i]);
}
System.out.println(mtotal);
}
}
2차원 배열
int[][] arr = new int [2][3]; //2행x3열 = 6개 요소
package array;
public class TwoDimension {
public static void main(String[] args) {
int[][] arr = new int[2][3];
System.out.println(arr.length); //2차원 배열에서 length는 행의 개수
System.out.println(arr[0].length); //0번째 행의 길이
System.out.println(arr[1].length);
//행을 기준으로 열을 돌린다.(2중 for문)
for (int i=0; i<arr.length; i++) { //행 for문
for (int j=0; j<arr[i].length; j++) { //열 for문
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
}
타입 추론, var
지역 변수 타입 추론 Local variable type inference (java 10 이상) : 지역변수에 한하여 대입되는 값을 보고 컴파일러가 변수형을 추론하는 기능.
- 지역 변수에 한정된다.
- 선언과 동시에 초기화가 필요하다.
package variable;
public class BooleanTest {
public static void main(String[] args) {
var iVar = 10;
var sVar = "String";
System.out.println(iVar);
System.out.println(cVar);
}
}