안드로이드 개발자가 알아야할 최소한의 지식

안드로이드 개발자가 알아야할 최소한의 지식

안드로이드는 현존하는 모바일 운영체제 중 가장 탄탄한 지지기반을 가진 운영체제이다. 안드로이드 개발자로서 일하고 있거나 직업으로 생각하고 있는 사람들이 알고 있어야할 최소한의 지식을 정리해봤다. 그리고 안드로이드 개발자를 뽑으려고 계획하는 사람들도 아래 지식을 숙지하고 면접 때 활용해 볼 만하다.

시작하면서..

이 문서는 이론에 관한 내용을 다룬다. 물론 소스 코드로 컨셉을 설명할 때도 있다.

안드로이드 관련

Android Manifest란 무엇인가?

Android Manifest는 모든 안드로이드 앱에 무조건 있어야만 하는 XML파일이다. 이 파일은 안드로이드 빌드 툴이나, 안드로이드 버전 구글 플레이 스토어에 앱에 앱에 대한 정보를 제공한다.

Manifest 파일은 많은 타입의 정보를 포함하고 있다. 그 중 중요한 것들로는 다음과 같다.

  • 패키지 네임
  • 앱의 액티비티, 프레그먼트, 서비스들과 같은 컴포넌트들
  • 유저에게 받아야만 하는 권한들

더 자세하게 공부하기 위해서는 안드로이드 기본 문서를 확인해 보기 바란다.

Gradle 빌드 시스템이란 무엇인가?

안드로이드 스튜디오는 앱을 빌드하기 위해 Gradle을 사용한다. 안드로이드 플러그인 Gradle은 컴파일하고, 빌드하고 앱과 라이브러리를 패키징한다. Gradle 파일들은 또한 의존성과 버전 정보 등을 포함하고 있다.

Gradle 파일들은 Groovy를 파일 작성 언어로 사용한다. 하지만, 2019년부터, 코틀린 프로젝트에서는 코틀린으로 Gradle 파일들을 작성할 수 있게 되었다.

액티비티와 프레그먼트가 무엇인가?

액티비티는 앱에서 유저가 이용할 수 있는 하나의 단위를 말한다. 액티비티는 UI요소가 위치하는 윈도우를 만든다.프레그먼트는 액티비티 내 기능상으로 작은 부분을 말한다.

2018년부터, 안드로이드는 단독 액티비티 앱을 만들기를 추천한다. 하나의 액티비티에 여러개의 프레그먼트들로 구성된 앱으로 제작하는 것을 말한다.

액티비티 라이프싸이클이란 무엇인가?

액티비티 라이프싸이클(생명주기)은 앱이 화면에 보이냐 안 보이냐와 깊은 관계가 있다. 액티비티를 시작하면 onCreate()가 호출되고 이때 여러가지 초기화 작업이나 재생성됐을 시 데이터를 복원하는 일을 한다. 그 다음 on Start()부터 사용자에게 화면이 보이기 시작하고, onResume()를 거치면 액티비티가 정상 출력되고 실행중인 것으로 간주한다.

홈키를 누르거나 다른 앱으로 화면이 전환되면 장치 화면에서 액티비티가 사라지고 onPause(), onStop()이 호출된다. 그 후, 원래 액티비티 화면으로 다시 돌아오면 onRestart()가 실행되고, 그렇지 않으면 안드로이드 시스템에 의해 액티비티가 종료되고, 재생성 시 onCreate()가 다시 호출된다.

더 깊은 공부를 하기 원한다면 액티비티 라이프사이클에 대한 안드로이드 공식 문서를 읽어보는 것을 추천한다.

설정 변경이란 무엇이고 언제 일어나게 되는가?

설정 변경(Configuration Changes)은 안드로이드가 액티비티를 재생성하게 만든다. 스크린 방향, 키보드 설정의 변경, 멀티 윈도우 모드등으로 진입 되는 것을 설정 변경이라한다. 설정 변경이 일어나게 되면 onDestroy()가 호출되고, 그 후 onCreate() 다시 호출되게 된다. 설정 변경에 대해서 지원하고 액티비티 재생성 시, 데이터를 잃지 않게 하는 것도 중요하다.

디자인

새로운 앱을 제작하게 되면, UI 디자인에 대해서 깊은 고민을 하게 될 것이다. 안드로이드는 material design과 quality design에 대한 가이드라인을 제공하고 있다. 이 가이드라인을 따라 유저의 기대에 부응하고 시각적 일관성, 네비게이션성을 고려한 앱을 제작하는데 도움을 줄 것이다.

  • Material Design이란 무엇인가?
    Material Design은 구글이 2014년에 제작한 디자인 가이드, 디자인 원칙이다. UI 컴포넌트들에 대한 제작 블록등을 포함하고 있다. 안드로이드 뿐만 아니라 다른 앱에도 적용가능하다

    구글은 Material Design에 대한 디테일한 가이드를 공식 문서에서 제공하고 있다. 앱을 제작하는데 가이드를 잘 활용하길 바란다.
  • Quality 가이드라인이란 무엇인가?
    구글은 또한 광범위한 퀄리티 가이드라인을 제공한다. 이 리스트를 사용해서 앱이 최신의 퀄리티 기준에 적합한지 확인할 수 있다. 이 테스트를 패스한다면, 앱이 성능, 안정성, 보안성에 대한 유저의 기대를 충족시키고 있다고 볼 수 있다.

    퀄리티 가이드라인에 대한 안드로이드 공식 문서를 확인 할 수 있다.

다양한 스크린 사이즈를 위한 리소스는 어떻게 관리하는가?

안드로이드 장치는 다양한 사이즈와 해상도로 출시된다. 앱을 개발할 때, 어떠한 모델들을 지원할지 결정하는 것이 중요하다. 일단 결정하게 되면, 모든 스크린 사이즈들의 지원을 하기 위해 아래와 같은 3개의 접근법이 있다.

  1. 뷰의 치수 값을 사용 (dp, sp, pt, px, mm ,in 등)
  2. 스크린 사이즈에 따라 여러개의 레이아웃을 만든다.
  3. 이미지와 리소스를 비트맵으로 준비한다.

물론 위의 접근법을 하나가 아니라 함께 사용할 수도 있다. 더 자세한 내용은 안드로이드 개발 사이트의 다양한 스크린 사이즈를 지원 문서를 읽어보기 바란다.

안드로이드에서 레이아웃(Layout)이란 무엇인가?

Layout은 앱의 UI 구조를 정의한 것을 말한다. View와 ViewGroup 객체들이 구조적으로 구성되어 있다. Layout은 다양한 타입이 있다.

  1. Constraint Layout
  2. Linear Layout
  3. Relative Layout

“무엇을 어디에 위치한다” 같은 제약(조건) 사항(Constraint)을 부여해서 원하는 레이아웃을 구성하는 Constraint Layout, 수직이나 수평의 직선 방향으로(Linear) 구조적으로 레이아웃을 구성하는 Linear Layout, 대상의 상대적인(Relative) 위치에 따라 레이아웃을 구성하는 Relative Layout를 사용해서 원하는 뷰를 만들어 낼 수 있다.

RecyclerView란 무엇인가?

대부분의 앱은 적어도 하나의 RecyclerView를 가지고 있다. RecyclerView는 안드로이드 SDK에서 제공되는 위젯이다. 한 화면에 꽉 차지 않고 스크롤링이 필요한 데이터들의 리스트를 화면에 표시하는데 사용한다.

RecyclerView Adapter란 무엇인가?

RecyclerView Adapter(적용시켜주는 것)는 각각의 ViewHolder에 어떤 데이터를 어떻게 적용하는지에 대한 소스코드로 구성되어 있다.

RecyclerView의 리스트 표시를 위해 어떤 레이아웃이 사용가능한가?

RecyclerView를 생성할 때, 아래의 레이아웃 타입에서 선택할 수 있는 권한이 있다.

  1. Linear Layout
  2. Grid Layout

Linear Layout은 데이터 리스트를 수직이나 수평의 방향으로 스크롤 되게 하고, Grid layout은 데이터를 격자(Grid) 형태로 표시하는 것을 말한다.

Support Libraries란 무엇인가?

안드로이드 Support Libraries는 최신 버전의 안드로이드에 추가된 기능을 이전 버전의 안드로이드에서도 사용할 수 있도록 지원(Support)하는 소스코드의 패키지를 말한다. 대부분의 Support Libraries는 이제 androidx의 일부분으로 통합되었다. 대부분의 경우에 구글은 androidx를 사용하기를 추천하고 있다.

Intent란 무엇인가?

Intent는 다른 컴포넌트로부터 액션을 수행시키는 의도(Intent)를 전달하는 메시지 오브젝트를 말한다. 타겟 컴포넌트는 서비스와 액티비티를 포함한다.

Explicit Intent (명시적 인텐트)

명시적 인텐트는 정확한 타겟을 특정하는 인텐트를 말한다. 인텐트를 외부의 앱으로도 전달 가능하다. 하지만 대체로 명시적 인텐트는 앱 내의 컴포너트를 타겟으로 한다. 명시적 인텐트를 사용할 때, 타겟 앱의 이름이나 앱 내 컴포넌트들을 명확하게(Explicitly) 지정해야한다.

Implicit Intent (암시적 인텐트)

암시적 인텐트는 타겟 컴포넌트를 명확하게 특정하지 않는다. 대신에, 수행할 액션에 대해서만 표시한다. 안드로이드 시스템은 그 인텐트를 요구하는 액션 수행이 가능한 외부 앱에게 전달한다. 예를 들어, 앱이 이메일을 전송해야 한다면, 안드로이드 시스템은 장치에 설치된 이메일 전송이 가능한 앱을 리스트로 표시할 것이다. 유저는 원하는 것을 선택하고 안드로이드 시스템은 인텐트를 그 앱으로 전달할 것이다.

현지화(Localization)란 무엇인가? 안드로이드에서 어떻게 구현하는가?

현지화(Localization)란 앱이 다양한 언어, 타임존, 화폐, 숫자 형식 등을 지원하는 것을 말한다. 현지화는 앱을 다양한 나라들의 사람들에게 출시할 수 있게 해준다. 앱은 현지화 리소스를 안드로이드의 리소스 디렉토리 프레임워크를 사용해서 문자열, 이미지, 레이아웃 등을 저장하고 해당하는 유저들이 사용할 수 있게 해준다.

안드로이드 Jetpack이란 무엇인가?

Android Jetpack은 2018년에 출시된 컴포넌트 라이브러리, 도구, 가이드라인을 모두 포함한 개발도구이다. Jetpack의 라이브러리들은 현재 사용되는 모든 안드로이드 장치들에서 사용할 수 있는 소스코드를 제공한다. 기존의 Support Libraries, Architecture Components들을 모두 합쳐서 4개의 카테고리로 구성되어 있다.

JetPack 라이브러리는 안드로이드 SDK에 포함되지 않고 별개로 제공되는 라이브러리이다. JetPack으로 변경되면서,기존에 사용하던 Support Libraries 등의 라이브러리들은 전부 androidx.*로 이동하였다.

build.gradle 파일을 살펴보면 이미 JetPack의 저장소 google()이 추가되어 있는 걸 볼 수 있다.

allprojects {
    repositories {
        google()
        jcenter()
    }
}

원하는 컴포넌트들을 추가하려면 앱 모듈 build.gradle 파일에 아래와 같은 형태로 붙여넣으면 된다.

dependencies {
   ...
   implementation 'androidx.appcompat:appcompat:1.1.0'
   ...
}

Android Architecture 컴포넌트란 무엇인가?

2017 구글 I/O에서, 구글은 앱을 좀 더 모듈화시켜서 관리와 테스트가 편하도록 만든 안드로이드 Architecture 컴포넌트들을 소개했다. 아래의 아키텍쳐 컴포넌트 라이브러리들은 앱을 설계하고 UI에 표시되는 데이터들을 관리하기 쉽도록 도와준다. 대부분의 라이브러리들은 이미 존재하던 것이었지만 Navigation, Paging, WorkManager은 새로 추가되었다.

  1. Data Binding
  2. Lifecycles
  3. LiveData
  4. Navigation
  5. Paging
  6. Room
  7. ViewModel
  8. WorkManager

1. Data Binding — Data Binding 라이브러리는 데이터를 XML의 레이아웃에 대입하도록 도와준다. 이 라이브러리를 사용하는데 가장 큰 이점은 데이터가 변할 때마다 자동적으로 UI를 업데이트 한다는 것이다.

2. Lifecycles — 메모리 누수와 안드로이드 라이프사이클 관련된 문제들을 해결하기 위한 라이브러리 모음이다. 라이프사이클 라이브러리는 액티비티와 프레그먼트의 라이프사이클의 변경이 일어날 때 대응한다.

3. LiveData — LiveData는 라이프사이클을 감지하고 있는다. 즉, 액티비티, 프레그먼트, 서비스 등의 라이프사이클을 준수한다는 것이다. 이 라이브러리를 쓰면 자동 UI 업데이트가 가능하다.

4. Navigation — 앱 디자인에서 가장 중요한 포인트 중 하나는 Navigation이다. 이 라이브러리를 이용해서 유저들이 앱 내에서 자유롭게 이동할 수 있도록 해준다.

5. Paging — 많은 양의 데이터를 점진적으로 적절하게 RecyclerView에 로드하기 위해서 이 라이브러리를 사용한다.

6. Room — SQLite에 하나의 추상적인 레이어를 제공하는 라이버러리 모음이다. 앱에서 SQLite 사용을 쉽게 하고 불필요한 소스코드를 줄일 수 있게 도와준다.

7. ViewModel — View Model은 모든 UI 관련 데이터를 저장하고 관리하기 위해서 만들어졌다. 그리고 또한 데이터가 유실되지 않도록 스크린 방향, 멀티 스크린 등의 설정 변경(configuration changes)의 상황에서도 유지되도록 만든다.

8. WorkManager — Workmanager는 작업 시간의 기회와 보장이 필요한 백그라운드 작업을 위해서 존재한다.

다른 기타 라이브러리들

안드로이드 세상에 있으면, Jetpack 이외의 무수히 많은 라이브러리를 마주치고 될 것이다. 다음 리스트는 당신이 알고 있어야할 가장 많이 사용되는 라이브러리들이다.

  1. 네트워크 리퀘스트를 위한 라이브러리들: Retrofit, GraphQL
  2. 뷰에 이미지 표시를 위한 라이브러리: Picasso
  3. 의존성 주입을 위한 라이브러리: Dagger
  4. 비동기적 데이터흐름 프로그래밍을 위한 라이브러리: RXJava와 RXKotlin

안드로이드에서 테스트는 어떻게 체계화하는가?

안드로이드 스튜디오 프로젝트를 생성하면 테스트를 위해 2개의 디렉토리를 생성한다.

  1. test 디렉토리는 로컬 유닛(unit) 테스트를 저장하는 곳이다. 이 테스트들은 JVM에서 실행된다.
  2. android 디렉토리는 실제 장치들에서 실행되는 테스트를 저장하는 곳이다. 이 디렉토리는 통합적인 테스트나 end-to-end 테스트 같이 다른 종류의 테스트를 위해 사용할 것이다.

유닛(Unit) 테스트란 무엇인가? 안드로이드에서 어떻게 수행하는가?

유닛 테스트는 로컬에서 실행된다. 장치에서 실행되는 것이 아니기 때문에, 안드로이드 프레임워크 라이브러리에 접근이 불가능하다. 물론 테스트 라이브러리를 사용해서 유닛 테스트에서 안드로이드 프레임워크 라이브러리를 호출하는 게 가능하다. 하지만 이 테스트 라이브러리는 장치를 시뮬레이션 하는 것이기 때문에 실제 장치와는 다를 수 있다. 테스트 라이브러리는 JUnit이나 Mockito가 주로 사용된다.

  • JUnit은 유닛 테스트를 위한 스탠다드 자바 라이브러리이다. 대체로 AndroidX Test와 연결되어 사용된다.
  • Mockito는 효율적으로 테스트를 작성할 수 있는 유명한 오픈 소스 테스트 프레임워크이다.

인스트루먼트(Instrumentation) 테스트

인스트루먼트(Instrumentation) 테스트는 유닛 테스트와 비슷하지만 장치나 시뮬레이터에서 실행하는 것을 말한다. 인스트루먼트 테스트는 장치에 실행되므로, 안드로이드 장치의 라이브러리에 대한 접근이 가능하다. 위에서 언급한 두개의 라이브러리, JUnit과 Mockito는 인스트루먼트 테스트를 위해서도 사용된다.

UI 테스트

UI 테스트는 유저가 UI와 상호작용하는 걸 시뮬레이션 한다. 이걸로 가장 유명한 라이브러리는 Espresso이다.

코틀린 관련

다음으로 알아볼 것은 기본 안드로이드 프로그래밍 언어 코틀린에 대한 것이다. 최근의 프로젝트들은 대부분의 코틀린으로 개발되고 있다. 그리고 많은 수의 앱들이 지속적인 앱의 관리를 위해 코틀린으로 다시 개발하고 있다.

코루틴(Coroutines)이란 무엇인가?

코루틴은 연속해서 실행되는 비동기 콜백들을 순차적인 실행으로 변환시키는 코드 부분들을 말한다. 안드로이드와 코틀린에서 비동기 프로그램을 훨씬 더 쉽게 만들어준다.

코루틴 관련 부분은 범위가 너무 커 별도의 글로 더 자세히 다루겠다.

동반자 객체(Companion Objects)란 무엇인가?

동반자 객체(Companion Objects)란 한 파일 내에서 클래스와 같은 이름을 가지는 객체를 말한다. 클래스의 객체들보다는 클래스 자체에 포함되는 함수나 속성들을 가지고 있다. 다른 언어들에서 static 멤버들과 비슷하다.

class MainFragment : Fragment(R.layout.fragment_main) {
  
  companion object {
        private const val TAG = "MainFragment "
    }
}

언제 Nullable을 사용하는가?

코틀린은 null이 될 수 있는 변수, 될 수 없는 변수들을 명확하게 구별한다. 이 기능이 null 참조로 인해서 발생하는 에러를(예를 들면, null pointer exception) 피하게 도와준다. 이 에러들은 다른 언어들에서 매우 흔하게 발생하는 것이다.

아래는 null이 될 수 없는 변수다.

var myVar: Int = 77
myVar = null // 컴파일 에러

그리고 아래가 null이 될 수 있는 변수다.

var myVar: Int ? = 77
myVar = null

‘?’ 심볼이 바로 변수를 nullable로 만드는 것이다.

타입 체크는 어떻게 하는가?

타입 체크를 위해 is 연산자를 사용한다. 그리고 그 반대가 !is 이다. 이 연산자들은 boolean 값을 리턴한다. 어떠한 연산을 수행하기 전에 넘겨진 값의 타입을 체크하는게 좋다.

if (myVar is Int) {
    myVar++; 
}

if (myVar !is Int) { 
    throw Exception("myVar는 Int 타입이 아니다!")
}

Switch 구문은 어떻게 구현하는가?

코틀린에서는 switch 대신에 when을 사용한다.

when (name) {
    "Jonathan Cho" -> print("안녕하세요 주인님!!")
    else -> print("주인님이 아닙니다")
}

Lambda란 무엇인가?

람다는 함수이지만 선언된 것이 아니라 표현으로 바로 전달되는 것을 말한다.

val multiply = {x : Int, y : Int ->  x * y} // -> 을 기준으로 왼쪽이 인자, 오른쪽이 함수 바디 겸 리턴값을 의미 마지막 코드가 반환 값으로 지정

print(multiply(10, 20))

// 실행 결과
200

매우 간결하게 사용할 수 있다. 그리고 다른 함수의 인자로 함수 자체를 전달할 수도 있다.

클래스 확장(Class Extension)이란 무엇인가?

클래스 확장이란 개념은 많은 프로그래밍 언어에 존재한다. 단어가 의미하는 것처럼, 클래스의 기능을 확장한다.

아래는 Int 클래스를 확장하는 코드이다. Int 클래스에 multiply라는 함수를 추가한다.

fun Int.multiply(y : Int): Int {
  return this * y
}
    
print(3.multiply(3))

// 실행 결과
9

범위(Range)란 무엇인가?

range는 수학에 나오는 범위와 아주 똑같다. 작은 숫자에서 큰 숫자로 가는 숫자들의 그룹을 말한다.

for( i in 1..10 ) print(i)

// 실행 결과
12345678910

범위는 두개의 점 ‘..’로 표시한다. 값이 올라가는 것 대신에 내려가려면 downTo 키워드를 쓰면 된다.

for( i in 10 downTo 1  ) print(i)

// 실행 결과
10987654321

데이터 클래스란 무엇인가?

코틀린에서 데이터 클래스는(data class)는 특수한 타입의 클래스로 데이터를 저장하기 위해서만 사용한다. 아래 예제에서 보이는 것처럼 클래스 이름과 속성들만을 정의하면 쉽게 데이터 클래스를 선언할 수 있다.

data class Person(val name: String)

코틀린은 최소한의 코딩으로 getter와 setter는 물론이고, 기본적인 기능 equals, hashCode, toString, copy들을 바로 사용할 수 있게 만들어준다.

객체 지향 프로그래밍

안드로이드 개발자로서 객체 지향 프로그래밍 기법을 이용해서 코드를 작성할 것이다. 몇가지 기본적인 사항만 짚고 넘어가자.

캡슐화(Encapsulation)란 무엇인가?

캡슐화는 객체 지향 프로그래밍의 아주 기본적인 컨셉이다. 오브젝트를 그것만의 속성, 상태, 연산을 가지도록 하나의 캡슐에 싸서 만드는 것을 말한다. 이건 코드를 간단하게 만들 뿐만 아니라 데이터 무결성에도 큰 영향을 미친다.

캡슐로 싸여진 오브젝트는 외부에서 접근할 수 있도록 최소한의 정보만을 제공한다. 이것이 정보 은닉에 도움이 된다. 또한 캡슐화는 다른 오브젝트들과의 디커플링(결합이 풀어지는 것)이 가능하게 한다. 한 오브젝트에서 소스코드 변경일 일어날 시, 다른 오브젝트에도 영향을 미쳐 변경을 해야 된다면 좋은 구조로 짜여진 코드가 아니다. 오브젝트들을 각각 하나의 독립적인 요소로 만들고 서로간의 의존성을 줄이는 것이 객체지향 프로그래밍의 기본이다.

상속(Inheritance)이란 무엇인가?

객체 지향 프로그래밍에서 상속이란 자식 객체가 부모 객체의 속성, 메소드 등을 물려받는 것을 말한다. 예를 들어, 부모 객체가 View이고, 자식 객체가 ImageView라면, 자식 객체는 View라는 기본 속성, 메소드들을 물려받아 그대로 사용해서 코드의 중복을 줄이고 빠르게 개발할 수 있다. 그리고 View의 기본 속성이 변경하여도 소스코드 단에서 ImageView를 변경할 필요가 없다. ImageView는 이미지 표시에 관한 부분만을 추가하면 된다.

다형성(Polymorphism)이란?

단어 다형성(Polymorphism)은 여러가지 형태를 갖는 것을 말한다. OOP에서, 다형성의 가장 일반적인 정의는 하나의 인터페이스나 클래스를 여러가지 형태로 구현하는 것을 말한다. 두가지 타입이 있는데, 동적(dynamic)과 정적(static) 타입이다.

동적 다형성(dynamic polymorphism)은 컴파일 타임에는 어떤 요소가 결정될 지 모르고 런타임에 결정되는 것을 말한다. 반대로 정적 다형성(static polymorphism)은 컴파일 타임에 결정되는 것을 말한다. 아래는 동적 다형성의 예로 메소드 overriding, 정적 다형성의 예로 메소드 overloading에 대해 설명할 것이다. 참고로, 동적 다형성(dynamic polymorphism), 정적 다형성(static polymorphism)은 추상적인 컨셉을 의미하는 단어이므로 overloading, overriding과 동일시 해서 이해해서는 안된다.

fun main() {
    open class MyClass() {
        open fun myFuncHello(name: String) : Unit {
          println("Hello $name! from MyClass")
        }
    }
    
    class DerivedMyClass(): MyClass(){
        override fun myFuncHello(name: String) : Unit {
          println("Hello $name! from DerivedMyClass")
        }
    }
    
    var derivedMyClass = DerivedMyClass()
    derivedMyClass.myFuncHello("Jonathan")
    var myClass = derivedMyClass;
    myClass.myFuncHello("Jonathan")
}

// 실행 결과
Hello Jonathan! from DerivedMyClass
Hello Jonathan! from DerivedMyClass

myClass.myFuncHello(“Jonathan”) 부분은 MyClass 클래스의 함수를 호출한 것처럼 보이지만, DerivedMyClass 클래스의 함수가 호출된다. 이것을 method overriding이라고 부르고 이러한 컨셉을 동적 다형성이라고 부른다.

class MyClass() {
        fun myFuncHello(name: String) : Unit {
          println("Hello $name! (with name)")
        }
        fun myFuncHello(name: String, nickname: String) : Unit {
          println("Hello $nickname $name! (with name, nickname)")
        }
        fun myFuncHello(name: String, nickname: String, from: String) : Unit {
          println("Hello $nickname $name from $from! (with name, nickname, from)")
        }
    }
    
    var myClass = MyClass();
    myClass.myFuncHello("Jonathan")
    myClass.myFuncHello("Jonathan", "The Handsome")
    myClass.myFuncHello("Jonathan", "The Handsome", "SF, USA")

// 실행 결과
Hello Jonathan! (with name)
Hello The Handsome Jonathan! (with name, nickname)
Hello The Handsome Jonathan from SF, USA! (with name, nickname, from)

같은 이름을 가진 함수이지만 위에 myFuncHello 함수들은 컴파일러에 의해 서로 다른 함수로 해석이 된다. 이처럼 컴파일러에 의해서 컴파일 타임에서 요소가 결정이 되는 컨셉을 정적 다형성이라고 부르고, 이것은 구체적으로 method overloading이라고도 부른다.

마치면서..

이 글을 통해서 안드로이드 개발자로서 가지고 있어야할 정말 최소한의 지식에 대해서 한번 알아봤다. 아주 간략히 알아보았기 때문에 조금 더 깊게 공부하기 위해서는 다른 자료를 더 참고하기 바란다. (특히 코틀린 부분은 다음 게시글을 통해 다룰 예정이다.)

본문에 대한 의견이나 질문이 있을 시 댓글에 남겨주기 바란다.

댓글 남기기