본문 바로가기
Kotlin

Kotlin11. interface, abstract, Singleton

by 히예네 2023. 8. 13.
728x90
반응형

1. interface

인터페이스 :  클래스에 준비되어야할 프로퍼티나 메소드를 정의해둔것

클래스와 다르게 메소드에는 구체적인 기능을 쓰는게 아니다! 

메소드는 이름만 갖고있다. (이 이름으로 통일할꺼야! ) 

 

(자바에서는 implement로 구현된다. kotlin에서는 : 으로 가져온다. 상속과 똑같음) 

 

인터페이스는 다중구현이 가능하다. (클래스는 다중상속이 불가능하다.) 

 

인터페이스를 받은 클래스는, 인터페이스에 준비되어있는 프로퍼티나 메소드를 오버라이드해서 사용해야한다. 

fun main() {
   val me = Person("고양이", "cat@cat.cat")
   val you = Student("갈색푸들")
   val he = Person("코코")
   val she = Student("테나아",30)
   val data : Array<Human> = arrayOf<Human>(me,you,he,she)
       for (ob in data)
       ob.say()
}

interface Human {
    val name : String
    fun say() //이름만 있고 기능은 없는 추상메소드
}

class Person : Human{
    override var name : String
    var mail : String
    
    constructor (name : String =  "이름없음", mail : String = "메일없음"){
      this.name = name
      this.mail = mail
    }	
    
    override fun say(){
        println("name : $name , mail : $mail ")
    }
}

class Student : Human{
    override var name : String
    var grade : Int
    
    constructor (name : String = "이름없음", grade : Int = 1){
        this.name = name
        this.grade = grade
    }
    
    override fun say(){
        println("name : $name , grade : $grade ")
    }
}
//output
name : 고양이 , mail : cat@cat.cat 
name : 갈색푸들 , grade : 1 
name : 코코 , mail : 메일없음 
name : 테나아 , grade : 30

Student / Person class 둘 다 Human을 implement하고 있다. 

전혀 다른 class이지만 인터페이스를 이용하여서,  배열로 묶고 출력하였다.

   val data : Array<Human> = arrayOf<Human>(me,you,he,she)
       for (ob in data)
       ob.say()

Array<Human> 을 보면, 인터페이스인 Human이 class처럼 들어가있다. 인터페이스는 class처럼 기능한다!

 

Array<Human>은 Human 인터페이스를 끼워넣은것을 보관하는 배열을 만들수있게되었다. 

=> 즉! Human을 끼워넣은 class라면 전부 보관가능하다는 얘기임. (class Person : Human  /  class Student : Human)

인터페이스를 쓰면 상속받지 않은 클래스를 한번에 묶어서 다룰수있다. 

 

2. SAM interface  (Single Abstract Method) 

SAM 인터페이스는 오직 한개의 메소드만 준비해둔다. 

자바나 코틀린에서는 SAM 인터페이스를 자주보게된다.

통상 인터페이스를 탑재한 class를 정의하고, 그 객체를 사용하는게 많다. 

그리고 메소드가 1개뿐이라서 인터페이스를 이용하기 위해 쓰는 코드가 인터페이스 본체보다 더 긴 경우도 있다. 

 

(1) 파라미터가 1개일때

fun main() {
	val a = Human { println("Hello $it !")}
    a.say("cat")
    
    val b = Human { println("안녕하세요 $it !")}
    b.say("고양이")
}

fun interface Human{
    fun say(name : String)
}
//output
Hello cat !
안녕하세요 고양이 !

Human 인터페이스를 어떤식으로 탑재하는가..?  {   } 를 이용한다. 

	val a = Human { println("Hello $it !")}
    val b = Human { println("안녕하세요 $it !")}

Human 뒤의 { } 람다식이다. (함수라는것임~)

즉, {  } 안에 들어가는 함수가 그모습 그대로 Human 인터페이스의 say( ) 메소드로써 탑재된 class가 on demand로 생성되고, 

그 객체가 반환되어 변수에 대입되는것임. 

(그 인터페이스를 탑재한 클래스의 객체를 만들어서 작업하게 되는 형식임)

파라미터가 하나라면 it으로 통일된다. 

 ※SAM 인터페이스에서는 파라미터 디폴트값을 설정불가

 

(2) 파라미터가 복수일때 

fun main() {
	val a = Human {
        name: String, age : Int ->
        println("Hello $name , $age !")}
    a.say("cat",1)
    
    val b = Human { 
        name: String, age : Int ->
        println("안녕하세요 $name , $age !")}
    b.say("고양이",5)
}

fun interface Human{
    fun say(name : String, age : Int)
}

//output
Hello cat , 1 !
안녕하세요 고양이 , 5 !

 

3.추상클래스 

추상클래스는 추상메소드를 갖고있는 클래스이다. 

(=> 인터페이스는 메소드 탑재를 강제한다. 이것과 비슷한게 추상클래스이다. ) 

추상클래스를 상속 받으면, 그 안에 있는 추상메소드를 반드시 오버라이드해야한다. 

 

클래스를 만드는 이유는? 객체를 만들고 그 클래스안에 적혀있는 기능을 쓰려고

기본클래스 new해서(자바에서는.. 코틀린은 아님) 객체를 만듬

 

추상클래스 : 객체를 new 해서(자바에서는.. 코틀린은 아님)  만드는 목적이 없음. 

 

※추상메소드 : 강제화된 이름을 정할때 쓰는것. 모두 다 say()라고 이름을 강제화 시킴 ! 이름 규격화

제품의 규격을 만드는중~

fun main() {
	val h = Person("안녕") 
    h.say()
    
    val a = Student("학생")
    a.say()
}

abstract class Human(name : String){
    var name = name
    abstract fun say()
}

class Person(name:String) : Human(name){
    override fun say(){
        println("Hello $name")
    }
}
class Student(name : String) : Human(name){
    override fun say(){
        println("안녕 $name")
    }
}
//output
Hello 안녕
안녕 학생

Person과 Student는 Humam 추상메소드를 상속받았다. (추상클래스도 일반클래스랑 똑같은 방법으로 상속받는다.)

추상클래스에는 추상메소드 말고 다른게 써져있는 경우도 있다. 이거는 오버라이드 할 필요는 없다.

 

4. 데이터 클래스

data class save(var name : String, var age : Int)

주생성자로써 사용되고, 동시에 그대로 프로퍼티로써 객체안에 값으로도 보관 가능하다.


fun main() {
	val h = Attr("안","@com")
    say(h)
}

data class Attr(val name : String, val mail : String, val age : Int = 0)

fun say(attr : Attr){
    println("""
    name : ${attr.name}, 
    ${attr.mail}, 
    ${attr.age}  """)
}

// output
name : 안, 
@com,
0

 

5. Object 클래스

클래스에는 객체를 만들지않고 , 클래스에서 직접 메소드를 부를 수 있다. kotlin에서는 이것을 object라는 것으로 부른다. 

오브젝트는 객체를 만들지 않고, 클래스에서 직접 프로퍼티나 메소드를 불러낸다.

fun main() {
	Human.set("고양이",10)
    Human.say()
}

object Human {
    var name : String = ""
    var age : Int = 0
    
    fun set(name : String, age : Int){
        this.name = name
        this.age = age
    }
    
    fun say(){
        println("$name $age 살")
    }
}
//output
고양이 10 살

set함수는 이미 존재하는 name, age에 다른 값을 셋팅할 수 있는 함수이다.

name과 age를 받고나면 순서대로 say( ) 를 출력할때 적용되고, main함수에서는 최종값을 불러오게 된다. 

※val human = Human( ) 이라 쓰면 에러가 난다. 

 

6. 싱글톤과 동반객체(Companion object)

클래스 중에서는 , 얼마나 객체를 만들어도 그 값이 항상 일정하게 얻어지는것이 있다. 이걸 싱글톤이라고 부른다.

=> 객체를 1개만 만드는 것이다! 특정 클래스의 객체가 오직 하나만 생성된다. 

 

동반객체는 클래스 내부에서 정의되는 객체이다. 싱글톤과 같은 효과를 갖고있음

 

fun main() {
	Human.set("켄수",23)
    var x = Human()
    x.say()
    
    var y = Human()
    y.say()
}

class Human {
    fun say(){
        println("안녕 나는 ${Human.name} 이고 ${Human.age}살이야")
    }
    
    companion object{
        var name = ""
        var age = 0
        
        fun set(name : String, age : Int){
            this.name = name
            this.age = age
        }
    }
}
//output
안녕 나는 켄수 이고 23살이야
안녕 나는 켄수 이고 23살이야

Human.name과 Human.age는 객체로 만들어진게 아니라 class안에 있는거다

 fun say(){
        println("안녕 나는 ${Human.name} 이고 ${Human.age}살이야")
    }

7. 열거형 클래스 (enum class) 

몇 개 열거된 것중에 하나를 고른다. 

fun main() {
	val t = Human.banana
    val s = Human.valueOf("apple")
    println(t)
    println(s)
}

enum class Human {banana, orange, apple}

//output
banana
apple

 

valueOf는 파라미터에 지정된 텍스트를 기준으로 값을 설정한다. 

fun main() {
	val t = Human.a
    val h = Human.a2
    val s = Human.valueOf("a3")
    println(t)
    println(h.label+h.age)
    s.show()
}

enum class Human (val label : String, val age : Int){
    a("1번",0),
    a2("2번",1),
    a3("3번",2);
    
    fun show(){
        println("<<${this} ${this.name} ${this.age}>>")
    }
}
//output
a
2번1
<<a3 a3 2>>
728x90
반응형