특정 처리를 위해 관련된 변수, 함수 등을 한꺼번에 모아놓은 프로그램의 단위를 클래스(Class)라고 합니다. Aandroid Studio에서 처음 프로젝트를 생성하고 나면 다음과 같은 코드를 볼 수 있는데 이것은 Android Studio가 onCreate라는 함수를 포함하고 있는 MainActivity라는 클래스를 자동 생성한 것입니다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
이제까지 어떠한 출력을 위해 자주 사용했던 Lod.d() 함수도 Log라는 클래스 안에 있는 d함수를 호출한 것입니다. 이렇듯 관련된 기능의 함수를 클래스라고 하는 단위로 모아 놓으면 코드의 재사용이 용이하고 관리하기도 편리해집니다.
클래스는 다음과 같은 형식으로 사용할 수 있습니다. 최소한의 기본 구조에 해당합니다.
class MyClass {
}
(1) 생성자
Kotlin에서 클래스를 사용하기 위해서는 다음과 같은 방법을 사용해 클래스의 인스턴스를 생성하고 인스턴스를 통해 함수나 속성을 호출합니다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var mc = MyClass() //클래스의 인스턴스 생성
}
}
class MyClass {
}
생성자라는 것은 클래스를 사용하기 위해 인스턴스를 생성할 때 자동으로 실행되는 클래스의 초기화 함수를 의미하며 다음과 같이 init 코드 블록을 만들어 두는 방법으로 생성자 함수를 정의할 수 있습니다.
class MyClass {
init {
Log.d("test", "생성자 함수가 실행됨")
}
}
init 안에서는 클래스가 호출되는 시점(인스턴스가 생성되는 시점)에 초기화에 필요한 작업을 모아두면 됩니다. 만약 별도의 초기화가 필요 없다면 init는 생략될 수 있습니다.
또한 만약 생성자 함수에서 어떠한 값을 받아야 한다면 클래스 옆에 필요한 매개변수를 정의해 두고 매개변수를 통해 전달된 값을 init 함수에서 그대로 받아 사용하면 됩니다.
class MyClass constructor(myvalue: String) {
init {
Log.d("test", "전달값 : ${myvalue}")
}
}
따라서 위와 같이 클래스를 정의하고 나면 클래스의 인스턴스를 생성할 때 필요한 값을 클래스에 전달하는 것입니다.
var mc = MyClass("안뇽")
이때 constructor는 생략할 수 있으며
class MyClass (myvalue: String) {
init {
Log.d("test", "전달값 : ${myvalue}")
}
}
아예 함수와 같은 형태로 클래스 내부에 생성자 함수를 정의하는 경우도 있으니 참고하시기 바랍니다.
(2) 속성과 메서드
우선 현재 함수와 메서드라는 용어를 같이 쓰게 되었는데 이 둘은 다른 것이 아니며 동일한 것임을 말씀드립니다.
클래스는 내부에 수많은 속성과 메서드를 포함할 수 있습니다. Kotilin에서 클래스를 생성할 때 속성은 변수로 구현되며 메서드는 내부 함수를 만드는 것으로 구현할 수 있습니다.
class CarClass {
var color = "red"
fun Drive()
{
Log.d("test", "주행")
}
}
단, 클래스 내부의 함수 안에서 생성된 변수는 함수를 위한 변수일뿐 속성으로 취급되지 않습니다.
class CarClass {
var color = "red"
fun Drive()
{
var speed = 60
Log.d("test", "주행")
}
}
만약 클래스를 사용하는 데 있어서 따로 생성자를 필요로 하지 않는다면 인스턴스 과정을 거치지 않고 곧장 클래스를 사용할 수 있수도 있는데 이때는 클래스 내부를 companion object로 감싸면 됩니다.
class CarClass {
companion object {
var color = "red"
fun Drive() {
var speed = 60
Log.d("test", "주행")
}
}
}
위와 같이 하면 인스턴스는 생성할 수 없으며 클래스명을 그대로 사용해 속성이나 메서드에 접근해야 합니다.
(3) 클래스의 상속
어쩌면 특정 기능의 구현을 위해 많은 수의 클래스를 생성할지도 모릅니다. 하지만 모든 개발자가 똑같은 기능의 구현을 위해 각기 저마다의 클래스를 별도로 생성해야 한다면 개발의 효휼성이 매우 떨어지게 됩니다. 이를 위해 기존에 만들어진 클래스의 기능을 내가 만들 클래스에 붙여 동일하게 사용하고자 하는 개념이 도입되었는데 그것이 바로 클래스의 상속입니다.
클래스를 상속하려면 우선 상속할 대상이 될 클래스가 open키워드로 정의되어 있어야 합니다.
open class parentClass {
fun parentWho() {
Log.d("parent", "parentClass")
}
}
위와 같은 클래스가 있다면 내가 만들 클래스에서 parentClass클래스를 상속받기 위해 다음과 같이 구현할 수 있습니다.
class childClass:parentClass() {
fun childWho() {
Log.d("child", "childClass")
parentWho()
}
}
childClass는 원래 parentWho()라는 메서드를 가지고 있지 않지만 해당 메서드를 가진 parentClass를 상속함으로써 동일한 메서드를 호출할 수 있게 됩니다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var cc = childClass()
cc.childWho()
}
}
open class parentClass {
fun parentWho() {
Log.d("parent", "parentClass")
}
}
class childClass:parentClass() {
fun childWho() {
Log.d("child", "childClass")
parentWho()
}
}
만약 특정 클래스를 상속할 때 상속할 부모 클래스에서 매개변수를 정의해 두고 있다면 상속받을 자식클래스에서도 동일한 형식의 매개변수를 정의해 부모 클래스에 전달해야 합니다.
open class parentClass(parentValue: String) {
var pv = parentValue
fun parentWho() {
Log.d("parent", "${pv}")
}
}
class childClass(childValue: String):parentClass(childValue) {
var cv = childValue
fun childWho() {
Log.d("child", "${cv}")
parentWho()
}
}
반대로 자식 클래스에서만 매개변수가 있고 부모 클래스는 별도의 매개변수가 없다면 굳이 값을 전달할 필요가 없습니다.
open class parentClass {
fun parentWho() {
Log.d("parent", "parentClass")
}
}
class childClass(childValue: String):parentClass() {
var cv = childValue
fun childWho() {
Log.d("child", "${cv}")
parentWho()
}
}
(4) 오버라이드
특정 클래스를 상속받은 자식 클래스에서 부모 클래스의 속성이나 메서드와 동일한 이름으로 다른 동작을 구현하는 것을 오버라이드라고 합니다. 단, 자식클래스에서 부모 클래스의 속성과 메서드를 오버라이드 하려면 해당 속성 혹은 메서드가 open으로 정의되어 있어야 합니다.
open class parentClass {
open var pp: String = "parent"
open fun parentWho() {
Log.d("parent", "parentClass")
}
}
그리고 자식 클래스에서 open으로 된 속성/메서드를 재정의 하는 경우에는 override를 명시해야 합니다.
class childClass:parentClass() {
override var pp: String = "Child"
override fun parentWho() {
Log.d("child", "childClass")
}
}
(5) 접근 제한자
클래스 자체 혹은 클래스 내부에 있는 함수, 변수등을 외부에서 접근할 때 이를 허용할 것인지를 지정하는 것을 접근 제한 자라고 합니다. 위에서 잠깐 봤었던 CarClass를 다시 살펴보겠습니다.
class CarClass {
var color = "red"
fun Drive()
{
Log.d("test", "주행")
}
}
사실 위에 있는 클래스는 아무런 접근제한자도 설정되어 있지 않은 상태인데 코틀린에서는 만약 접근 제한자를 설정하지 않으면 기본적으로 public처리됩니다. public은 외부에서 자유롭게 접근이 가능한 상태를 의미합니다.
그밖에 코틀린에서 사용 가능한 접근 제한자로는 다음과 같은 것들이 있습니다.
private | 외부에서 접근할 수 없습니다. |
internal | 같은 모듈안에서만 접근이 가능합니다. |
protected | 상속했을때 자식클래스에서만 접근이 가능합니다. |
public | 외부에서 자유롭게 접근이 가능합니다. |
internal에서 모듈의 단위가 생소한데, 앱을 만들 때 사용되는 파일 단위를 말하며 앱 하나가 전체적인 하나의 모듈이 됩니다.
class CarClass {
private var color = "red"
protected fun Drive()
{
Log.d("test", "주행")
}
}
클래스를 수정하여 변수는 private로 메서드는 protected로 선언하였습니다. 이렇게 하면 클래스로는 변수나 함수에 접근할 수 없게 됩니다.
다만 protected는 상속을 거치면 자식 클래스 안에서는 접근이 가능합니다.
class ChildCarClass: CarClass() {
fun Go() {
Drive()
}
}
(6) 익스텐션
익스텐션은 기존에 만들어져 있는 클래스에 추가적인 메서드를 부여하는 경우를 말합니다. 예컨대 위에서 사용된 childClass클래스에 childWho라는 메서드를 추가하고자 한다면 단지.(점)을 이용해 추가하고자 하는 메서드를 붙여 주기만 하면 됩니다.
fun childClass.childWho() {
Log.d("child2", "childClass2")
}
이 방법은 새로 정의된 클래스가 아닌 기존에 존재하는 클래스에도 적용이 가능합니다.
fun Int.double(myvalue: Int): Int {
return this * myvalue
}
정수형 변수를 선언할 때 타입으로 지정하는 Int도 엄밀히 하나의 클래스입니다.
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/
여기에 double이라는 메서드를 위에서 처럼 추가하면 다음과 같이 double메서드를 호출할 수 있게 됩니다.
var testvalue: Int = 10;
var rtn = testvalue.double(2)
Log.d("test", "결과값: ${rtn}")
'Mobile > Kotlin' 카테고리의 다른 글
[Kotlin] 추상 클래스와 인터페이스 (0) | 2020.12.10 |
---|---|
[Kotlin] 데이터 클래스 (0) | 2020.12.09 |
[Kotlin] 함수 (0) | 2020.12.08 |
[Kotlin] 배열과 컬렉션 (0) | 2020.12.07 |
[Kotlin] 반복문 (0) | 2020.12.07 |