Android03
챕터 3 코틀린 사용을 위한 기본 문법
1. 코딩 준비하기
1.1 새 프로젝트 생성하기
1.2 로그의 활용
- Log.d(“태그”, “출력 메시지”);
- d는 debug를 의미하며 첫번째 인자에는 검색 용도로 사용되는 태그를 입력하고 두번째 인자에는 실제 출력할 메시지를 입력한다.
- 안드로이드에서 기본으로 제공하는 클래스나 함수를 사용하기 위해서는 import를 거쳐야 한다.
- 로그 : 코딩을 할 때 코드의 흐름을 파악하기 위해 앱 외부에 출력하는 정보.
- 로그캣 : 출력되는 로그를 모아서 보는 도구.
- 로그 사용법
- Log.v() : verbose 상세한 로그 내용을 출력
- Log.d() : debug 개발에 필요한 내용을 출력
- Log.i() : information 정보성의 일반적인 메시지 전달
- Log.w() : warning 에러는 아니지만 경고성 메시지 전달
- Log.e() : error 에러 메시지 출력
2. 변수와 상수
2.1 변수 ver
- 변수란 값을 임시로 메모리에 저장하고 그 저장 공간에 이름을 부여한 것.
- 변수는 변수의 이름 앞에 var를 입력해서 선언할 수 있다.
- 변수 선언 방법 2가지
- 변수 선언과 동시에 값 넣기
- var 변수명(이름) = 값
- 값으로 초기화하지 않고 선언만 하고 사용하기
- var 변수명: 타입
- 변수명 = 값
- 변수 선언과 동시에 값 넣기
- 변수 선언 방법 2가지
2.2 데이터 타입
- 숫자형
- Double : 64비트 실수 : 소수점이 있는 값을 저장할 때 사용
- Float : 32비트 실수 : double과 동일한 용도지만 더 작은 범위의 숫자
- Long : 64비트 정수 : int보다 큰 범위의 정수
- Int : 32비트 정수 : 소수점이 없는 정수
- Short : 16비트 정수 : int보다 작은 범위의 정수
- Byte : 8비트 정수 : int보다 작은 범위의 정수
- 문자형
- Char : 1개의 문자
- String : 여러개의 문자
- 불린형
- Boolean :true, false
2.3 상수 val
- 변수의 다른 선언 방법으로 상수가 있다.
- 상수는 변수와 다르게 val로 선언하며, 한 번 입력된 값은 변경할 수 없다.
- 주로 기준이 되는 변하지 않는 값을 미리 입력해 둘 때 사용한다.
- val 상수 이름 = 값
2.4 네이밍 컨벤션
클래스명
- 대체로 캐멀 케이스를 사용한다.
- 클래스명은 단어의 첫글자는 대문자로, 나머지는 소문자로 표기한다. 그리고 새로운 단어가 나타나면 첫글자를 대문자로 표기한다.
함수명과 변수명
- 캐멀 케이스를 따르며 첫글자만 소문자로, 이후 새로운 단어의 첫글자는 대문자로 표기한다.
상수명
- 모두 대문자.
들여쓰기
- 새로운 코드 블록이 시작되면 스페이스바 또는 탭키로 동일한 간격만큼 들여쓰기 한다.
3 조건문
3.1 조건문 if
- 특정 코드를 조건식의 결괏값이 참인지 거짓인지에 따라 실행하거나 실행하지 않을 때 조건문을 사용한다.
- if와 when 두가지 형태의 조건문이 있다.
변수에 직접 if문 사용하기
-
if문의 조건식 결과를 변수에 대입할 수 있다.
- var a = 5
-
var b = 3
- var bigger = if (a > b) a else b
if문의 마지막 값을 반환값으로 사용하기
- if문의 코드 영역이 여러줄일 경우에도 마지막 줄을 변숫값으로 사용할 수 있다.
- var a = 5
- var b = 3
- var bigger = if (a > b) {
- a = a - b
- a // 마지막 줄의 a값이 변수 bigger에 저장된다.}
3.2 조건문 when
- 일반적인 형태의 when
when (파라미터) { // 괄호 안에 특정 변수를 할당하는 것을 파라미터라 한다.
비교값 -> {
// 변숫값이 비교값과 같다면 이 영역이 실행된다.
}
}
- 콤마로 구분
- 특정 값을 비교하는데 결과 처리가 동일하다면 콤마로 구분하여 한 번에 비교할 수 있다.
when (파라미터) { // 괄호 안에 특정 변수를 할당하는 것을 파라미터라 한다. 비교값, 비교값 -> { // 변숫값이 비교값과 같다면 이 영역이 실행된다. } }
- 특정 값을 비교하는데 결과 처리가 동일하다면 콤마로 구분하여 한 번에 비교할 수 있다.
- 범위값을 비교하기
when (파라미터) { // 괄호 안에 특정 변수를 할당하는 것을 파라미터라 한다.
비교값..비교값 -> {
// 변숫값이 비교값과 같다면 이 영역이 실행된다.
}
}
- 파라미터 없는 when
- When 다음의 괄호를 생략하고 if 문처럼 사용 가능
when { // 괄호 안에 특정 변수를 할당하는 것을 파라미터라 한다.
변수값 == x {
// 변숫값이 비교값과 같다면 이 영역이 실행된다.
}
변수값 > x {
// 변숫값이 비교값보다 크다면 이 영역이 실행된다.
}
else -> {
}
}
3.3 if문과 when문은 언제 사용할까?
- 범위가 넓고 값을 특정할 수 없는 경우에는 If문을 사용한다.
- 범위가 제한되고 값도 특정할 수 있다면 when을 사용한다.
4. 배열과 컬렉션
- 여러개의 값을 하나의 변수에 저장할 수 있도록 배열과 컬렉션이라는 데이터 타입을 제공한다.
- 배열은 개수 특정.
- 콜렉션은 개수 특정 없음.
4.1 배열
- 값을 담기 전에 먼저 배열 공간의 개수를 할당하거나 초기화 시에 데이터를 저장해두면 데이터의 개수만큼 배열의 크기가 결정된다.
- var 변수 = Array(개수)
- 인덱스는 0부터 시작한다.
문자 배열에 빈 공간 할당하기
- var stringArray = Array(10, {item->””})
값으로 배열 공간 할당하기
- var dayArray = arrayOf(“MON”, “TUE”, “WED”, “THU”, “FRI”, “SAT”, “SUN”)
배열에 값 입력하기
- 배열명[인덱스] = 값
- set함수 사용
- 배열명.set(인덱스, 값)
배열에 있는 값 꺼내기
- 배열명[인덱스]
- 배열명.get(인덱스)
4.2 컬렉션
- 동적 배열
- 크기를 고정하지 않고 임의의 개수를 담을 수 있다.
- 리스트, 맵, 셋이 있다.
리스트(List)
-
저장되는 데이터에 인덱스를 부여한 컬렉션
-
중복된 값을 입력할 수 있다.
-
코틀린에서 동적으로 리스트를 사용하기 위해서는 리스트 자료형 앞에 뮤터블이라는 접두어가 붙는다.
- 뮤터블?
- 변할 수 있는 데이터 타입.
- 반대로 변할 수 없는 데이터 타입은 이뮤터블.
- 코틀린은 컬렉션 데이터 타입을 설계할 때 모두 이뮤터블로 설계.
- 기본 컬렉션인 리스트, 맵, 셋은 한번 입력된 값을 바꿀 수 없다.
- 그래서 컬렉션의 원래 용도인 동적 배열로 사용하기 위해서는 뮤터블로 만들어진 데이터 타입을 사용해야 한다.
- 뮤터블?
-
var list = mutableListOf(“MON”, “TUE”, “WED”)
리스트 생성하기 : mutableListOf
-
3개의 값을 가진 크기가 3인 동적 배열 리스트가 생성된다.
-
var mutableList = mutableListOf(“MON”, “TUE”, “WED”)
리스트에 값 추가하기
-
mutableLsit.add(“THU”)
-
인덱스를 따로 지정하지 않아도 입력되는 순서대로 인덱스가 지정된다.
리스트에 입력된 값 사용하기 : get
- var variable = mutableList.get(1)
리스트 값 수정하기 : set
- mutableList.set(1, “수정할 값”)
리스트에 입력된 값 제거하기 : removeAt
-
mutableList.removeAt(1)
-
1번 인덱스가 삭제되면 2번 인덱스부터 하나씩 앞으로 당겨진다.
빈 리스트 사용하기
- 아무것도 없는 빈 리스트를 생성하면 앞으로 입력되는 값의 데이터 타입을 알 수 없기 때문에 값의 타입을 추론할 수 없다.
- 그래서 빈 컬렉션의 경우 앞에서처럼 ‘데이터 타입Of’만으로는 생성되지 않고 데이터 타입을 직접적으로 알려주는 방법을 사용해야 한다.
- var 변수명 = mutableListOf<컬렉션에 입력될="" 값의="" 타입="">()
컬렉션에>
var stringList = mutableListOf<String>()- < > 는 제네릭
- 제네릭은 컬렉션이 사용하는 값의 타입을 지정하기 위한 도구
- 코틀린에서 컬렉션은 제네릭을 사용하지 않으면 생성할 수 없다.
- 단 값을 초기화 할 때는 입력되는 값으로 타입을 추론할 수 있기 땜누에 제네릭을 쓰지 않아도 생성할 수 있다.
컬렉션 가져오기
- Size 프로퍼티를 사용하면 컬렉션의 개수를 가져올 수 있다.
- mutableList.size
- set, get은 함수라고 하고 size는 프로퍼티라고 한다.
- 둘을 구별하는 방법은 괄호의 유무이다.
셋(set)
- 셋은 중복을 허용하지 않는 리스트이다.
- 리스트와 유사한 구조이지만 인덱스로 조회할 수 없고 get함수도 지원하지 않는다.
- String 타입의 값을 입력받기 위해 다음과 같이 선언할 수 있다.
var set = mutableSetOf<String>()
빈 셋으로 초기화하고 값 입력하기
set = mutableSetOf<String>()
set.add("JAN")
set.add("FEB")
set.add("MAR")
set.add("JAN")
- 셋은 중복을 허용하지 않기 때문에 네번째 JAN은 입력되지 않는다.
셋 사용하기
- 인덱스로 조회하는 함수가 없기 때문에 특정 위치의 값을 직접 사용할 수 없다.
Log.d("Collection", "set 전체 출력 = ${set}")
셋 삭제하기
-
값으로 직접 조회해서 삭제할 수 있다.
-
set.remove("FEB")
맵(map)
맵 생성하기
- 맵은 키와 값의 쌍으로 입력되는 컬렉션이다.
- 제네릭으로 키와 값의 데이터 타입을 지정해서 맵을 생성한다.
- var map = mutableMapOf<데이터 타입, 데이터 타입>
빈 맵으로 생성하고 값 추가하기
- 값을 추가하기 위해서는 제공되는 맵에서 제공되는 put 함수에 키와 값을 입력하면 된다.
- Map.put(“키1”, “값2”)
- 키와 값을 추가할 때마다 리스트처럼 공간이 늘어난다.
- 키가 다르다면 중복값을 넣을 수 있다.
맵 사용하기
- get() 함수에 키를 직접 입력해서 값을 꺼낼 수 있다.
- Log.d(“CollectionMap”, “map에 입력된 키의 값은 ${map.get(“키1”)}입니다”)
맵 수정하기
- put 함수를 사용할 때 동일한 키를 가진 값이 있으면 키는 유지된 채로 그 값만 수정된다.
- map.put(“키1”, “수정”)
맵 삭제하기
- remove 함수에 키를 입력해서 값을 삭제할 수 있다.
- 리스트와는 다르게 인덱스에 해당하는 키의 값이 변경되지 않고 그대로 유지된다.
- map.remove(“키1”)
4.3 이뮤터블 컬렉션
- 크기와 값을 변경할 수 없는 컬렉션
- 이뮤터블 컬렉션은 기존 컬렉션에서 mutable이라는 접두어가 제거된 형태로 사용된다.
var list = mutableListOf("1", "2") ---> var list = listOf("1", "2")- 불변형 컬렉션은 한 번 입력된 값을 변경할 수 없기 때문에 add나 set 함수는 지원하지 않고 최초 입력된 값만 사용할 수 있다.
- 기준이 되는 어떤 값의 모음을 하나의 변수에 저장할 필요가 있거나, 여러개의 값을 중간에 수정하지 않고 사용할 필요가 있을 때 이뮤터블 컬렉션을 사용한다.
- 이뮤터블 컬렉션을 저장할 때는 상수로 선언하고 상수명을 대문자로 표시하는 것이 좋다.
5 반복문
5.1 for 반복문
- 특정 횟수만큼 코드를 반복하기 위해 사용
for (반복할 범위) {
// 실행 코드
}
for in..(온점 2개) : 일반적인 형태의 반복문
- 시작값과 종료값으로 지정한 숫자 범위만큼 코드를 반복하는 일반적인 방법.
for (변수 in 시작값..종료값) { // 실행 코드 }
until : 마지막 숫자 제외하기
- 시작값과 종료값 사이의 .. 대신에 until을 사용하면 종료값 이전까지만 반복한다.
for (변수 int 시작값 until 종료값) {
// 실행 코드
}
step : 건너뛰기
- for문의 블록을 step 수만큼 건너뛰어서 실행한다.
for (변수 in 시작값..종료값 step 3) {
// 실행 코드
}
downTo : 감소시키기
- 큰수에서 작은수로 감수하면서 실행할 수 있다.
for (index in 0 downTo 10) {
// 실행 코드
}
배열, 컬렉션에 들어있는 엘리먼트 반복하기
- 배열이나 컬렉션을 엘리먼트의 개수만큼 반복하면서 사용할 수 있다.
for (변수 in 배열 또는 컬렉션) {
// 실행 코드
}
5.2 while 반복문
- if문처럼 조건식을 사용해서 언제까지 반복할 지 결정
- 반복이 가능한 if문
일반적인 while 문
- 증감되는 인덱스가 있으면 코드에서 직접 처리해야 한다.
while (조건식) {
// 실행 코드
}
do와 함께 사용하기
- While 문의 조건식과 관계없이 do 블록 안의 코드를 한 번 실행한다.
do {
// 실행 코드
} while (조건문) {
// 실행 코드
}
while과 do ~ while의 차이점
- 최초값이 조건식을 만족하지 않았을 경우 실행 코드가 달라진다.
5.3 반복문 제어하기
break : 반복문 탈출하기
- 반복문 코드 안에서 break를 만ㄷ나면 반복문을 탈출할 수 있게 해준다.
continue : 다음 반복문으로
- 반복문 내에서 continue를 만나면 continue 다음 코드는 실행하지 않고 반복문의 처음으로 돌아간다.
6 함수
- 함수는 fun으로 정의하고 반환값이 있는 함수는 내부에서 return으로 값을 반환할 수 있다.
- 함수를 정의할 때 입력값을 기술한 것을 파라미터라고 한다.
- 함수는 코드를 사용할 수 있는 최소 단위.
- 모든 코드는 함수 안에 작성해야 하며 코드의 실행은 함수를 호출하는 것에서 시작한다.
6.1 함수의 정의
fun 함수명(파라미터 이름: 타입): 반환 타입 {
return 값
}
- 파라미터와 반환값이 없으면 둘 다 작성하지 않는다.
- 반환값이 없는 대표적인 함수가 log에 정의되어 있는 d()이다.
- 함수를 호출할 때 괄호 안에 값을 넣어서 전달하는데 이때 입력되는 값의 타입은 함수에 정의된 파라미터 타입과 동일하게 입력해야 한다.
반환값과 입력값이 있는 함수의 정의
fun square(x: Int): Int {
return x * x
}
- 함수가 호출되면 호출한 측으로 입력값을 제곱해서 반환하고 실행 종료.
반환값이 없는 함수의 정의
fun printSum(xL Int, y: Int) {
Log.d("fun", "x + y = ${x + y}")
}
- 함수가 호출되면 결괏값을 log로 출력하고 실행 종료.
입력값 없이 반환값만 있는 함수의 정의
fun getPi(): Double {
return 3.14
}
- 호출한 측으로 3.14를 반환하고 실행 종료.
6.2 함수의 사용
- 함수의 사용은 이름 뒤에 괄호를 붙여서 명령어를 실행하는 형태.
- 함수명(값)
반환값과 입력값이 있는 함수의 호출
var squareResult = square(30)
Log.d("fun", "30의 제곱은 ${squareResult}입니다.)
반환값이 없는 함수의 호출
printSum(3, 5)
- 반환값이 없으면 대입 연산자(=)를 사용하지 않고 바로 호출해서 실행한다.
입력값이 없는 함수의 호출
var PI = getPi()
Log.d("fun", "지름이 10인 원의 둘레는 ${10*PI}입니다."}
6.3 함수 파라미터의 정의
- 코틀린에서 함수 파라미터를 통해 입력되는 모든 값은 변하지 않는 이뮤터블이다.
- 코틀린에서의 함수 파라미터는 모두 상수 키워드 val이 생략된 형태.
- fun 함수명(val 생략) name1: Stirng, name2: Int, name3: Double) {실행 코드}
파라미터의 기본값 정의와 호출
-
파라미터는 정의할 때 등호를 사용해서 기본값을 설정할 수 있다.
-
fun 함수명(name1: String, name2: Int = 157, name3: Double) {실행 코드}
파라미터 이름으로 값을 입력하기
- 순서와 상관없이 정의된 파라미터 이름을 지정해서 직접 값을 입력할 수 있다.
7 클래스와 설계
- 함수와 변수를 한군데 모아두고 사용하기 쉽게 이름을 붙여놓은 것을 클래스라고 한다.
7.1 클래스의 기본 구조
class 클래스명 {
var 변수
fun 함수() {
// 코드
}
}
클래스의 생성
- 코틀린은 객체를 사용하기 위해 두 가지 형태의 생성자(함수)를 제공한다.
- 클래스를 사용한다는 것은 곧 클래스라는 그룹으로 묶여있는 코드를 실행하는 것이기 대문에 함수 형태로 제공되는 생성자를 호출해야지만 클래스가 실행된다.
-
클래스 시작 —호출—> 클래스{생성자(함수)}
- 생성자를 사용하지 않을 경우에는 생성 시 자동으로 기본 생성자가 호출되는데 기본 생성자는 파라미터가 아무겂도 없는 빈 코드 블록이다.
class Kotlin {
init {
// 생성자가 없으면 아무것도 없는 init 블록이 실행되는 것과 같다.
}
}
프라이머리 생성자
- 클래스의 헤더처럼 사용할 수 있으며 constructor 키워드를 사용해서 정의하는데 조건에 따라 생략할 수 있다.
- 파라미터 사용 가능.
- 생성자에 접근 제한자나 특정 옵션이 없다면 constructor 키워드 생략 가능.
class KotlinOne constructor(value: String) {
// 코드
}
class KotlinTwo (value: String) {
// 코드
}
- 프라이머리 생성자는 헤더처럼 class 키워드와 같은 위치에 작성되기 때문에 생성자 옆에 코드 블록을 작성할 수는 없지만, 이는 init 블록으로 대체할 수 있다.
- 클래스의 생성자가 호출되면 init 블록의 코드가 실행되고, init 블록에서는 생성자를 통해 넘어온 파라미터에 접근할 수 있다.
class KotlinTwo (value: String) {
init {
Log.d("class", "생성자로부터 전달받은 값은 ${value}입니다.")
}
}
세컨더리 생성자
- 세컨더리 생성자는 constructor 키워드를 마치 함수처럼 사용해서 작성할 수 있다.
class KotlinTwo (value: String) {
constructor (value: String) {
Log.d("class", "생성자로부터 전달받은 값은 ${value}입니다.")
}
}
7.3 클래스의 사용
- 클래스의 이름에 괄호를 붙여서 클래스의 생성자를 호출한다.
- 클래스명()
- 아무런 파라미터 없이 클래스 명에 괄호를 붙여서 호출하면 init블록이 있는 생성자가 호출되면서 블록 안의 코드가 자동으로 실행된다.
- 세컨더리 생성자의 경우 constructor 블록 안의 코드가 실행된다.
클래스 안에 정의된 함수와 변수 사용하기
- 클래스를 사용한다는 것은 사실상 클래스 내부에 정의된 변수와 함수를 사용한다는 것이다.
클래스를 인스턴스화 하지 않고 사용하기 : companion object
- Companion object 코드 블록을 사용하면 클래스를 생성자로 인스턴스화 하지 않아도 블록 안의 프로퍼티와 메서드를 호출해서 사용할 수 있다.
class KotlinFour {
companion object {
var one: String = "None"
fun printOne() {
Log.d("class", "one에 입력된 값은 ${one}입니다")
}
}
}
- 클래스명을 그대로 사용하기 때문에 호출하는 클래스명의 첫글자가 대문자이다.
7.4 데이터 클래스
- 간단한 값의 저장 용도로 데이터 클래스를 제공한다.
- data class 클래스명 (val 파라미터1: 타입, var 파라미터2: 타입)
데이터 클래스의 정의와 생성
- var 키워드 생략 불가.
- toString() 메서드를 호출하면 값을 반환.
copy() 메서드 지원
-
값을 간단하게 복사할 수 있다.
-
var newData = dataUser.copy()
7.5 클래스의 상속과 확장
- 클래스의 재사용을 위해 상속을 지원한다.
클래스의 상속
- 상속 대상이 되는 부모 클래스는 open 키워드로 만들어야만 자식 클래스에서 사용할 수 있다.
-
상속을 받을 자식 클래스에서는 콜론을 이용해서 상속할 부모 클래스를 지정한다.
- 클래스 상속은 부모의 생성자를 호출해서 생성된 인스턴스를 자식이 갖는 과정이기 때문에 부모 클래스명 다음에 괄호를 입력해서 생성자를 호출한다.
open class 상속될 부모 클래스 {
// 코드
}
class 자식 클래스 (value: String) : 부모 클래스(value) {
//코드
}
생성자 파라미터가 있는 클래스의 상속
- 상속될 부모 클래스의 생성자에 파라미터가 있다면 자식 클래스의 생성자를 통해 값을 전달할 수 있다.
open class 상속될 부모 클래스 (value: String) {
// 코드
}
class 자식 클래스 (value: String) : 부모 클래스(value) { // 파라미터 전달
//코드
}
- 부모 클래스에 세컨더리 생성자가 있다면 역시 자식 클래스의 세컨더리 생성자에서 super 키워드로 부모 클래스에 전달할 수 있다.
부모 클래스의 프로퍼티와 메서드 사용하기
open class Parent {
var hello: String = "안녕하세요."
fun sayHello() {
Log.d("inheritance", "${hello}")
}
}
class Child : Parent() {
fun myHello() {
hello = "Hello"
sayHello() // Hello 출력
}
}
프로퍼티와 메서드의 재정의 : 오버라이드
- 상속받은 부모 클래스의 프로퍼티와 메서드 중에 자식 클래스에서는 다른 용도로 사용해야 하는 경우가 있다.
- 동일한 이름의 메서드나 프로퍼티를 사용할 필요가 있을 경우에 override 키워드를 사용해서 재정의 할 수 있다.
- 오버라이드를 할 때는 프로퍼티나 메서드도 클래스처럼 앞에 open을 붙여서 상속할 준비가 되어 있어야 한다.
메서드 오버라이드
- 상속할 메서드 앞에 oepn 키워드를 붙인다.
open class BaseCalss {
open fun opened() {
}
}
class ChildClass : BaseClass() {
override fun opened() {
}
}
프로퍼티 오버라이드
- 상속할 프로퍼티 앞에 open 키워드를 붙인다.
open class BaseCalss {
open var opened: String = "I am"
}
class ChildClass : BaseClass() {
override var opened: String = "You are"
}
익스텐션
- 클래스, 메서드, 프로퍼티에 대해 익스텐션을 지원한다.
- 이미 만들어져있는 클래스에 다음과 같은 형태로 메서드를 추가할 수 있다.
fun 클래스.확장할 함수() {
// 코드
}
- 미리 만들어져있는 클래스에 메서드를 붙여넣는 개념
7.6 설계 도구
- 패키지 : 클래스와 소스 파일을 관리하기 위한 디렉터리 구조의 저장 공간
- 추상화 : 명확한 코드는 설계 단계에서 메서드 블록 안에 직접 코드를 작성하는데, 그렇지 않은 경우에는 구현 단계에서 코드를 작성하도록 메서드의 이름만 작성한다.
- 인터페이스 : 실행 코드 없이 메서드 이름만 가진 추상 클래스.
- 인터페이스 만들기 : interface 예약어로 인터페이스를 정의한다.
- 클래스에서 구현하기 : 인터페이스를 클래스에서 구현할 때는 상속과 다르게 생성자를 호출하지 않고 인터페이스 이름만 지정해준다.
- 접근 제한자
- 종류
- private : 다른 파일에서 접근할 수 없다.
- internal : 같은 모듈에 있는 파일만 접근할 수 있다.
- protected : privated와 같으나 상속 관계에서 자식 클래스가 접근할 수 있다.
- public : 제한 없이 모든 파일에서 접근할 수 있다.
- 적용 : 접근 제한자를 앞에 붙이면 된다.
- 종류
- 제네릭 : 입력되는 값의 타입을 자유롭게 사용하기 위한 설계 도구.
8 null 값에 대한 안정적인 처리 : null Safety
8.1 null 값 허용하기 : Nullable
- 코틀린에서 지정하는 기본 변수는 모두 null이 입력되지 않는다.
-
null값을 입력하기 위해서는 변수를 선언할 때 타입 뒤에 ?(Nullable) 입력한다.
- var variable: String?
변수에 null 허용 설정하기
- 변수의 타입 뒤에 물음표를 붙이지 않으면 null 값을 입력할 수 없다.
- null 예외를 발생시키고 싶지 않다면 기본형으로 선언한다.
var nullable: String?
nullable = null
함수 파라미터에 null 허용 설정하기
- 함수의 파라미터가 null을 허용할 경우는 코드 내부에서 해당 파라미터에 대해서 null 체크를 먼저 해야만 사용할 수 있다.
fun nullParameter(str: String?) {
if (str != null) {
var length2 = str.length
}
}
함수의 리턴 타입에 null 허용 설정하기
- 함수의 리턴 타입에도 물음표를 붙여서 null 허용 여부를 설정할 수 있다.
fun nullReturn(): String? {
return null
}
8.2 안전한 호출 : ?.
?.를 사용해서 간결하게 할 수 있다.- Nullable인 변수 다음에 ?.을 사용하면 해당 변수가 null일 경우 ?.다음의 메서드나 프로퍼티를 호출하지 않는다.
8.3 null 값 대체하기 : ?:
- 원본 변수가 null일 때 넘겨줄 기본값을 설정한다.
- 프로퍼티 뒤에 다시 ?: 을 붙이고 그 뒤에 값을 표시한다.
- 이 경우 변수가 null일 경우 ?: 의 뒤에 붙은 값은 반환한다.