POJO 클래스를 활용 하여 많이 사용
아래에서 사용할 POJO 예시
public class PojoClass {
String textData;
int numberData;
public String getTextData() {
return textData;
}
public void setTextData(String textData) {
this.textData = textData;
}
public int getNumberData() {
return numberData;
}
public void setNumberData(int numberData) {
this.numberData = numberData;
}
}
하지만 위의 예시 처럼 클래스를 정의하여 사용한다면 아래의 문제점들이 있음
데이터를 표현하는 toString() 메소드의 불명확성
public class JavaMain {
public static void main(String[] args) {
PojoClass pojoClass = new PojoClass();
pojoClass.setNumberData(100);
pojoClass.setTextData("text");
System.out.println(pojoClass); // PojoClass@6b884d57
}
}
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
toString() 함수를 통해 변환 됨toString() 함수는, 클래스의 이름과 해당 객체의 hash 값으로 이루어 져 있어 해당 객체에 대한 정보 ( 아래의 예에선 numberData / textData 에 대한 정보 )를 유추 할 수 없음두 객체가 같은지에 대한 함수 정의 필요
public class JavaMain {
public static void main(String[] args) {
PojoClass pojoClass = new PojoClass();
pojoClass.setNumberData(100);
pojoClass.setTextData("text");
PojoClass otherPojoClass = new PojoClass();
otherPojoClass.setNumberData(100);
otherPojoClass.setTextData("text");
System.out.println(pojoClass.toString()); // PojoClass@1be6f5c3
System.out.println(otherPojoClass); // PojoClass@6b884d57
System.out.println("is it equal two instance = " + (pojoClass == otherPojoClass)); // false
System.out.println("is it equal two instance = " + (pojoClass.equals(otherPojoClass))); // false
}
}
pojoClass 객체와, otherPojoClass 객체는 객체 속 데이터들이 모두 동일== / equals()
자바 == 연산
== 연산인 경우, 두 객체의 값이 동일 한 지 검사== 연산인 경우, 두 객체의 주소 값이 같은지 검사자바 equals() 연산
== 연산자가, 두 객체의 주소 값이 같은지를 검사하고 값이 같은지를 보장 하지 않으므로 equals() 메소드를 활용하여 두 객체의 값이 같은지를 검사equals() 메소드를 활용하는 이유도 이와 같음equals() 메소드는 overiding 될 수 있으며, 일반 클래스에서 overiding 되지 않았을 시 object 클래스에 있는 equals 메소드를 그대로 사용// Object class
public boolean equals(Object obj) {
return (this == obj);
}
equals() 메소드를 overiding 하지 않았음pojoClass.equals(otherPojoClass) 는 object의 equals를 그대로 사용하므로 false따라서, PojoClass의 두 객체에 있는 모든 값이 같은지를 검사하려면, equals 함수를 overide 해서 사용해야 한다
== / equals()
== 연산
== 연산은, 내부적으로 equals 를 호출하여 객체의 값을 비교 함=== 연산
== 와 같은 역할import java.util.Objects;
public class PojoClassEqual extends PojoClass {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PojoClassEqual pojoClass = (PojoClassEqual) o;
return numberData == pojoClass.numberData && Objects.equals(textData, pojoClass.textData);
}
}
public class JavaMain {
public static void main(String[] args) {
PojoClassEqual pojoClassEqual = new PojoClassEqual();
pojoClassEqual.setNumberData(100);
pojoClassEqual.setTextData("text");
PojoClassEqual otherPojoClassEqual = new PojoClassEqual();
otherPojoClassEqual.setNumberData(100);
otherPojoClassEqual.setTextData("text");
System.out.println(pojoClassEqual.toString());
System.out.println(otherPojoClassEqual);
System.out.println("is it equal two instance = " + (pojoClassEqual == otherPojoClassEqual)); // false
System.out.println("is it equal two instance = " + (pojoClassEqual.equals(otherPojoClassEqual))); // true
}
}
equals() 가 정의 되어 있고, 객체의 타입과 객체 속 모든 값이 같다면 true를 반환 하기 때문에, pojoClassEqaul 객체와, otherPojoClassEqaul 객체는 동일하다고 판단hashCode() 함수에 대한 없음
equals() 함수를 정의한 클래스에서, hashCode() 함수는 정의 되지 않음hashCode() 함수가 정의 되지 않아, hash함수를 먼저 비교하는 hashSet 등의 클래스에서 해당 객체를 다룰 때 문제가 있을 수 있음public class PojoClassEqualHashCode extends PojoClassEqual {
@Override
public int hashCode() {
return textData.hashCode() * 31;
}
}
import java.util.HashSet;
public class JavaMain {
public static void main(String[] args) {
PojoClassEqualHashCode pojoClassEqualHashCode = new PojoClassEqualHashCode();
pojoClassEqualHashCode.setNumberData(100);
pojoClassEqualHashCode.setTextData("text");
PojoClassEqualHashCode otherPojoClassEqualHashCode = new PojoClassEqualHashCode();
otherPojoClassEqualHashCode.setNumberData(100);
otherPojoClassEqualHashCode.setTextData("text");
HashSet<PojoClassEqualHashCode> hashSetWithHashCode = new HashSet<>();
hashSetWithHashCode.add(otherPojoClassEqualHashCode);
System.out.println(hashSetWithHashCode.contains(otherPojoClassEqualHashCode)); // true
}
}
Data를 갖고 있기 위한 클래스
DataClass를 생성하기 위해선 아래의 조건을 반드시 따라야 함
val 또는 var 로 선언 되어야 함abstract, open, sealed, inner 클래스가 될 수 없음Data를 위한 기본적인 기능, 함수들을 제공 해 줌
data class User(val name: String, var age: Int)
val user = User(name = "rams", age = 29)
위 처럼 data class를 선언 시, 아래의 함수들을 기본적으로 제공 해 줌
Property Get / Set
// Get property 확인
println("----Get property 확인----")
println(user.age) // 29
println(user.name) // rams
// Set property 확인
println("----Set property 확인----")
user.age = 30 // val 로 선언된 property 에서는 Compile error ( var / val 차이 )
println(user) // User(name=rams, age=30)
user.age = 29
println(user) // User(name=rams, age=29)
toString
// toString 함수 확인
println("----toString 함수 확인----")
println(user) // User(name=rams, age=29)
println(user.toString()) // User(name=rams, age=29)
equals
// equals 함수 확인
println("----equals 함수 확인----")
val sameUser = User(age = 29, name = "rams")
val otherUser = User(age = 20, name = "rams")
println(user == sameUser) // true
println(user == otherUser) // false
println(user === sameUser) // false
hashCode()
// hashCode 확인
println("----hashCode 확인----")
val hashSet = mutableSetOf<User>()
hashSet.add(user)
println(user.hashCode() == sameUser.hashCode()) // true
println(hashSet.contains(sameUser)) // true
Component N
// ComponentN 확인
println("----ComponentN 확인----")
println(user.component1()) // rams
println(user.component2()) // 29
destructuring declarations
// destructuring declarations 확인
println("----destructuring declarations 확인----")
val (name, age) = user
println(name) // rams
println(age) // 29
val (ageTest) = user
println(ageTest) // rams
// Compile error
// val (name, age, error) = user
copy
// copy 확인
println("----copy 확인----")
val copiedUser = user.copy(name = "RAMS")
val sameCopiedUser = user.copy()
println(copiedUser) // User(name=RAMS, age=29)
println(user == copiedUser) // false
println(user == sameCopiedUser) // true
println(user.hashCode() == sameCopiedUser.hashCode()) // true
println(user === sameCopiedUser) // false
Inheritance
equals / hashCode / toString 함수 등을 final 키워드를 붙여 override 하면, 부모 클래스에서 override한 함수를 그대로 사용 ( 자동 생성 해주지 않음 )data class User(val name: String, var age: Int) : UserSuperClass()
open class UserSuperClass {
final override fun equals(other: Any?): Boolean {
return super.equals(other)
}
final override fun hashCode(): Int {
return super.hashCode()
}
final override fun toString(): String {
return super.toString()
}
}
----Get property 확인----
29
rams
----Set property 확인----
User@2f2c9b19
User@2f2c9b19
----toString 함수 확인----
User@2f2c9b19
User@2f2c9b19
----equals 함수 확인----
false
false
false
----hashCode 확인----
false
false
----ComponentN 확인----
rams
29
----destructuring declarations 확인----
rams
29
rams
----copy 확인----
User@1c20c684
false
false
false
false
Process finished with exit code 0
Interface / Abstract class
fun sampleCodeForInterface() {
val duck = Duck("Donald", 123)
duck.cry() // Quack
val dog = Dog("Snoopy", 3000)
dog.cry() // Bow
val penguin = Penguin("Peng", 13)
penguin.eat() // Nyam
penguin.somethingNormal
}
abstract class AbstractAnimal {
abstract fun cry()
}
interface Animal {
fun cry()
}
open class AnimalClass {
val somethingNormal = "somethingNormal"
fun eat() {
println("Nyam")
}
}
data class Duck(val name: String, val age: Int): AbstractAnimal() {
override fun cry() {
println("Quack")
}
}
data class Dog(val name: String, val age: Int): Animal {
override fun cry() {
println("Bow")
}
}
data class Penguin(val name: String, val age: Int): AnimalClass() {
}
// 데이터 클래스 끼리의 상속은 안됨 ( open keyword 가 안붙음 )
data class ParentAnimal(val name: String, val age: Int)
// Function 'component1' generated for the data class conflicts with member of supertype 'ParentAnimal'
//data class Dog(val firstElement: String): ParentAnimal()