문서의 선택한 두 판 사이의 차이를 보여줍니다.
양쪽 이전 판 이전 판 다음 판 | 이전 판 | ||
wiki:java:java-lecture:2week [2021/01/12 09:32] iyyeo |
wiki:java:java-lecture:2week [2023/01/13 18:44] (현재) |
||
---|---|---|---|
줄 5: | 줄 5: | ||
{{: | {{: | ||
* 우리가 주로 사용하는 값의 종류는 크게 문자와 숫자로 나눌 수 있으며 여기서 숫자는 다시 정수와 실수로 나뉜다.\\ | * 우리가 주로 사용하는 값의 종류는 크게 문자와 숫자로 나눌 수 있으며 여기서 숫자는 다시 정수와 실수로 나뉜다.\\ | ||
+ | |||
* 기본형은 모두 8가지의 타입(자료형)이 있으며, 크게 논리형, 문자형, 정수형, 실수형으로 구분된다.\\ | * 기본형은 모두 8가지의 타입(자료형)이 있으며, 크게 논리형, 문자형, 정수형, 실수형으로 구분된다.\\ | ||
\\ | \\ | ||
==== 타입 종류 ==== | ==== 타입 종류 ==== | ||
{{: | {{: | ||
- | * 정수형은 가장 많이 사용되기에 타입이 4가지나 제공된다. | + | * 정수형은 가장 많이 사용되기에 타입이 4가지나 제공된다.\\ |
* 각 타입별로 범위가 다르기에 범위에 맞는 값을 사용하면 된다.\\ | * 각 타입별로 범위가 다르기에 범위에 맞는 값을 사용하면 된다.\\ | ||
\\ | \\ | ||
==== 타입 범위 ==== | ==== 타입 범위 ==== | ||
{{: | {{: | ||
- | * boolean은 true와 false 두 값만 표현하면 되기에 1바이트면 충분하다. | + | * boolean은 true와 false 두 값만 표현하면 되기에 1바이트면 충분하다.\\ |
- | * 기본 값: '' | + | * 기본 값 : '' |
- | * char는 자바에서 유니코드(2 byte문자 체계)를 사용하기에 2byte | + | * char는 자바에서 유니코드(2 byte문자 체계)를 사용하기에 2byte\\ |
- | * 기본 값: '' | + | * 기본 값 : '' |
- | * byte는 크기가 1byte이므로 byte. | + | * byte는 크기가 1byte이므로 byte.\\ |
- | * 기본 값: '' | + | * 기본 값 : '' |
- | * int(4 byte)를 기준으로 짧게는 (2 byte) 길게는 (8 byte)를 취사선택한다. | + | * int(4 byte)를 기준으로 짧게는 (2 byte) 길게는 (8 byte)를 취사선택한다.\\ |
- | * 기본 값: '' | + | * 기본 값 : '' |
- | * float은 실수값을 부동소수점(floating-point)방식으로 저장하기 때문에 float | + | * float은 실수값을 부동소수점(floating-point)방식으로 저장하기 때문에 float\\ |
- | * 기본 값: '' | + | * 기본 값 : '' |
- | * double은 float보다 두 배의 크기(8byte)를 갖기 때문에 double | + | * double은 float보다 두 배의 크기(8byte)를 갖기 때문에 double\\ |
- | * 기본 값: '' | + | * 기본 값 : '' |
\\ | \\ | ||
==== 실수형의 정밀도 ==== | ==== 실수형의 정밀도 ==== | ||
줄 45: | 줄 47: | ||
* 리터럴은 데이터 그 자체를 의미한다.\\ | * 리터럴은 데이터 그 자체를 의미한다.\\ | ||
- | * 아래 '' | + | * 아래 '' |
{{: | {{: | ||
줄 59: | 줄 61: | ||
* 💬Ex: '' | * 💬Ex: '' | ||
+ | \\ | ||
===== 변수 선언 및 초기화하는 방법 ===== | ===== 변수 선언 및 초기화하는 방법 ===== | ||
+ | ==== 변수 선언 ==== | ||
+ | 변수를 사용하기위해서는 우선 변수를 선언해야 하며 아래 그림과 같이 선언합니다.\\ | ||
+ | |||
+ | {{: | ||
+ | |||
+ | * **변수 타입** : 변수에 저장될 값이 어떤 타입(type)인지 지정하는 것.\\ | ||
+ | * **변수 이름** : 변수에 붙힌 이름. | ||
+ | |||
+ | 이렇게 변수를 선언하면, | ||
+ | \\ | ||
+ | ==== 변수 초기화 ==== | ||
+ | 💡 변수를 사용하기 전 처음으로 값을 저장하는 것 | ||
+ | |||
+ | 변수를 선언하면 메모리에 변수의 저장공간이 확보되어있지만, | ||
+ | |||
+ | 그렇기에 '' | ||
+ | |||
+ | {{: | ||
+ | {{: | ||
+ | |||
+ | * 변수에 값을 저장할 때는 대입 연산자 '' | ||
+ | |||
+ | * 즉, 대입연산자의 우측의 있는 값을 좌측에 있는 변수에 저장한다.\\ | ||
+ | |||
+ | * 변수의 종류에 따라 변수의 초기화를 생략할 수 있는 경우도 있지만, 변수는 사용되기 전에 적절한 값으로 초기화 하는 것이 좋다.\\ | ||
+ | \\ | ||
+ | **💬지역변수는 사용하기 전 반드시 초기화 해야 한다.**\\ | ||
+ | \\ | ||
+ | ==== 그밖의 초기화의 종류 ==== | ||
+ | 지역변수는 변수의 초기화로 충분하지만, | ||
+ | |||
+ | === 1. 명시적 초기화(explicit initialization) === | ||
+ | : 변수 선언과 동시에 초기화 하는 것을 명시적 초기화라 하는데, 위에서 소개한 변수의 초기화와 동일하며, | ||
+ | |||
+ | === 2. 초기화 블럭(initialization block) === | ||
+ | : 초기화 블럭은 클래스 초기화 블럭과 인스턴스 초기화 블럭으로 나뉜다.\\ | ||
+ | |||
+ | class ExplicitInitialization { | ||
+ | static { | ||
+ | / | ||
+ | } | ||
+ | { | ||
+ | / | ||
+ | } | ||
+ | } | ||
+ | |||
+ | * '' | ||
+ | |||
+ | * '' | ||
+ | |||
+ | === 3. 생성자(constructor) === | ||
+ | : 생성자는 말 그대로 인스턴스 생성시에 생성자 함수 안에서 명시적 초기화가 이뤄진다. | ||
+ | |||
===== 변수의 스코프와 라이프타임 ===== | ===== 변수의 스코프와 라이프타임 ===== | ||
+ | 스코프는 한글로 풀어보자면 범위이다. 즉, 변수의 스코프는 변수의 범위라는건데 이 범위는 키워드와 선언된 블럭위치에 따라서 달라진다.\\ | ||
+ | |||
+ | ==== 선언위치에 따른 변수의 종류 ==== | ||
+ | class A { | ||
+ | int instanceValue; | ||
+ | static int classValue;// | ||
+ | |||
+ | void method(){ | ||
+ | int localValue = 0; //지역 변수 | ||
+ | } | ||
+ | } | ||
+ | \\ | ||
+ | 클래스 내부에 선언되는 변수를 멤버변수라 한다. 여기서 static키워드가 붙은 변수를 클래스 변수, static 키워드가 없는 변수를 인스턴스 변수라 한다. 그리고 메서드 내부에 있는 localValue는 지역변수이다. 이 셋 모두의 범위와 생성시기는 다르다.\\ | ||
+ | \\ | ||
+ | === 1. 변수의 종류와 특징 === | ||
+ | {{: | ||
+ | |||
+ | **1) 인스턴스 변수(instance variable)**\\ | ||
+ | * 클래스 영역에 선언되며, | ||
+ | |||
+ | * 인스턴스 별로 별도의 저장공간을 확보하기에 인스턴스별 다른 값을 가질 수 있다.\\ | ||
+ | |||
+ | * Ex: 아이스크림이라는 클래스의 돼지바 라는 인스턴스는 1000원이라는 가격과 쿠키라는 속성을 가진다.\\ | ||
+ | \\ | ||
+ | |||
+ | **2) 클래스 변수(class variable)**\\ | ||
+ | * 멤버변수에 '' | ||
+ | |||
+ | * 클래스 변수는 인스턴스를 생성하지 않고 클래스가 메모리에 올라갔을때 선언되기 때문에 인스턴스에서는 언제든 바로 접근해서 사용할 수 있다.\\ | ||
+ | |||
+ | * 그렇기에 어디서나 접근 할 수 있는 전역변수(global variable)의 성격을 가진다.\\ | ||
+ | |||
+ | class LottoTicket { | ||
+ | public static final LOTTO_PRICE = 1000; | ||
+ | ... | ||
+ | } | ||
+ | public static void main(String[] args) { | ||
+ | // | ||
+ | System.out.println(" | ||
+ | } | ||
+ | \\ | ||
+ | |||
+ | **3) 지역 변수(local variable)**\\ | ||
+ | * 메소드 내에 선언되어 메소드 내에서만 사용 가능하며 메소드 종료와 함께 소멸된다.\\ | ||
+ | |||
+ | * for문이나 while문같은 반복문도 동일하게 블럭내에서 선언된 지역변수는, | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | for (int i = 0; i < 10; i++) { | ||
+ | System.out.println(" | ||
+ | } | ||
+ | System.out.println(" | ||
+ | } | ||
+ | \\ | ||
+ | \\ | ||
+ | ==== 초기화 시기와 순서(라이프타임) ==== | ||
+ | === 1. 초기화 시점 === | ||
+ | {{: | ||
+ | |||
+ | ⇒ 프로그램 실행도중 클래스에 대한 정보가 요구될 때 클래스는 메모리에 로딩된다.\\ | ||
+ | (만약 이미 메모리에 로딩되어 있다면 또다시 로딩하지는 않는다.)\\ | ||
+ | |||
+ | === 2. 초기화 순서 === | ||
+ | {{: | ||
+ | |||
+ | === 3. 예제 === | ||
+ | class InitTest { | ||
+ | static int classValue = 1; | ||
+ | int instanceValue = 1; | ||
+ | | ||
+ | static { | ||
+ | classValue = 2; | ||
+ | } | ||
+ | InitTest() { | ||
+ | instanceValue = 3; | ||
+ | } | ||
+ | } | ||
+ | \\ | ||
+ | {{: | ||
+ | |||
+ | * 클래스변수 초기화(1~3): | ||
+ | |||
+ | * 인스턴스변수 초기화(4~7): | ||
+ | |||
+ | * __**클래스 변수는 항상 인스턴스 변수보다 먼저 생성및 초기화된다.**__ | ||
===== 타입 변환, 캐스팅 그리고 타입 프로모션 ===== | ===== 타입 변환, 캐스팅 그리고 타입 프로모션 ===== | ||
+ | ==== 타입 변환 ==== | ||
+ | 💡 변수 또는 상수의 타입을 다른 타입으로 변환하는 것 | ||
+ | | ||
+ | 프로그램을 작성하다보면 서로 다른 타입간의 연산을 수행해야 하는 경우가 있다. 이럴 때 연산을 수행하기 전 서로의 타입을 일치시켜야하는데, | ||
+ | \\ | ||
+ | ==== 형변환 방법 ==== | ||
+ | 💡 (type)operand | ||
+ | |||
+ | |||
+ | * 변환할 변수나 리터럴 앞에 타입을 괄호와 함께 붙혀주기만 하면 된다. 이 때 형변환 연산자는 그저 피연산자의 값을 읽어서 지정된 타입으로 형변환하고 그 결과를 반환할 뿐이기에 기존의 변수나 리터럴이 변화되지는 않는다.\\ | ||
+ | \\ | ||
+ | double value = 123.456; | ||
+ | int score = (int)value; | ||
+ | System.out.println(value == 123.456); //true | ||
+ | |||
+ | * 기본형(primitive type) 변수는 '' | ||
+ | * 하지만, 타입간에는 각각이 가지는 범위(크기)가 다르기 때문에 형변환을 통해 크기의 차이만큼 값이 잘려나감으로써 값 손실(loss of data)이 발생할 수 있다.\\ | ||
+ | \\ | ||
+ | ==== 자동 형변환 ==== | ||
+ | * 경우에 따라 형변환을 생략할 수 있다. 그래도 컴파일러가 생략된 형변환을 자동으로 추가한다.\\ | ||
+ | * 하지만, 저장될 변수 타입의 범위가 더 작은 경우 에러가 발생하는데 이는 더 작은 값으로 할당되며 값 손실이 발생할 수 있기 때문이며 이를 이미 알고 명시적으로 형변환을 작성해주면 에러를 발생시키지 않는다.\\ | ||
+ | |||
+ | byte b = 10000; //에러 발생. byte의 범위는 -128~127이다. | ||
+ | byte c = (byte)10000; | ||
+ | |||
+ | \\ | ||
+ | ==== 자동 형변환 규칙 ==== | ||
+ | 💡 기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환한다. | ||
+ | |||
+ | * 표현범위가 좁은 타입에서 넓은 타입으로 형변환 할 때 값 손실이 없기에 두 타입 중 표현범위가 더 넓은 쪽으로 형변환이 된다. | ||
+ | |||
+ | {{: | ||
+ | 기본형의 자동 형변환의 방향 | ||
===== 1차 및 2차 배열 선언하기 ===== | ===== 1차 및 2차 배열 선언하기 ===== | ||
+ | ==== 배열의 선언과 생성 ==== | ||
+ | **1. 배열의 선언** | ||
+ | {{: | ||
+ | |||
+ | * 배열의 선언은 타입 뒤 혹은 변수이름뒤에 대괄호('' | ||
+ | |||
+ | **2. 배열의 생성** | ||
+ | | ||
+ | 타입[] 변수이름 = new 타입[길이]; | ||
+ | |||
+ | * '' | ||
+ | * 💬 이때 배열의 길이는 최초 생성시 선언한 길이에서 정적이므로 길이의 변경을 원할 때는 새로운 배열을 생성해줘야 한다.\\ | ||
+ | \\ | ||
+ | ==== 1차원 배열의 선언 & 2차원 배열의 선언 ==== | ||
+ | * 배열은 1차원 뿐 아니라 다차원 배열도 선언해서 사용할 수 있다. | ||
+ | * 다차원의 차원간 선언방법의 차이는 대괄호('' | ||
+ | |||
+ | ** 1. 1차원 배열의 선언 ** | ||
+ | int[] oneDimensionalArray = new int[5]{1, 2, 3, 4, 5}; | ||
+ | |||
+ | {{: | ||
+ | |||
+ | 메모리에 올라간 1차원 배열\\ | ||
+ | \\ | ||
+ | ** 2. 2차원 배열의 선언 ** | ||
+ | int[][] twoDimensionalArray = new int[2][2]{{1, | ||
+ | |||
+ | {{: | ||
+ | |||
+ | 메모리에 올라간 2차원 배열\\ | ||
+ | * 2차원 배열은 각각의 대괄호를 행/열로 보면 좀 더 알기 쉽다 예를들어 '' | ||
===== 타입 추론, var ===== | ===== 타입 추론, var ===== | ||
+ | ==== 타입 추론 ==== | ||
+ | * 자바 컴파일러에서 타입을 추론하는 것을 '' | ||
+ | * 이 타입추론을 하기 위해 메소드 호출과 호출할 때 사용하는 인수(혹은 인수들)을 결정하기위한 선언부를 살펴본다. | ||
+ | * 추론 알고리즘(inference algorithm)을 통해 인수 타입을 결정하고 가능하다면 결과가 할당되는 타입(인수타입)이나 반환 타입도 추론한다. | ||
+ | static <T> T pick(T a1, T a2) { return a2; } | ||
+ | public static void main(String[] args) { | ||
+ | Serializable d = pick(" | ||
+ | } | ||
+ | |||
+ | * 추론 알고리즘은 모든 인자와 어울리는 선에서 가장 구체적인 타입을 찾는데, 위 코드를 보면 pick 메소드의 매개변수는 T이고 메소드의 매개변수 a1, a2 둘 다 T 타입이다.\\ | ||
+ | * 하지만 pick 메소드를 호출하면서 첫 번째 인자로 String을 주고 두 번째 인자로 ArrayList를 주었다. 이런 경우 모든 인자에 어울리는 선(공통 부모)란 Serializable으로 String과 ArrayList 둘 다 Serializable을 구현하고 있기 때문이다. | ||
+ | |||
+ | ==== 타입추론과 Generic Methods ==== | ||
+ | * 타입추론덕분에 generic 메소드를 사용할 때 보통의 메소드처럼 특정 타입을 명시하지 않은 채로 호출할 수 있다. \\ | ||
+ | |||
+ | public class BoxDemo { | ||
+ | public static <U> void addBox(U u, java.util.List< | ||
+ | Box< | ||
+ | box.set(u); | ||
+ | boxes.add(box); | ||
+ | } | ||
+ | } | ||
+ | public static <U> void outputBoxes(java.util.List< | ||
+ | int counter = 0; | ||
+ | for (Box< | ||
+ | U boxContents = box.get(); | ||
+ | System.out.println(" | ||
+ | | ||
+ | counter++; | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | public static void main(String[] args) { | ||
+ | java.util.ArrayList< | ||
+ | new java.util.ArrayList<> | ||
+ | BoxDemo.< | ||
+ | BoxDemo.addBox(Integer.valueOf(20), | ||
+ | BoxDemo.addBox(Integer.valueOf(30), | ||
+ | BoxDemo.outputBoxes(listOfIntegerBoxes); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | \\ | ||
+ | '' | ||
+ | '' | ||
+ | \\ | ||
+ | ==== 타입추론과 Generic 클래스의 인스턴스 ==== | ||
+ | * Java 컴파일러가 컨텍스트로부터 타입추론이 가능하다면 Generic 클래스의 생성자를 호출하기 위해 필요한 type arguments를 비어있는 type witness(<>, | ||
+ | |||
+ | List< | ||
+ | List< | ||
+ | |||
+ | \\ | ||
+ | ==== 타입추론과 Generic 생성자 ==== | ||
+ | * 클래스가 Generic/ | ||
+ | |||
+ | class MyClass< | ||
+ | <T> MyClass(T t) { | ||
+ | // ... | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | public static void main(String[] args) { | ||
+ | MyClass< | ||
+ | } | ||
+ | |||
+ | * MyClass의 type 매개변수 X에는 Integer가 들어가지만 생성자의 type 매개변수 T에는 String이 들어간다. \\ | ||
+ | \\ | ||
+ | |||
+ | '' | ||
+ | '' | ||
+ | |||
+ | MyClass< | ||
+ | |||
+ | \\ | ||
+ | ==== Target Types ==== | ||
+ | * Java 컴파일러는 generic method invocation의 type argument를 추론하기 위해 target typing의 이점을 이용한다. | ||
+ | * 표현식의 target type이란 표현식이 나타낸 위치에 의존하여(컨텍스트 의존) Java 컴파일러가 기대하는 데이터 타입이다.\\ | ||
+ | |||
+ | static <T> List< | ||
+ | List< | ||
+ | |||
+ | * 위 코드는 Collection API의 emptyList 함수를 이용해 List< | ||
+ | * 이런 데이터 타입을 Target Type이라 하는데, emptyList 함수가 List< | ||
+ | * 물론, type witness를 사용해 명시적 선언을 해줄 수도 있지만 위 코드에서는 불필요하다.\\ | ||
+ | \\ | ||
+ | List< | ||
+ | |||
+ | |||
+ | * 하지만, Type Witness가 필요한 경우도 있다. | ||
+ | \\ | ||
+ | |||
+ | void processStringList(List< | ||
+ | //process stringList | ||
+ | } | ||
+ | public static void main(String[] args) { | ||
+ | processStringList(Colections.emptyList()); | ||
+ | } | ||
+ | |||
+ | * 위 코드에서 메소드 호출은 정상적으로 동작할까? | ||
+ | * Java SE 7 컴파일러에서는 컴파일 되지 않고 에러가 발생하며 아래와 같은 에러 메세지가 출력된다. | ||
+ | |||
+ | List< | ||
+ | |||
+ | * 이런 에러가 발생하는 이유는 컴파일러는 type argument T를 위한 value를 필요한데, | ||
+ | * 그 결과 Collections.emptyList()는 List< | ||
+ | * 그렇기에 Java SE 7에서는 type witness를 명시해줘야 한다. | ||
+ | |||
+ | processStringList(Colections.< | ||
+ | |||
+ | * 하지만, Java SE 8 부터는 위와 같은 경우에도 type witness를 명시해주지 않아도 Target type을 결정할 때 메소드의 argument도 살피도록 확장되었기 때문에 에러가 발생하지 않는다. | ||
+ | * 그렇기 때문에 Java SE 8이상에서는 위의 type witness가 없는 메소드 호출도 정상적으로 동작할 것이다.\\ | ||
+ | \\ | ||
+ | ==== var ==== | ||
+ | * Java 10부터 추가된 특징중 하나인 Local Variable Type Inference은 로컬 변수 선언을 var를 이용하여 기존의 엄격한 타입 선언방식에서 컴파일러에게 타입추론 책임을 위임할 수 있게 되었다. | ||
+ | |||
+ | var list = new ArrayList< | ||
+ | var stream = list.stream();// | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ==== Local Variable Type Inference 사용 조건 ==== | ||
+ | * 초기화된 로컬 변수 선언시 | ||
+ | * 반복문에서 지역변수 선언 시(enhanced for loop포함) | ||
+ | |||
+ | ==== var 활용 ==== | ||
+ | |||
+ | **1. 지역변수 선언** | ||
+ | | ||
+ | var numbers = Arrays.asList(1, | ||
+ | | ||
+ | for (var i = 0; i < numbers.size(); | ||
+ | System.out.println(" | ||
+ | } | ||
+ | \\ | ||
+ | |||
+ | **2. forEach** | ||
+ | | ||
+ | var numbers = Arrays.asList(1, | ||
+ | | ||
+ | for (var number : numbers) { | ||
+ | System.out.println(number); | ||
+ | } | ||
+ | |||
+ | |||
+ | * 기존에는 Object타입으로 받아서 형변환을 하거나 IDE가 아닌 개발자가 직접 타입추론해 명시적 타입선언을 해줬는데 var를 사용하여 훨씬 편하게 타입선언이 가능해진다.\\ | ||
+ | \\ | ||
+ | **3. Lambda (Java 11)** | ||
+ | |||
+ | IntBinaryOperator plus10 = (@NonNull var one, @NonNull var two) -> one + two + 10; | ||
+ | |||
+ | * Java 11부터는 람다 인자에도 var사용이 가능해졌는데, | ||
+ | * '' | ||
===== Ref ===== | ===== Ref ===== | ||
- | https:// | + | [[https:// |
- | https:// | + | |
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
{{tag> | {{tag> |