-
접근 제한자,지연 초기화, 널 세이프티Android 2024. 3. 7. 23:42
알고리즘 29번
- arr = [1,2,3] 인데 ArrayList 일 경우에는 println(arr) 에 대하여 [1,2,3] 이 출력되지만, IntArray 일 경우에는 println(arr) 을 했을 때 [1,2,3] 이 출력되지 않고 해시코드가 출력된다. 원소 값을 출력하려면 for문을 이용해야 한다.
- IntArray 배열 arr 에 대하여 값을 넣을때는 arr += 3 이런 식으로 쓸 수 있지만, 원소 값을 제거할 때는 arr -= 3 으로 쓸 수 없다.
arr.filter{it!=arr.minOrNull()}.toIntArray() // arr.filter{it!=arr.minOrNull()} → ArrayList 형태 arr.filter{it!=arr.minOf{it}}.toIntArray() // IntArray 배열의 가장 작은 원소 값을 구하는 함수 2개 // 문제 풀면서 참고한 다른 사람의 코드 일부 arrayOf(-1).toIntArray() = intArrayOf(-1) // arr : IntArray var answer = arr.toMutableList() answer.remove(answer.min()!!) answer.toIntArray()
알고리즘 30번
- 문자열(String) 에 대한 길이를 구하는 함수로는 length 가 있다. 또한, slice(처음 인덱스, 마지막 인덱스) 와 substring(처음 인덱스, 마지막 인덱스) 함수를 이용해 문자열의 일부를 다른 변수에 저장할 수 있다.
- 문제의 핵심 : 문자열 길이가 짝수/홀수 일 때 가운데에 해당하는 값의 인덱스는 어떻게 정의할 수 있을까?
과제 lv2, lv3 구현
- 기존 lv2 에서는 하나의 클래스에 작성한 메소드를 lv3 에서는 클래스로 분류해야 했다. 클래스를 분류하면서 부모 클래스와 자식 클래스의 관계를 생성할 수 있었고, 이때 상속과 오버라이딩 그리고 인터페이스 개념을 자연스럽게 이용할 수 있었다.
- 또한 언제 명시적 생성자(주 생성자, 부 생성자)를 써야 하는가 에 대한 고민이 어제와 오늘 과제 만들면서 있었는데 클래스에 매개변수가 주어질 때는 명시적 생성자를 쓰고, 클래스가 매개변수가 주어지지 않을 때는 생성자를 쓰지 않아도 된다는 것을 알게 되었다. 또한, 아래 내용은 헷갈려서 다시 적어보았다!
//부모가 사용자로부터 인자를 전달받지 않는 경우의 자식 클래스 class Chicken : Bird() {} //부모가 사용자로부터 인자를 전달받는 경우 자식 클래스 open class Bird(name:String) {} class Chicken(name:String) : Bird(name) {}
깃헙 강의를 오늘 들었는데.. 이번주 중으로 복습하면서 따로 티스토리에 정리할 계획이다!
접근 제한자
- 프로젝트 > 모듈 > 패키지 > 클래스
- 객체가 변수나 메소드에 접근하는 것을 일부 제한하는 명령어를 뜻한다.
- public : 항상 접근이 가능하며, 선언한 것과 선언하지 않는 것은 같은 의미이다.
- private : 동일한 클래스 내에서만 접근 가능하다.
- internal : 같은 모듈(app) 에 있는 경우 접근 가능하다.
- protected : private 와 같은 개념이면서 자식 클래스 내에서는 접근 가능하다.
지연 초기화
클래스 설계시 초기의 값을 정의하기가 난감하여 나중에 대입을 위한 문법으로, lateinit 과 lazy 가 있다.
lateinit : 변수 지연 초기화
non-nullable primitive type 은 컴파일 할 때 int 로 변하고, nullable primitive type 은 Integer 로 변경이 된다. 변수의 지연 초기화인 lateinit 을 사용하기 전에는 값을 무조건 초기화해야하고, 그렇지 않으면 null 값을 넣어야 한다.
var str1 : String // 틀린 코드 var str1 : String? = null // 맞는 코드1 var str2 : String = "" // 맞는 코드2
하지만, null 자체의 표현에 어색함을 피하기 위해 lateinit 을 사용한다.
lateinit var str1 : String // 맞는 코드 lateinit var num : Int // 틀린 코드
lateinit 지연 초기화에서 Int 형을 쓸 수 없는 이유?
lateinit 지연 초기화를 사용하면 결국에는 처음에 값을 초기화하지 않은거니까 코틀린은 내부적으로 초기화되지 않는 case 를 나타내기 위해 null 이라는 special value 를 사용하게 되는데 null 값을 int(int 를 포함한 다른 primitive type 도 해당되는데 boolean 등이 있다.) 에 저장할 수 없도록 코틀린 문법을 설계하였다.
- isInitialized 명령어를 통해 값이 초기화되었는지 확인할 수 있다 (try~catch 문 예외를 발생시킬 필요 없다!)
- isInitialized 명령어는 값이 아니라 참조 형태로 사용해야해서 this:: 또는 :: 를 붙인다.
lazy : 상수 지연 초기화
상수를 사용하는 시점에 값을 대입하고 초기화한다.
val address: String by lazy { println("address 초기화") "seoul" } fun Info() { if(this::name.isInitialized) {..} // name 값이 초기화가 된 경우 실행 } }
널 세이프티
Null 예외로부터 안정성을 설계하기 위해 자료형에 Null 여부 명시하는 방법이다.
1. ?
null을 저장할 수 있다.
2. !!
null 값이 절대 들어갈 수 없다는 뜻이지만 컨벤션 상 쓰지 않는게 좋다.
3. ?.
값이 null 인지 확인하고 null 이 아닐 때만 참조
4. ?: (Elvis Operator)
값이 null 인 경우 ?: 뒤에 있는 값을 사용하겠다는 의미이다.
val hello = something ?: "default hello" // something이 null이면 hello는 default hello를 갖게 되며 // something이 null이 아니면 something의 값으로 할당된다.
class Student { var opt = readLine()!! // !! → null 값이 들어갈 수 없다 var address: String? = null // ? → null 값이 들어갈 수 있다. fun returnLen() { println("주소의 길이 : ${address?.length}") // ?. → null 값일 때 "null"을 출력 println("주소의 길이 : ${address?.length ?: "주소값이 없습니다!"}) // ?: → null 대신 다른 값 출력 } }
// 널 세이프티 예시1 "money" -> { println("초기자본을 입력해주세요") while (true) { try { var originMoney: String? = readLine() return originMoney?.toInt() ?: -1 } catch (e: Exception) { println("잘못 입력하셨습니다!") } } } // 널 세이프티 예시2 "job" -> { println("직업을 입력해주세요") while (true) { try { var originName = readLine() if (originName?.equals("궁수") == true || originName?.equals("마법사") == true) { return originName } else { println("직업은 궁수와 마법사밖에 없습니다") } } catch (e: Exception) { println("잘못 입력하셨습니다!") } } }
'Android' 카테고리의 다른 글
abstract vs open, 예외 처리 (0) 2024.03.11 CharArray, Zip, Map, Array, Collection (0) 2024.03.08 생성자, 상속, 인터페이스, 오버라이딩, 오버로딩 (2) 2024.03.06 fold / foldIndexed 함수, 자료형 정리, 증감연산자 (0) 2024.03.05 2024-03-04 BOOTCAMP TIL (3) 2024.03.04