🚀 패키지는 클래스와 소스 파일을 관리하기 위한 디렉토리 구조의 저장 공간 ✓ 현재 클래스가 어떤 패키지(디렉토리)에 있는지 표시 ✓ 디렉토리가 계층 구조로 만들어져 있으면 점(.)으로 구분해서 각 디렉토리를 모두 나열해 줌
package 메인 디렉토리. 서브 디렉토리 class 클래스 { }
🚀 이 디렉토리 구조라면 윈도우의 파일 탐색에서 보면 메인 디렉토리 아래에 서브 디렉토리가 있고, 서브 디렉토리 안에 실제 코드가 있는 클래스.kt 파일이 있음
🚀 하나의 패키지에 여러 개의 파일을 생성할 수 있기 때문에 '서로 관계가 있는 파일을 동일한 패키지로 만들어 두면 관리가 용이
2. 추상화
🚀 프로그래밍을 하기 전 개념 설계를 하는 단계에서는 클래스의 이름과 클래스 안에 있음 직한 기능을 유추해서 메서드 이름으로 먼저 나열. 이때 명확한 코드는 설계 단계에서 메서드 블록 안에 직접 코드를 작성하는데, 그렇지 않은 경우에는 구현 단계에서 코드를 작성하도록 메서드의 이름만 작성 ▶️ 이것을 추상화 Abstract 라고 하며 abstract 키워드를 사용해서 명시
✓ 구현 단계에서는 이 추상화된 클래스를 상속받아서 아직 구현되지 않은 부분을 마저 구현 ✓ 다음과 같이 추상화된 Aniamal 클래스를 만들고 동물이 사용할 것 같은 기능 중 walk()와 move()를 설계한다고 가정
abstract class Animal {
fun walk() {
println("Walking")
}
abstract fun move()
}
👾 walk는 명확하게 걸어가는 행위이지만 move는 어떤 동물이냐에 따라서 달라진다고 가정 👾 이렇게 앞으로 상속받을 자식 클래스의 특징에 따라 코드가 결정될 가능성이 있다면 해당 기능도 abstract 키워드로 추상화 ➡️ 실제 구현 클래스는 이 추상 클래스를 상속받아서 아직 구현되지 않은 추상화되어 있는 기능을 모두 구현해 줌 👾 추상 클래스는 독립적으로 인스턴스화 할 수 없기 때문에 구현 단계가 고려되지 않는다면 잘못된 설계가 될 수 있음
class Bird : Animal() {
override fun move() {
println("Bird move")
}
}
3. 인터페이스
🚀 인터페이스 interface는 실행코드 없이 메서드 이름만 가진 추상 클래스. 즉, 누군가 설계해 놓은 개념 클래스 중에 실행 코드가 한 줄이라도 있으면 추상 클래스, 코드 없이 메서드 이름만 나열되어 있으면 인터페이스
🚀 인터페이스는 안드로이드에서는 주로 상속 관계의 설계보다는 외부 모듈에서 내가 만든 모듈을 사용할 수 있도록 메서드의 이름을 나열해둔 일종의 명세서로 제공
🚀 인터페이스는 interface 예약어를 사용해서 정의할 수 있고 인터페이스에 정의된 메서드를 오버라이드해서 구현할 수 있음 ✓ 코틀린은 프로퍼티도 인터페이스 내부에 정의할 수 있고, 추상 클래스와 다르게 class 키워드는 사용되지 않음
interface 인터페이스명 {
var 변수 : String
fun 메서드1()
fun 메서드2()
}
1) 인터페이스 만들기
interface 예약어로 인터페이스를 정의 코틀린은 인터페이스 내부에 프로퍼티도 정의할 수 있음
interface InterfaceKotlin {
var variable: String
fun get()
fun set()
}
2) 클래스에서 구현하기
인터페이스를 클래스에서 구현할 때는 상속과는 다르게 생성자를 호출하지 않고 인터페이스 이름만 지정해 주면 됨
class KotlinImpl : InterfaceKotlin {
override var variable: String = "Default"
override fun get() {
}
override fun set() {
}
}
💡 인터페이스를 코틀린의 상속 형태가 아닌 소스 코드에서 직접 구현할 때도 있는데, object 키워드를 사용해서 구현해야 함 ➡️ 안드로이드 프로젝트에서 자주 사용하는 형태
val kotlinImpl = object : InterfaceKotlin {
override var variable: String = "Default"
override fun get() {
}
override fun set() {
}
}
'주문 정보와 배송 정보가 같습니다' 클릭 시 주문 정보 가지고 오고, 클릭 해제시 정보 지우는 코드
<head>
<link rel="stylesheet" href="css/order.css">
<script>
document.addEventListener('DOMContentLoaded', function () {
const check = document.querySelector('#shippingInfo');
// 체크박스의 id는 shippingInfo
check.addEventListener('click', function () {
// check 요소에 click 이벤트가 발생했을 때 실행할 함수
if (this.checked) { // 체크 되었을 때
document.querySelector('#shippingName').value = document.getElementById('billingName').value;
document.querySelector('#shippingTel').value = document.getElementById('billingTel').value;
document.querySelector('#shippingAddr').value = document.getElementById('billingAddr').value;
} else { // 체크 해제되었을 때 배송정보 지움
document.querySelector('#shippingName').value = "";
document.querySelector('#shippingTel').value = "";
document.querySelector('#shippingAddr').value = "";
}
});
});
</script>
</head>
💡 폼 요소 접근 방법 3가지
1. id 값이나 class 값을 사용해 폼 요소에 접근하기 👾 id 값이나 class 값을 사용해 폼 요소에 접근하는 방법은 DOM의 다른 요소에 접근하는 것과 같음 👾 querySelector() 함수나 querySelectorAll() 함수를 사용 👾 텍스트 필드에 있는 값을 가져오기 위해서는 텍스트 필드에 접근하는 소스 뒤에 value 속성을 붙임
2. name 값을 사용해 폼 요소에 접근하기 👾 폼 요소에 id나 class 속성이 없고 name 속성만 있는 경우 name 식별자를 사용해 폼 요소에 접근 👾 이 방법을 사용하려면 <form> 태그에 name 속성이 지정되어 있어야 하고, <form> 태그안에 포함된 폼 요소에도 name 속성이 있어야 함 👾 폼 안에 있는 텍스트 필드에 접근하려면 <form>의 name 값과 텍스트 필드의 name 값을 사용 👾 submit시에 input의 name은 서버로 전송. 하지만 form의 name은 서버로 전송되지 않음
console.log(document.order.billingName.value);
3. 폼 배열을 사용해 폼 요소에 접근하기 👾 document의 속성 중 forms 속성은 문서 안에 있는 <form> 태그를 모두 가져와 배열 형태로 반환 👾 이 방법은 폼 요소에 id나 class 속성도 없고 name 속성도 없을 때 유용 👾 <form> 태그 안에 포함된 요소에 접근하려면 elements 속성을 사용 ➡️ 해당 폼 안에 있는 모든 폼 요소를 가져오는 속성, 인덱스 번호로 접근
🐝 코틀린에서는 자료형이 다른 변수에 재할당하면 자동 형 변환이 되지 않고 자료형 불일치 오류Type Mismatch 발생 ➡️ 의도하지 않게 자료형이 변하는 것을 방지하기 위한 것
fun main() {
val a: Int = 1
// val b: Double = a // 자료형 불일치 오류 발생. 자바와 차이점.
// val c: Int = 1.1 // 자료형 불일치 오류 발생
}
🍯 변수 a는 Int 형이므로 Double 형 변수 b에 다시 할당할 수 없음 🍯 만일 자료형을 변환해 할당하고 싶다면 코틀린에서는 자료형 변환 메서드를 이용 ex. Int ▶️ Double : toDouble() 메서드를 이용
fun main() {
val b: Double = a.toDouble()
println("a=$a, b=$b") // a = 1, b = 1.0
}
자료형이 서로 다른 값을 연산하면, 자료형이 표현할 수 있는 범위가 큰 자료형으로 자동 형변환하여 연산
fun main() {
val result = b + a
println("result = $result") // result = 2.0
}
2. 기본형과 참조형의 비교 원리
🐝 자료형을 비교할 때는 단순히 값만 비교하는 방법 vs 참조 주소까지 비교하는 방법 🐝 단순히 값만 비교할 때는 이중 등호(==)를 사용하고, 참조 주소를 비교하려면 삼중 등호(===)를 사용
이중 등호는 참조와 상관없이 값이 동일하면 true를, 값이 다르면 false를 반환 삼중 등호는 값과 상관없이 참조가 동일하면 true를 반환, 값이 동일하더라도 참조 주소가 다르면 false를 반환
다음은 Int 형으로 선언한 변수 a, b에 128을 대입하고 이중 등호와 삼중 등호로 비교한 것 비교 결과는 모두 true. 이 때 참조형으로 선언된 a와 b는 코틀린 컴파일러가 기본형으로 변환하여 저장 즉, 여기서는 삼중 등호가 비교하는 값도 저장된 값인 128.
fun main() {
val a: Int = 128
val b: Int = 128
println(a == b) // true
println(a === b) // true
}
참조 주소가 달라지는 경우는 null을 허용한 변수 null을 허용한 변수는 같은 값을 저장해도 이중 등호와 삼중 등호를 사용한 결과값이 다름
fun main() {
val c: Int? = 128
val d: Int? = 128
println(c == d) // true
println(c === d) // false
}
3. 스마트 캐스트 알아보기
🐝 만약 어떤 값이 정수일 수도 있고, 실수일 수도 있는 경우에는 그때마다 자료형을 변환해도 되지만 '스마트 캐스트'를 사용할 수 있음 🐝 스마트 캐스트 Smart Cast는 컴파일러가 자동으로 형 변환
⚡️ 대표적으로 스마트 캐스트가 적용되는 자료형은 Number형이 있음 ⚡️ Number형을 사용하면 숫자를 저장하기 위한 특수한 자료형 객체를 만듦 ⚡️ Number형으로 정의된 변수에는 저장되는 값에 따라 정수형이나 실수형 등으로 자료형이 변환됨
fun main() {
var test: Number = 12.2 // 12.2에 의해 test는 Float형으로 스마트 캐스트
println("$test") // 12.2
test = 12 // Int 형으로 스마트 캐스트
println("$test") // 12
test = 120L // Long형으로 스마트 캐스트
println("$test") // 120
test += 12.0f // Float형으로 스마트 캐스트
println("$test") // 132.0
}
4. 자료형 검사하기
🐝 변수의 자료형을 알아낼떄는 is 키워드를 사용 🐝 is는 왼쪽 항의 변수가 오른쪽 항의 자료형과 같으면 true를, 아니면 false를 반환 🐝 is는 변수의 자료형을 검사한 다음 그 변수를 해당 자료형으로 변환하는 기능도 있음
⚡️ Any형을 사용하면 자료형을 결정하지 않은 채로 변수를 선언할 수 있음 ⚡️ Any형은 코틀린의 최상위 기본 클래스로 어떤 자료형이라도 될 수 있는 특수한 자료형 ⚡️ 이때 is를 사용하여 자료형을 검사하면 검사한 자료형으로 스마트 캐스트
fun main() {
var num = 256
if (num is Int) { // num의 자료형이 Int라면 실행.
println(num) // 256
} else if (num !is Int) {
println("No an Int")
}
val x: Any
x = "Hello"
if (x is String) {
println(x.length) // 5
}
/*
변수 x는 Any형으로 선언. 그 후에 "Hello"라는 값을 대입. 아직 x의 자료형은 Any형.
이후 if문으로 is로 x의 자료형을 검사할 때 String으로 스마트 캐스트되어 조건문이 실행.
*/
}
5. 묵시적 형변환
🐝 코틀린의 모든 클래스는 Any형이라는 슈퍼클래스(Superclass)를 가짐 🐝 Any는 자바의 최상위 클래스인 Object와 비슷하지만 서로 다른 유형 🐝 Any 형은 무엇이든 될 수 있기 때문에 언제든 필요한 자료형으로 자동변환할 수 있음 ➡️ 이것을 묵시적 변환이라고 함
fun main() {
var a: Any = 1 // Any형 a는 1로 초기화 될 때 Int형이 됨.
a = "one" // Int형이었던 a는 변경된 값에 의해 String이 됨.
println("a: $a type: ${a.javaClass}") // 자바의 기본형을 출력하면 String이 나옴
// 띄어씌기가 있으면 중괄호 생략 가능
// a: one type: class java.lang.String
checkArg("Hello") // x is String: Hello
checkArg(5) // x is Int: 5
}
fun checkArg(x: Any) { // 인자를 Any형으로 받음
if (x is String) {
println("x is String: $x")
}
if (x is Int) {
println("x is Int: $x")
}
}