객체지향 프로그래밍
1. 객체지향 프로그래밍
1) 캡슐화 (Encapsulation)
: 데이터와 기능을 하나의 단위(클래스)로 묶어서 활용하는 것.
- 외부의 코드가 내부의 작동 방식을 고려하는 상황 방지
- 객체 내부의 데이터를 외부에서 자유롭게 접근하지 못하도록 하는 정보은닉의 개념까지 포함. (접근 제어자 활용)
2) 상속 (Inheritance)
: 이미 존재하는 클래스를 재활용하여 상속받은 클래스의 기능을 재활용/ 확장할 수 있게 하는 것.
- 자식 클래스가 부모 클래스의 속성과 기능 공유
- 기능을 덮어써서 독자적인 동작 구현
- 코드 재사용성, 확장성 증진
3) 다형성 (Polymorphism)
: 서로 다른 객체가 하나의 공통된 클래스 형태로 취급.
- 메서드 오버로딩 : 같은 이름의 메서드로 여러 기능 활용
- 메서드 오버라이딩 : 같은 메서드가 어떤 객체가 사용하느냐에 따라 기능이 변경
- 인터페이스로 여러 클래스가 같은 인터페이스의 구현체로 인식되게.
- 코드 재사용성, 유연성 증진.
4) 추상화 (Abstraction)
: 실제 기능이 만들어지지 않은 추상클래스와 인터페이스를 바탕으로, 실제 기능을 자식 클래스(Concrete class)에 위임.
- 추상 클래스에 공유된 기능, 개별적 기능 분리
- 인터페이스로 클래스가 가져야 하는 기능 정의
- 코드를 사용하는 입장에서 불필요한 세부사항에 대한 관심 줄이기.
- 코드 복잡성 낮추고 코드 재사용성, 유연성 증진.
2. Inheritance & Composition
- 클래스 생성 시 클래스의 관계를 정리해본다.
ex. 자동차는 엔진을 가지고 있다. (has-a관계)
게시물에는 댓글이 있다.
~~~> 자동차 클래스에 엔진이라는 클래스가 속성으로 가지고 있다. >> 이렇게 작성하는 것을 Composition(구성)이라고 한다.
ex2. 사각형과 원은 일종의 도형이다. (is-a 관계)
고양이와 강아지는 일종의 동물이다.
~~~> 이때 동물이라는 클래스를 만들고, 고양이과 강아지가 동물 클래스를 상속(Inheritance) 받는다. "extends"
~~> 고양이는 일종의 동물이 된다. (동물의 메서드를 사용 가능)
but 반대로 동물이 고양이의 메서드를 사용할 수는 없다.......(?) > 그럴 때에는 Animal을 Cat으로 바꿔주어야 한다.
--> Downcasting 다운캐스팅 : 업캐스팅 되었던 객체를 다시 하위클래스의 자료형을 바꾸어 되돌려 놓는 것.
cf) Upcasting 업캐스팅 : 하위클래스의 정보를 담을 수 있는 객체에 상위클래스의 자료형을 부여해서 상위클래스처럼 사용하게 하는 것. (ex. Animal animal = new Cat(); Cat 객체에 Animal 자료형을 부여함)
ex.
Animal animal = new Cat(); // upcasting
animal.sound();
animal.grooming(); //오류남. 동물인 cat이 Cat의 메서드를 사용할 수 없다. 그럴 때 downcasting
((Cat)animal).grooming();
- 만약 형변환 전에 가능한지 여부 확인하고 싶다면 instanceof 사용
+ instanceof 체크를 하면 객체가 해당 클래스 인스턴스인지 확인이 된 셈이므로 > 직접 downcasting 하지 않고 instanceof에서 임시 변수를 만들 수 있다. (Java 14)
if (animal instanceof Cat) {
((Cat)animal).grooming();
} else {
System.out.println("Can't do that!");
}
혹은
if (animal instanceof Cat cat) {
cat.grooming();
} else {
System.out.println("Can't do that!");
}
* 메서드 오버라이딩
: 상황에 따라 부모 클래스와 자식 클래스의 메서드가 다르게 동작해야 한다면...?
-> 메서드 오버라이딩 하기
- 자식 클래스에서 변경하고 싶은 부모 클래스의 메서드와 동일한 이름, 매개변수, 반환형의 메서드를 만들면 오버라이딩 가능.
- super : 부모 클래스를 나타내는 키워드.
- protected 접근 제어자를 활용해 자식 클래스에서도 부모클래스의 속성/메서드에 접근할 수 있도록 한다.
public void drive(int kilos) { // 부모 클래스의 drive 메서드
this.fuel -= kilos/10;
}
@Override
public void drive (int kilos) { // 자식 클래스에서 drive 메서드 오버라이딩
super.drive(kilos);
fuel -= load/(maxLoad/10);
}
** 추상 클래스 abstract class & 인터페이스 interface
- 명백한 구현이 존재하는 Concrete class (구상클래스)를 상속받으면 > 부모와 자식이 강하게 결합된다... > 좀더 높은 단계의 추상화를 위해 추상클래스와 인터페이스 사용.
1) 추상 클래스
: 구현되지 않은 메서드를 가질 수 있는 클래스.
- 인스턴스 객체를 만들 수 없음. (실제 기능이 없으니까...)
- 여러 클래스의 기본 클래스를 만들고 싶을 때 (공통 기능과 직접 구현 기능 분리.)
- 추상 메서드 : 메서드 바디를 작성하지 않고, 상속 받은 클래스에 구현을 위임하는 메서드. ("내 자식이 되려면 넌 이건 할 줄 알아야해~.") >> 자식 클래스에서 직접 구현.
ex. 사람 (이름) : 인사를 할거지만 누가 하는지에 따라 다르게 하고싶다.
학생 (이름, 전공) (인사)
강사 (이름, 강의 주제) (인사)
>> 이 때 추상 클래스 사람을 만들고 학생, 강사에 따라 인사를 다르게 하는 추상 메서드를 만든다.
// 추상 클래스 Person
public abstract class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
// 추상 메서드
public abstract void sayHello();
}
// Person을 상속받은 Student
public class Student extends Person {
private String major;
public Student(String name, String major) {
super(name);
this.major = major;
}
@Override
public void sayHello() {
System.out.println("안녕하세요. " +
"저는 "+major+"과 "+getName()+"입니다. ");
}
}
// Person을 상속받은 Lecturer
public class Lecturer extends Person {
private String subject;
public Lecturer(String name, String subject) {
super(name);
this.subject = subject;
}
@Override
public void sayHello() {
System.out.println(String.format("Hello, I'm %s, and today we will study %s!",
getName(), subject));
}
}
> 요렇게 하면 학생일 때, 강사일 때 다른 인사방법을 표현할 수 있다~!
2) 인터페이스 (implements 구현하다)
: 상위 클래스가 아닌 특정 기능을 추가하고 싶을 때
- 둘이 큰 관계는 없지만 같은 기능을 하도록 보장하고 싶다면......?
- 변수 없이 구현해야 하는 기능인 추상 메서드의 모음/ 어떤 클래스가 반드시 만들어야 하는 기능.
- Java의 Comparable (인터페이스)을 구현하면 객체간의 비교가 가능.
-> Arrays.sort(배열) > 사용하여 정렬 가능
Person alex = new Student("Alex", 29,"CSE");
Person brad = new Student("Brad", 21,"CSE");
Person joy = new Lecturer("Joy", "computers", 40);
Person eric = new Student("Eric", 25, "MD");
Person[] people = new Person[]{alex, brad, joy, eric};
//배열을 정렬하는 메서드
Arrays.sort(people);
for(Person person: people) {
person.sayHello();
}
// 결과 : 나이순 정렬
3. Object 클래스
: 모든 클래스가 상속받는 클래스
- 객체를 다루기 위해 필요한 메서드가 정의되어 있다. 이 메서드들을 오버라이드해서 의도대로 동작하도록 만들 수 있음.
1) toString()
: 객체를 문자열로 표현한 형태를 반환하는 메서드.
ex. println 메서드
public void println(Object x) {
String s = String.valueOf(x);
if (getClass() == PrintStream.class) {
// need to apply String.valueOf again since first invocation
// might return null
writeln(String.valueOf(s));
} else {
synchronized (this) {
print(s);
newLine();
}
}
}
- toString() 메서드 오버라이딩
public abstract class Person implements Comparable{
// ...
@Override
public String toString() {
return String.format("%s, age: %s", name, age);
}
}
2) equals(Object o)
: 두 객체가 동일한 값을 들고 있는지 판단하고 싶을 때 사용.
cf) ==는 데이터의 값을 기준으로 비교하여서 참조변수는 데이터 주소값을 저장하기 때문에 > 같은 객체여야만 동일하게 인식을 한다.
- 상속 관계의 클래스를 대상으로 구현할 경우 주의 !
// Person.java
@Override
public boolean equals(Object o) {
if (this == o) return true;
// 서로 다른 자식클래스가 일치하게 하고 싶다면
if (!(o instanceof Person person)) return false;
return age == person.age && Objects.equals(name, person.name);
}
// Student.java
@Override
public boolean equals(Object o) {
// 1. 실제로 두 변수의 값(할당된 주소)이 동일하냐
if (this == o) return true;
// 2. null 이거나 둘이 다른 클래스인가
if (o==null || getClass() != o.getClass()) return false;
// 나머지 속성을 비교하자.
Student student = (Student) o;
return Objects.equals(major, student.major);
}
//main
Person alex = new Student("Alex", 20, "CSE");
Person alex2 = new Lecturer("Alex", 20, "OOP");
System.out.println(alex.equals(alex2)); //false
System.out.println(alex2.equals(alex)); // true
3) hashCode()
: 어떤 입력값에 대해서든 일정한 길이의 출력을 돌려주는 함수로 만드는 코드.
- 어떤 객체가 유일한 객체인지 아닌지를 나타내어 빠르게 객체를 찾을 수 있도록 한다.
- equals를 구현했다면 일치관계의 두 객체는 hashCode()의 결과가 같아야 한다.
- equals를 오버라이드 했다면 hashCode()도 같이 오버라이드.
ex) 다운로드한 파일이 정상적인 파일인지 확인하는 Checksum
//Person.java
@Override
public int hashCode() {
return Objects.has(name, age);
}
4) null
: 값이 없음. 아스키코드 0에 대응되어있는 특수한 제어 문자. 객체가 존재하지 않는다는 의미
- 원시타입은 각 타입에 대응하는 기본값이 존재하지만, 참조타입은 실제로 할당할 데이터가 없으므로 null로 할당된다.
- null 확인을 꼼꼼히 하고 확실히 null이 아닌 객체를 사용하기 !!!
'Programming > Java' 카테고리의 다른 글
제너릭 (Generics) (1) | 2023.11.29 |
---|---|
예외처리 (Exception Handling) (1) | 2023.11.28 |
클래스 (Class) (1) | 2023.11.28 |
메서드 (Methods) (1) | 2023.11.23 |
제어문 (Control Statements) (1) | 2023.11.22 |