Java 객체지향 프로그래밍
1. Java 객체지향 프로그래밍 - 상속 (Inheritance)
2. Java 객체지향 프로그래밍 - 메서드 오버라이딩 (Overriding)
3. Java 객체지향 프로그래밍 - 은닉화(Encapsulation) 와 접근 제한자 (modifier)
4. Java 객체지향 프로그래밍 - 싱글톤 패턴 (Singleton)
5. Java 객체지향 프로그래밍 - 다형성 (Polymorphism)
메서드 오버라이딩 (Overrding)
이는 다형성과도 관련된 것이지만, 상속과도 관련이 있습니다.
메서드 오버라이딩은 부모클래스의 메서드를 자식클래스에서 재정의하는 것입니다.
오버라이딩의 조건
1. 메서드 시그니처가 똑같아야 한다. (매개변수 순서도 같아야 함)
2. 접근 제한자의 범위가 부모클래스보다 작으면 안된다.
3. 예외의 범위가 더 크면 안된다.
4. 리턴 타입이 같아야 한다.
package first.subject.m07.inheritance;
public class ChildClass extends ParentsClass {
@Override
public void printLastName() {
this.lastName = "김";
System.out.println("내 성은 " + lastName + " 입니다.");
}
public static void main(String[] args) {
ChildClass c = new ChildClass();
System.out.println(c.eyeColor);
System.out.println(c.hairColor);
c.printLastName();
}
}
예를 들면 이런 것입니다. 미국을 보면 결혼을 하면 성이 바뀌는 경우가 종종 있습니다.
그런 경우 생각해봅시다.
새로운 성을 받고 print() 를 하고싶은데 부모클래스의 printLastName() 을 쓰면 똑같이 출력이 될 것입니다.
그때 재정의를 하고 새로운 출력을 하는 것 입니다.
저렇게 @Override Annotation 을 붙이면 오버라이딩이 되었다는 것입니다.
여기서 Annotation 이라는 것은 컴파일러, JVM, 프레임워크 등이 보는 주석이라고 보시면 됩니다.
소스 코드에 메타 데이터를 삽입하여 라벨링 하여 위같은 것들이 추가작업을 해줍니다.
@Deprecated
: 컴파일러에게 해당 메서드 쓰지말라고 알리는 것
: 취소선이 그인다.
@Override
: 컴파일러에게 해당 메서드는 오버라이딩 된 것이라고 알리는 것
: 반드시 부모 클래스에 선언된 메서드여야 한다.
@SuppressWarnings
: 컴파일러에게 사소한 warning의 경우 신경쓰지 말라고 알리는 것
생성자 오버라이딩
package first.subject.m07.overriding;
public class Super {
private int no;
private String name;
public Super() {}
public Super(int no) {
this.no = no;
}
public Super(String name) {
this.name = name;
}
public Super(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Super [no=" + no + ", name=" + name + "]";
}
}
package first.subject.m07.overriding;
public class Sub extends Super {
private String hello;
public Sub() {}
public Sub(int no, String name, String hello) {
super(no, name);
this.hello = hello;
}
public static void main(String[] args) {
Sub s = new Sub(1, "이름", "안녕하세요.");
System.out.println(s.toString());
}
@Override
public String toString() {
return super.toString() + " Sub [hello=" + hello + "]";
}
}
생성자는 new 다음에 옵니다. new 은 malloc allocation 을 사용합니다.
생성자는 참고로 기본 생성자를 자동으로 생성해줍니다.
만약 생성자를 아무것도 생성하지 않았다면, 이미 기본 생성자가 있는 것입니다.
여기서 기본 생성자란 파라미터가 아무것도 없는 생성자를 이릅니다.
하지만, 생성자를 하나라도 만들었다면 기본 생성자를 만들어줘야합니다.
생성자는 객체를 만들 때, 호출되는 것들로 객체의 멤버변수나 메서드 같은 것들을 초기화하는 역할을 합니다.
여기서 사용되는 this 는 자기자신 멤버를 가리키며, super 는 조상의 멤버를 가르킵니다.
super() 나 this() 은 생성자 젤 위에 하나만 올 수 있습니다. 만약 이들 위에 어떠한 코드라도 있다면 에러가 발생합니다.
명시적으로 super() 를 호출하지 않는 경우 컴파일러가 알아서 super() 를 삽입하여 사용합니다.
즉 아무 클래스도 상속받고 아무런 생성자도 만들지 않았다면, 자동으로 생성되는 기본 생성자에는 Object() 를 호출하는 super() 가 삽입되어 있는 것이죠.
toString 오버라이딩
package first.subject.m07.inheritance;
public class ToString {
private int num = 10;
public static void main(String[] args) {
ToString ts = new ToString();
System.out.println(ts.toString());
}
}
Object 로 인해서 toString() 메서드를 써볼려고 하는데 보면 보고싶은 내용은 안보이고 주소값만 찍힙니다.
사람이 볼 때는 보통 그냥 내용이 보이는게 좋죠? 그래서 이럴 때 toString() 을 오버라이딩해서 사용합니다.
보통 이클립스에서 [Cmd + Option + S] 를 누르면 생성을 하는 패널이 뜹니다.
여기서 toString() 을 누르면 자동으로 메서드를 생성해줍니다. 혹은 자기자신이 만들수도 있습니다.
package first.subject.m07.inheritance;
public class ToString {
private int num = 10;
@Override
public String toString() {
String str = this.num + " 입니다요.";
return str;
}
//@Override
//public String toString() {
// return "ToString [num=" + num + "]";
//}
// @Override
// public String toString() {
// return getClass().getName() + '@' + Integer.toHexString(hashCode());
// }
public static void main(String[] args) {
ToString ts = new ToString();
System.out.println(ts.toString());
}
}
이렇게 오버라이딩을 해서 사용하면 원하는 출력을 만들 수 있습니다.
equals 오버라이딩
equals 도 Object 에서 가져온 메서드입니다. 이는 두 객체가 같은지 비교를 할 때 사용합니다.
보통 String 객체와 많이 쓰죠?
package first.subject.m07.inheritance;
public class Equals {
private int no;
private String name;
// @Override
// public boolean equals(Object obj) {
// return this == obj;
// }
public static void main(String[] args) {
Equals eq1 = new Equals();
Equals eq2 = new Equals();
eq1.name = "hello";
eq1.no = 1;
eq2.name = "hello";
eq2.no = 1;
System.out.println(eq1.equals(eq2));
}
}
no 과 name 이 같은 두 객체를 만들었습니다.
하지만 equals() 메서드로 같은지 확인을 해보니 false 로 다르다고 나옵니다.
왜일까요? 왜냐하면 각각의 객체의 고유한 주소값이 다르기 때문입니다.
저렇게 주석처리한 메서드처럼 == 의 연산자를 사용하여 비교를 하기 때문에 주소값이 달라 두 객체가 다르다고 나옵니다.
하지만 우리가 원하는 것은 내용이 같으면 객체도 같다고 말해주는 것입니다.
따라서 보통 equals() 객체 또한 오버라이딩을 해서 사용합니다.
package first.subject.m07.inheritance;
public class Equals {
private int no;
private String name;
// @Override
// public boolean equals(Object obj) {
// return this == obj;
// }
@Override
public boolean equals(Object obj) {
if (obj != null && obj instanceof Equals) {
Equals eq = (Equals) obj;
if (this.no == eq.no && this.name.equals(eq.name)) return true;
}
return false;
}
public static void main(String[] args) {
Equals eq1 = new Equals();
Equals eq2 = new Equals();
eq1.name = "hello";
eq1.no = 1;
eq2.name = "hello";
eq2.no = 1;
System.out.println(eq1.equals(eq2));
}
}
이런식으로 다운캐스팅을 하고 하나하나 비교하여 사용을 합니다.
물론 이것도 [Cmd + Option + S] 를 누르면 자동으로 생성해줍니다.
hashCode 오버라이딩
객체의 해시코드란, 시스템 에서 객체를 구별하기 위해 사용되는 정수 값입니다.
HashSet, HashMap 에서 객체의 동일성을 확인하기 위해서 사용됩니다.
즉, Set 같은 경우는 중복을 허용치 않습니다. 이러한 것을 어떻게 구분을 할까요?
바로 equals() 와 hashCode() 를 이용해서 구분을 합니다.
s1.equals(s2) && (s1.hashCode() == s2.hashCode())
따라서 equals() 을 재정의한다면, hashCode() 도 같이 재정의해야합니다.
이클립스에서 옵션으로 재정의할 때, 두 개가 같이 재정의되는 것을 확인할 수 있습니다.
package first.subject.m07.inheritance;
import java.util.Objects;
public class HashCode {
private int no;
private String name;
@Override
public int hashCode() {
return Objects.hash(no, name);
}
public static void main(String[] args) {
HashCode hc = new HashCode();
System.out.println(hc.hashCode());
}
}
Objects.hash() 를 이용해서 멤버변수들을 통해서 고유한 해시코드를 생성해냅니다.
super 키워드
this 로 멤버변수나 멤버메서드에 접근했듯이 super 키워드를 이용해서 부모(조상) 클래스 멤버에 접근할 수 있습니다.
따라서 super 를 통해서 코드를 재사용할 수 있게 됩니다.
package first.subject.m07.inheritance;
public class ChildClass extends ParentsClass {
private String lastName = "염";
@Override
public void printLastName() {
System.out.println("성이 변경되었습니다.");
System.out.println("내 성은 " + lastName + " 입니다.");
System.out.println("내 전의 성은 " + super.lastName + " 입니다.");
}
public static void main(String[] args) {
ChildClass c = new ChildClass();
System.out.println(c.eyeColor);
System.out.println(c.hairColor);
c.printLastName();
}
}
이런식으로 super 키워드를 이용해서 조상 클래스의 멤버에 접근이 가능합니다.
super. 이렇게 되면 멤버 변수나 메서드에 접근하게 되는 것이고
super() 이렇게 되면 생성자에 접근 하게 되는 것입니다.
package first.subject.m07.inheritance;
public class ChildClass extends ParentsClass {
private String lastName = "염";
@Override
public void printLastName() {
String lastName = "염김";
System.out.println("성이 변경되었습니다.");
System.out.println("내 성은 " + lastName + " 입니다.");
System.out.println("내 성은 " + this.lastName + " 입니다.");
System.out.println("내 전의 성은 " + super.lastName + " 입니다.");
}
public static void main(String[] args) {
ChildClass c = new ChildClass();
System.out.println(c.eyeColor);
System.out.println(c.hairColor);
c.printLastName();
}
}
super의 scope 는 사용된 위치에서 점점 확장하여 선언부와 연결이 됩니다.
# java toString # java equals # java hashCode
'🧑💻 𝗣𝗿𝗼𝗴𝗿𝗮𝗺𝗺𝗶𝗻𝗴 > Java' 카테고리의 다른 글
Java 객체지향 프로그래밍 - 싱글톤 패턴 (Singleton) (0) | 2022.07.31 |
---|---|
Java 객체지향 프로그래밍 - 은닉화(Encapsulation) 와 접근 제한자 (modifier) (0) | 2022.07.31 |
Java 객체지향 프로그래밍 - 상속 (Inheritance) (0) | 2022.07.31 |
Java 기본 클래스를 찾거나 로드할 수 없습니다 + java.lang.UnsupportedClassVersionError 오류 해결 (0) | 2022.07.25 |
Java Eclipse 프로젝트 빨간 느낌표 뜨는 오류 해결 (0) | 2022.07.25 |