val num1 : Int? = 10
val num2 : Int? = 20
val num3 : Int? = num1 + num2
는 에러가 나온다. 그 이유는 컴퓨터가 num1과 num2가 정수라는 것을 보장받지 못하기 때문이다. 때문에 우리는 컴퓨터에게 우리가 정수를 보장해 준다는 것을 말해줄 필요가 있는데 그것을 하는 키워드가 !!이다.
val num1 : Int? = 10
val num2 : Int? = 20
val num3 : Int? = num1!! + num2!! //null이 아니야
함수를 간단하게 선언하는 방법
fun 함수명(변수명:타입...) = 함수내용
가변인자를 갖는 함수
fun 함수명(vararg 변수명:타입):반환형{
}
배열
arrayOf<자료형/생략>(값1,값2,값3)
var array1 = arrayOf(true, false, "안녕하세요", 1)
var array2 = arrayOf<Int>(1,3,6)
var array3 = intArrayOf(1,3,5)
var array4 = Array(10,{0})
var array5 = Array<Int>(10,{0})
var array6 = Array<String>(10,{"Hi"})
var array7 = IntArray(10,{0})
array7[2] = 100
array7.set(2,100)
val value = arry7[2]
val value = array7.get(2)
Collection
크기 조정 가능
val numbers = listOf<Int>(1,2,3)
val numbers = mutableListOf<Int>(1,2,3)
val numbers = setOf<Int>(1,2,3) //중복X
val numbers = mutableSetOf<Int>(1,2,3) //중복X
val numbers = mapOf<String, String>("1" to "일","2" to "이")
val numbers = mutableMapOf<String, String>("1" to "일","2" to "이")
Progression
시작점과 끝점이 있고, 범위를 정할 수 있다.
구간 1 : 반복을 할 때 1씩 이동한다
Range : 구간이 1인 Progression
1..10 -> 1부터 10까지
1..10 step 2
1.rangTo(10) -> 1부터 10까지
10 downTo 1 step 2
(1..10).reversed()
1 until 10 -> 1부터 9까지
열린구간 : 해당 시작점/끝점을 제외
닫힌구간 : 해당 시작점/끝점을 포함
반복문
for(i in 1..10){
}
val numbers = listOf<Int>(1,2,3,4)
for(value in numbers.size){
println(value)
}
for((index, number) in numbers.withIndex()){
println(index + " | " number)
}
nmbers.forEach{
println(it)
}
//label
loop@for(i in 1..3){
println(i)
for(j in 1..3){
if(j==2) break@loop
else println(j)
}
}
//index만 뽑을 때
for(index in numbers.indices){
println(index)
}
//index와 value 가져올때
numbers.forEachIndexed { index, i -> }
예외처리
try{
코드 -> 예외 발생 가능한 코드
}catch(변수 : 에러코드){
예외를 처리하는 코드
}finally{ //필요에 따라 실행
무조건 실행하는 코드
}
//에러코드 Exception은 모든 에러코드 잡아줌
고차함수
fun fuction1 (number1 : Int, number2 : Int) : Int ={}
fun function2 (function : (Int, Int) -> Int){
함수내용
}
//고차함수 호출하는 방법
function2(::function1)
람다
1. 풀버전
val function3 : (String) -> Unit = {str : String -> 함수내용}
2. 축약 버전
val function3 : (String) -> Unit = {str -> 함수내용}
or
val function3 = {str : String -> 함수내용}
3. 파라미터가 없는 람다
val function3 : () -> Int ={
10 + 9
}
4. 파라미터가 한 개인 경우라면 it을 사용
val function4 : (String) -> Unit = { println(it) }
클래스
//주 생성자
class User constructor( name : String){
val userName : String
init {
userName = name
}
}
//constructor, init은 생략가능
class User (name : String){
val userName = name
}
//클래스 속성 초기화도 생략 가능
class User (val name : String){
}
//부 생성자
class User ( name : String){
val userName : String = name
var age : Int = 0
constructor(name : String, age : Int) : this(name){
this.age = age
}
}
//getter, setter
class Book() {
var title: String = "어린왕자"
get() {
return field
}
set(value) {
field = value
}
}
//lateinit
fun main() {
val book = Book()
book.nextPage()
book.title = "어린왕자"
book.nextPage()
}
class Book() {
lateinit var title : String
fun nextPage(){
if(::title.isInitialized){
println("페이지가 넘어간다.")
}else{
println("초기화 필요")
}
}
}
//lazy
//사용이유 : 사용하지 않는 복잡한 작업들에 리소스가 소모되는 것 예방, 꼭 필요할 때만 초기화 해줌
class Book() {
val title : String by lazy{
//본문 -> 다른 작업도 할 수 있지만 반드시 프로퍼티를 초기화 시켜주는 작업을 해야함
println("lazy 초기화")
"어린왕자"
}
}
형 변환
fun main() {
val defenseWarrior : Worrior = DefenseWarrior()
defenseWarrior.attack()
//is 타입 체크로 스마트 캐스팅을 해준다
//defenseWarrior는 Worrior 타입이라 DefenseWarrior의 프로퍼티 사용 불가지만 is 사용하면 가능
if(defenseWarrior is DefenseWarrior){
println(defenseWarrior.bonusPower)
}
//지정한 타입으로 캐스팅 시도하고 불가능하면 예외발생
val warrior2 : DefenseWarrior = defenseWarrior as DefenseWarrior
warrior2.bonusPower
}
open class Worrior {
open fun attack() {
println("복잡한 코드 + 공격")
}
}
class DefenseWarrior : Worrior(){
var bonusPower = 0
}
NullSafety
//?. null이면 null출력 아니면 그냥출력
val str : String? = null
print(str?.length)
//!!. null이 아니니까 length 실행해
println(str!!.length)
//as? safe casting 이 안되면 null반환
open class Warrior1(var name: String, var power: Int, var type: String) { //부모클래스, 슈퍼클래스
fun attack() {
println("복잡한 코드 + 공격")
}
}
//주 생성자가 슈퍼클래스 생성을 하는 경우
class DefenseWarrior1 constructor(name: String, power: Int) : Warrior1(name,power,"고블린") {
fun defense() {
println("방어")
}
}
val defenseWarrior = DefenseWarrior1("", 100)
val warrior = defenseWarrior as? Warrior1
println(warrior)
// ?: 엘비스 연산 null이면 오른쪽 아니면 왼쪽 실행 (?: 기준)
val str : String? = null
print(str?.length ?: 0)
패키지명 : 앱 처음 만들 때 지정해주는데 플레이스토어에 올릴 때 패키지명은 겹치면 안 되므로 고유해야한다, 거의 회사 URL 거꾸로 써줌
allawBackup : 앱 지우고 다시 설치시 이전에 있던 정보 복구해줌
supportsRtl : 아랍권이나 문자를 오른쪽에서 왼쪽으로 읽는 문화권 지원을 해줌
exported : 액티비티를 외부에서 부를 수 있음(켤 수 있음) 첫 화면은 무조건 true 왜냐하면 앱 킬 때도 적용(시스템)
빌드 : 우리가 만든 코드들을 실제 돌아가는 앱으로 만들어 주는 것을 빌드한다함
gradle : 우리가 작성한 코드를 APK로 만들어줌
프로젝트 : 앱들의 모음(최상위), 모든앱에 영향을 줌
모듈 : 앱 하나에 영향을 줌
targetSkd : test할 때 어떤 sdk로 테스트할건지
코드 난독화 : 사람이 내 앱 코드를 읽을수 없게 함
debugmode : 왼쪽에 클릭해 표시해 둔 곳까지 빌드해줌(문제가 있을 거 같은 부분 찝어줌)
profile : 우리 앱이 얼마나 리소스 확인하고 있는지 실시간 확인
LifeCycle
savedInstanceState : 사용자가 앱 나갔다 다시 들어왔을 때 전에 정보 저장해주는 변수
리스너 : 이벤트가 발생했을 때 수신하는 역할
apply / also -> 처리가 끝나면 (스코프 끝) 인스턴스(객체)를 반환한다
run(with) / let -> 처리가 끝나면 최종값을 반환한다
apply / run(with) -> this 스코프 밖에 있는 변수 이름과 혼돈할 수 있음(객체 생성 하기 전)
also / let -> it 스코프 밖에 있는 변수 이름과 혼돈 방지(객체 생성 미리 됨)
apply : 객체 초기화
also : 유효성검사
run(with) : 잘 안쓰임
let : nullsafety기능 사용해서 null 아닐경우 스코프 안에 사용한다
인스턴스 변수는 인스턴스 생성시 인스턴스 안에 존재하는 변수, 클래스 변수는 인스턴스와 상관없이 존재하는 변수로 앞에 static을 붙인다.
클래스 내의 정의된 클래스는 네스티드 클래스라 하며 감싸는 클래스를 외부 클래스라한다.
네스티드 클래스는 static을 붙이냐 마냐에 따라 나누어 지는데 Non-static 네스티드 클래스를 이너 클래스라고 한다. 그리고 이너 클래스는 정의되는 위치나 특성에 따라 세가지 종류로 나뉜다.
이들은 보통 이너를 빼고 말함
Static 네스티드 클래스 선언은 외부 클래스.네스티드클래스 변수 = new 외부클래스.네스티드클래스()
클래스 변수에 접근 가능하지만 외부 클래스의 인스턴스 변수와 메소드에는 접근 불가능
같은 외부 클래스를 공유하는 멤버 이너 클래스는 외부 클래스의 인스턴스 변수를 공유한다.
익명 클래스란 class를 선언하지 않고 인터페이스의 메소드를 구현한 것은 인터페이스의 자료형으로 반환하는 것이다. 인터페이스의 추상메소드는 1개
interface Printable{
void print(String s);
}
//익명 클래스
Printable prn = new Printable(){
public void print(String s){
System.out.println(s);
}
};
//람다
Printable prn = (s) -> {System.out.println(s);};
Intent
- 의도, 의사
- A야 B좀 해줘
- B좀 해줘
- A야 B좀 해줘 그리고 다하면 알려줘
- 데이터를 같이 전달할 수 있다
- 명시적 인텐트 (Explicit Intent)
- 호출될 대상을 명시하는 경우
- 암시적 인텐트 (Implicit Intent)
- 호출될 대상을 명시하지 않는 경우
- 인텐트 필터 (Intent- filter)
- 암시적 인텐트를 보낸 경우, 인텐트가 처리할 수 있는지 확인할 때 사용
- 인텐트 호출 대상 V
- 앱내에서
- 엑티비티 끼리
- 외부(안드로이드 OS, 시스템), 앱 끼리(권한이 필요한다)
- 사진 앱
- 우리 앱 -> 시스템 -> 사진첩
- 우리 앱 전화 걸기 버튼 -> 시스템 -> 전화 걸기 앱
- 인텐트 V
- 결과가 필요한 경우
- 결괄가 필요하지 않은 경우