
코틀린 교육이 끝나고 과제 평가가 있을 예정(프로젝트폴더 압축파일제출)
오늘까지 배운 내용을 토대로 문제가 나옴
B클래스가 A클래스를 상속받고
B타입의 변수 b1에 B클래스의 인스턴스를 담으면 -> 변수 a,b, 메서드 a,b 모두 사용 가능
A타입의 변수 a1에 B클래스의 인스턴스를 담으면 -> 변수 a, 메서드 a 만 사용 가능
자식클래스(B)에서 부모클래스(A)의 메서드를 오버라이딩하고 추후 생성한 자식클래스 객체에서 해당 메서드를 호출하면 부모클래스의 메서드가 아닌 자식클래스의 메서드가 호출됨
오버라이딩을 안한 경우에는 원래대로 부모클래스(A)의 메서드가 호출됨
부모클래스의 메서드 내용을 호출하고 싶으면 super를 통해 접근가능
override fun superMethod2(){
// 만약 부모의 메서드를 호출하고자 한다면 super를 통해 접근한다.
super.superMethod2()
println("SubClass1의 superMethod2")
}
안드로이드OS(과거시점)
안드로이드APP(미래시점)
프로그램마다 동작하는 코드가 다름
안드로이드OS는 프로그램코드에 짜인 메서드의 이름을 알아야지 메서드 호출이 가능함
1. 안드로이드OS가 알고있는 이름으로 메서드를 호출하던가
2. 안드로이드OS가 알 수 있게 이름을 알려줘야 함(어떤 파일에 기록해서 OS가 읽을 수 있게)
코틀린을 동작시키는 VM에서 처음 실행하는 코드가 main()함수로 정해져있음
프로그래머는 main()함수를 만들어서 VM이 해당 함수를 실행할수있게 해주는 것임
보통 자바계열에서는 1번 방법으로 함
버튼을 만들 때
안드로이드OS가 버튼 클래스를 만들고 클릭 메서드를 정의해둠
안드로이드OS에서는 버튼 클릭을 감지할 수 있게 대기하다가 클릭이 감지되면 메서드를 호출할 수 있게 해줌
안드로이드앱을 만들면서 해당 클래스를 상속하고 클릭 메서드를 오버라이딩한 객체를 생성해주면 객체 주소값이 안드로이드 OS에 전달됨
안드로이드 OS는 전달받은 객체 주소값을 통해 실제 앱에 있는 메소드를 호출할 수 있음
앱사용자가 버튼을 클릭하면 안드로이드OS에서는 클릭 메서드를 호출
Kotlin에서 사용하는 모든 클래스의 부모 클래스
모든 클래스는 부모 클래스가 존재함(명시되지 않은 클래스의 경우 Any클래스)
코틀린은 클래스를 작성할 때 상속받지 않는다면 자동으로 Any클래스를 상속받는다
자바 Object -> 코틀린 Any
Any 클래스에는 모든 객체가 가지고 있어야할 메서드가 제공되고 있으며 이 메서드를 Overriding하여 각 클래스의 성격에 맞게 재구현하여 사용할 수 있다.
코틀린에서 모든 클래스는 Any를 상속받기 때문에 모든 객체는 Any 타입 변수에 담을 수 있다.
fun main() {
// 코틀린에서 모든 클래스는 Any를 상속받기 때문에 모든 객체는
// Any 타입 변수에 담을 수 있다.
val a1:Any = TestClass1()
val a2:Any = TestClass2()
println("a1 : $a1")
println("a2 : $a2")
}
// 상속 관계를 설정하지 않았지만 Any를 상속받는다.
class TestClass1
class TestClass2
a1 : TestClass1@cbd64252
a2 : TestClass2@24e84fc1
class TestClass3{
// toString 메서드 구현
// toString : 객체를 문자열로 변환하는 의미의 메서드
// 객체의 주소값을 가지고 있는 변수를 출력하면 toString 메서드가 호출되고
// 여기서 반환하는 문자열을 출력해준다.
override fun toString(): String {
// return super.toString()
return "TestClass3을 통해 만든 객체입니다"
}
}
fun main(){
val t3 = TestClass3()
println("t3 : $t3 ")
}
t3 : TestClass3을 통해 만든 객체입니다
class TestClass3(var a1:Int, var a2:Int){
override fun toString(): String {
// return super.toString()
// 강사는 객체가 가지고 있는 property들의 값을 출력해보는 코드를 넣어놓습니다.
println("a1 : $a1")
println("a2 : $a2")
return "TestClass3을 통해 만든 객체입니다"
}
}
fun main(){
val t3 = TestClass3(100,200)
println("t3 : $t3 ")
}
a1 : 100
a2 : 200
t3 : TestClass3을 통해 만든 객체입니다
fun main() {
val t1 = TestClass1()
t1.testMethod1(200)
}
class TestClass1{
// 프로퍼티
var value1 = 100
// 매개변수
fun testMethod1(value1:Int){
println("value1 : $value1")
}
}
value1 : 200
fun main() {
val t1 = TestClass1()
t1.testMethod1(200)
}
class TestClass1{
// 프로퍼티
var value1 = 100
// 매개변수
fun testMethod1(value1:Int){
// 프로퍼티의 이름과 매개변수의 이름이 같을 경우
// 매개변수를 사용한다.
println("value1 : $value1")
// 프로퍼티의 이름과 매개변수의 이름이 같은 경우
// 매개변수가 아닌 프로퍼티를 사용하겠다면
// this를 통해 객체에 접근해 사용하면 된다.
println("this.value1 : ${this.value1}")
}
}
value1 : 200
this.value1 : 100
fun main() {
val t2 = TestClass2()
println("t2 : $t2")
}
class TestClass2{
// this() : 다른 생성자를 호출한다.
// 만약 클래스에 주 생성자가 정의되어 있다면 무조건 주 생성자를 반드시 호출하도록 해야 한다.
constructor() : this(100){
println("매개 변수가 없는 생성자 호출")
}
constructor(a1:Int){
println("매개 변수가 있는 생성자 호출")
println("a1 : $a1")
}
}
매개 변수가 있는 생성자 호출
a1 : 100
매개 변수가 없는 생성자 호출
t2 : TestClass2@3ab9d975
fun main() {
val t1 = TestClass1()
t1.testMethod2()
}
class TestClass1{
...
// 코틀린은 메서드(외부) 안에 메서드(내부)를 만들 수 있다.
// 메서드(외부)내의 메서드(내부)는 메서드(외부)에서만 사용이 가능하다.
fun testMethod2(){
fun innerMethod1(){
println("innerMethod1 호출")
}
innerMethod1()
}
}
innerMethod1 호출
fun main() {
val t1 = TestClass1()
t1.testMethod2()
}
class TestClass1{
...
fun testMethod2(){
fun innerMethod1(){
println("innerMethod1 호출")
}
innerMethod1()
// 클래스의 멤버 메서드와 동일한 메서드를 내부에 만들어준다.
fun testMethod3(){
println("testMethod2 메서드의 내부 메서드 testMethod3")
}
// 메서드 내부에 만든 메서드가 호출된다.
testMethod3()
// 만약 멤버 메서드를 호출하고 싶다면 this를 이용하여 호출한다.
this.testMethod3()
}
fun testMethod3(){
println("TestClass1의 testMethod3")
}
}
testMethod2 메서드의 내부 메서드 testMethod3
TestClass1의 testMethod3
fun main() {
val sub1 = SubClass1()
sub1.subMethod1(300)
}
open class SuperClass1{
// 자식 클래스에서 동일한 이름의 프로퍼티를 만드는 것을 허용하겠다면 open 을 붙여줌
open var superValue1 = 100
}
class SubClass1 : SuperClass1(){
// 부모 클래스에 정의된 프로퍼티와 동일한 이름의 프로퍼티를 만들고자 한다면
// 부모가 가지고 있는 프로퍼티 중에 open 프로퍼티만 가능하며
// 앞에 override 키워드를 붙여줘야 한다.
override var superValue1 = 200
fun subMethod1(superValue1:Int){
// 매개변수 사용
println("superValue1 : $superValue1")
// 매개변수의 이름과 프로퍼티의 이름이 같기 때문에 프로퍼티에 접근하려면
// this 를 사용해야 한다.
// 만약 동일명의 매개변수가 없다면 this 는 생략 가능
println("this.superValue1 : ${this.superValue1}")
// 매개변수의 이름이나 프로퍼티의 이름이 부모의 프로퍼티 이름과 동일할 경우
// super를 통해 부모의 프로퍼티에 접근한다.
println("super.superValue1 : ${super.superValue1}")
}
}
superValue1 : 300
this.superValue1 : 200
super.superValue1 : 100
fun main() {
val sub1 = SubClass1()
sub1.subMethod2()
}
open class SuperClass1{
...
// 자식 클래스에서 메서드를 재구현(overriding)을 허용하겠다면 open 을 붙여준다.
open fun superMethod2(){
println("SuperClass1의 superMethod2")
}
}
class SubClass1 : SuperClass1(){
...
// 부모 클래스의 메서드를 overriding 한다.
override fun superMethod2() {
println("SubClass1의 superMethod2")
}
fun subMethod2(){
superMethod2()
// 부모의 메서드를 자식에서 재구현한 경우 부모의 메서드를 호출하고자 한다면 super를 사용
super.superMethod2()
}
}
SubClass1의 superMethod2
SuperClass1의 superMethod2
fun main() {
val sub1 = SubClass1()
}
open class SuperClass1{
...
// 생성자
constructor(){
println("SuperClass1의 생성자")
}
constructor(a1:Int){
println("매개 변수를 가지고 있는 SuperClass1의 생성자")
println("a1 : $a1")
}
...
}
class SubClass1 : SuperClass1{
...
// 코틀린의 모든 클래스는 생성자에서 부모 클래스의 생성자 호출을 명시하지 않으면
// 자동으로 부모의 생성자 중 매개변수가 없는 생성자가 호출된다.
// 만약 호출되는 부모의 생성자를 명시적으로 지칭하겠다면 super를 사용한다.
constructor() : super(1000){
println("SubClass1의 생성자 호출")
}
...
}
매개 변수를 가지고 있는 SuperClass1의 생성자
a1 : 1000
SubClass1의 생성자 호출
EX13에서 운동부별로 입출력메서드 이름이 달랐는데
오버라이딩을 통해 메서드를 동일하게 통일시켜줌
EX14에서 동물별로 입출력메서드 이름이 달랐는데
오버라이딩을 통해 메서드를 동일하게 통일시켜줌
fun main() {
// 추상 클래스의 객체 생성
// 추상 클래스는 완벽한 클래스가 아니기 때문에 객체를 생성하는 것이 불가능하다.
// val t1 = TestClass1() // 에러남
// 추상 클래스를 상속 받은 클래스의 객체를 생성한다.
val sub1 = SubClass1()
sub1.testMethod1()
sub1.testMethod2()
sub1.testMethod3()
}
// 추상 클래스는 abstract 키워드를 붙혀줘야 한다.
// 추상 클래스는 상속이 가능해야 하기 때문에 open 키워드를 붙혀줘야 한다.
open abstract class TestClass1{
fun testMethod1(){
println("TestClass1의 testMethod1")
}
fun testMethod2(){
println("TestClass1의 testMethod2")
}
// 추상 메서드
// 추상 메서드는 추상 메서드임을 알리기 위해 abstract 라는 키워드를 붙여줘야 한다.
// 추상 메서드는 overriding이 가능해야 하기 때문에 반드시 open을 붙혀줘야 한다.
open abstract fun testMethod3()
}
// 추상클래스를 상속받은 클래스
class SubClass1 : TestClass1() {
// 추상 메서드 구현
override fun testMethod3() {
println("SubClass1에서 구현한 testMethod3")
}
}
TestClass1의 testMethod1
TestClass1의 testMethod2
SubClass1에서 구현한 testMethod3
fun main() {
val t1 = SubClass1()
val t2 = SubClass2()
testFunction1(t1)
testFunction2(t2)
}
// 추상 클래스
abstract class AbstractClass1{
abstract fun abstractMethod1()
}
abstract class AbstractClass2{
abstract fun abstractMethod2()
}
// 객체의 주소값을 받아 메서드를 호출하는 함수
fun testFunction1(t100:AbstractClass1){
t100.abstractMethod1()
}
fun testFunction2(t200:AbstractClass2){
t200.abstractMethod2()
}
// 코틀린(자바 포함)에서는 단일 상속만 지원되기 때문에 여러 클래스를 상속 받을 수 없다.
// class SubClass1 : AbstractClass1(), AbstractClass2() // 에러
// 추상 클래스 하나당 하나의 자식클래스를 만들어줘야 한다.
class SubClass1 : AbstractClass1(){
override fun abstractMethod1() {
println("SubClass1의 abstractMethod1")
}
}
class SubClass2 : AbstractClass2(){
override fun abstractMethod2() {
println("SubClass2의 abstractMethod2")
}
}
SubClass1의 abstractMethod1
SubClass2의 abstractMethod2
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
fun main() {
val t10 = TestClass10()
testFunction3(t10)
testFunction4(t10)
}
// 인터페이스
interface Inter1{
fun interfaceMethod1()
}
interface Inter2{
fun interfaceMethod2()
}
fun testFunction3(inter1:Inter1){
inter1.interfaceMethod1()
}
fun testFunction4(inter2:Inter2){
inter2.interfaceMethod2()
}
// 인터페이스를 구현한 클래스
class TestClass10 : Inter1, Inter2{
override fun interfaceMethod1() {
println("TestClass10의 interfaceMethod1")
}
override fun interfaceMethod2() {
println("TestClass10의 interfaceMethod2")
}
}
TestClass10의 interfaceMethod1
TestClass10의 interfaceMethod2
fun main() {
// 일반 멤버 프로퍼티는 객체를 생성할 때 마다 계속 생성된다.
val t1 = TestClass1(100)
val t2 = TestClass1(200)
println("t1.a1 : ${t1.a1}")
println("t2.a1 : ${t2.a1}")
t1.a1 = 1000
println("t1.a1 : ${t1.a1}")
println("t2.a1 : ${t2.a1}")
}
class TestClass1{
// 일반 멤버 프로퍼티
var a1:Int
constructor(a1:Int){
this.a1 = a1
}
}
t1.a1 : 100
t2.a1 : 200
t1.a1 : 1000
t2.a1 : 200
fun main() {
// 정적 멤버는 객체를 생성하지 않고 사용한다.
// 클래스명.멤버이름
println("TestClass1.a2 : ${TestClass1.a2}")
// 정적 멤버는 객체를 통한 접근이 불가하다.
val t1 = TestClass1(100)
val t2 = TestClass1(200)
// println("t1.a2 : ${t1.a2}") //에러
// println("t2.a2 : ${t2.a2}") //에러
}
class TestClass1{
// 일반 멤버 프로퍼티
var a1:Int
// 정적 멤버 정의
companion object{
// 정적 멤버 프로퍼티
var a2:Int = 100
}
constructor(a1:Int){
this.a1 = a1
}
}
TestClass1.a2 : 100
fun main() {
TestClass1.testMethod2()
}
class TestClass1{
// 일반 멤버 프로퍼티
var a1:Int
// 정적 멤버 정의
companion object{
// 정적 멤버 프로퍼티
var a2:Int = 100
// 정적 멤버 메서드
fun testMethod2(){
// 정적 프로퍼티 사용
println("testMethod2 - a2 : $a2")
}
}
constructor(a1:Int){
this.a1 = a1
}
}
testMethod2 - a2 : 100
class TestClass1{
// 일반 멤버 프로퍼티
var a1:Int
// 정적 멤버 정의
companion object{
// 정적 멤버 프로퍼티
var a2:Int = 100
// 정적 멤버 메서드
fun testMethod2(){
// 정적 프로퍼티 사용
println("testMethod2 - a2 : $a2")
// 정적 메서드에서 일반 멤버 프로퍼티를 사용할 경우.
//println("testMethod2 - a1 : $a1") // 에러
//println("testMethod2 - a1 : ${this.a1}") // 에러
// 정적 멤버는 객체를 생성하지 않아도 사용할 수 있다.
// 이제, 정적 멤버 입장에서는 객체가 생성되었지 않을 가능성, 객체가 여러개가 만들어져있어
// 어떤 객체의 멤버인지 확인할 수 없는 등의 여러가지 이유 때문에 일반 멤버 프로퍼티는 사용이 불가하다.
}
}
constructor(a1:Int){
this.a1 = a1
}
}
fun main(){
t1.testMethod1()
}
class TestClass1{
...
// 일반 멤버 메서드
fun testMethod1(){
println("a1 : $a1")
// 일반 멤버 메서드에서는 정적 멤버를 사용할 수 있다.
println("a2 : $a2")
testMethod2()
}
}
a1 : 1000
a2 : 100
testMethod2 - a2 : 100
// JavaMain.java
public class JavaMain {
// 정적 변수
public static int javaValue1 = 100;
// 정적 메서드
public static void javaMethod1(){
System.out.println("JavaMethod1");
}
// 자바 프로그램에서의 시작 메서드
public static void main(String [] args){
}
}
fun main(){
// Java 파일에 정의된 static멤버 사용
// Java 파일에 정의된 정적 멤버 사용은 자유롭게 가능
println("JavaMain.javaValue1 : ${JavaMain.javaValue1}")
JavaMain.javaMethod1()
}
JavaMain.javaValue1 : 100
JavaMethod1
// main.kt
class TestClass2{
companion object {
var kotlinValue1 = 1000
fun kotlinMethod(){
println("kotlinMethod1")
}
}
}
// JavaMain.java
public class JavaMain {
// 자바 프로그램에서의 시작 메서드
public static void main(String [] args){
// 코틀린에서 정의한 companion object의 정적 멤버 사용
int a1 = TestClass2.Companion.getKotlinValue1();
System.out.println("a1 : "+a1);
TestClass2.Companion.kotlinMethod();
}
}
a1 : 1000
kotlinMethod1
※ 출처 : 멋쟁이사자 앱스쿨 2기, 소프트캠퍼스