상속
클래스 이름 뒤에 extends 키워드를 적고 부모클래스 이름을 적게 되면 부모 클래스가 가지고 있는 것을
상속받을 수 있게 된다. 부모가 가진 것을 자식에게 물려주는 것을 의미하며,
즉, 부모가 가지고 있는 것을 자식이 사용할 수 있게 된다.
// Car 를 상속받은 Bus 를 class로 표현하는 방법
public class Car{
}
public class Bus extends Car{
}
// 부모클래스에 메소드 추가하기
// Car에 run()메소드를 추가
public class Car{
public void run(){
System.out.println("달리다.");
}
}
// Bus에 메소드 추가
public class Bus extends Car{
public void ppangppang(){
System.out.println("빵빵");
}
}
// Car를 상속받은 Bus 사용
public class BusExam{
public static void main(String args[]){
Bus bus = new Bus();
bus.ppangppang();
bus.run();
//Bus class는 run 이라는 메소드를 직접 가지고 있지 않아도 Car를 상속받았기 때문에 사용할 수 있다.
}
}
Casting & 객체간 타입 비교(instanceof)
Casting
- up casting : 자식 값을 부모 타입으로 형변환(부모가 자식을 가리키고만 있다.)
- down casting : up casting된 객체를 자식타입으로 형변환
* 부모의 값을 자식 타입으로 형변환시 오류 발생
Casting을 사용하는 이유
모든 자식 값을 전달받기 위해서는 동일한 타입의 저장공간을 받아야 하는데
자식끼리는 서로 타입이 다르기 때문에 한번에 전달 받을 수가 없다.
그래서 up casting을 사용해서 모든 자식을 부모 타입의 저장공간에 한번에 받아준다.
그리고 만약 자식 클래스의 메소드 또는 필드를 사용해야 된다면 다시 down casting을 해서
복구하여 사용한다.
up casting : 다양한 타입을 한번에 관리하기 위해서
down casting : up casting된 자식에서 자식 클래스의 필드나 메소드를 사용해야 할 경우
ex) DieselCar dieselCar = new DieselCar(30, 20, 4, 8, "white", "kia", true); → up casting
Car car = dieselCar; → down casting
DieselCar d = (DieselCar) car; → 형변환
Instanceof
a instanceof A : a가 A타입이라면 true, 아니면 false
public class CastingTest {
public static void main(String[] args) {
// instanceof
// a(객체) instanceof b(클래스) : a와 b가 같은 타입인지 확인
// a가 b타입이면 true, a가 b타입이 아니면 false
Car car = new Car();
DieselCar dieselCar = new DieselCar();
ElectricCar electricCar = new ElectricCar();
// 자식 객체가 부모타입(클래스)을 가지고 있는지
System.out.println(dieselCar instanceof Car); // true
System.out.println(electricCar instanceof Car); // true
// 부모 객체가 자식타입(클래스)을 가지고 있는지
System.out.println(car instanceof DieselCar); // false
System.out.println(car instanceof ElectricCar); // false
// up casting
Car car1 = new DieselCar(30, 10, 4, 5, "blue", "kia", false);
Car car2 = new ElectricCar(30, 10, 4, 5, "white", "tesla", false);
DieselCar dieselCar2 = new DieselCar(30, 10, 4, 5, "red", "kia", false);
Car car3 = dieselCar2;
// Car car3 = new DieselCar(); // 위의 코드와 같은 내용이다.
// System.out.println(car3.currentOil); // 부모가 자식을 가르키고 있지만 형변환을 안 했기 때문에 err가 난다.
// down casting
DieselCar dieselCar3 = new DieselCar(30, 20, 4, 8, "white", "kia", true);
Car car4 = dieselCar3;
// Car car4 = new DieselCar(); // 위의 코드와 같은 내용이다.
DieselCar d = (DieselCar) car4;
d.getCurrentOil(); // 부모가 자식을 가리킨 상태에서 부모값을 자식타입(클래스)으로 형변환 하였기 때문에 출력된다.
Car car5 = new ElectricCar(30, 20, 4, 8, "white", "kia", true);
ElectricCar e = (ElectricCar) car5;
e.getCharge(); // 부모가 자식을 가리킨 상태에서 부모값을 자식타입(클래스)으로 형변환 하였기 때문에 출력된다.
// ElectricCar e2 = (ElectricCar) car; // 부모가 자식을 가리키지 않은 상태에서 바로 형변환을 해서 err가 난다.
}
}
클래스 형변환
부모 타입으로 자식객체를 참조하게 되면 부모가 가지고 있는 메소드만 사용할 수 있다.
부모 타입으로 자식객체가 가지고 있는 메소드나 속성을 사용하고 싶다면 형변환을 해야 한다.
public class Car{
public void run(){
System.out.println("Car의 run메소드");
}
}
public class Bus extends Car{
public void ppangppang(){
System.out.println("빵빵.");
}
}
public class BusExam{
public static void main(String args[]){
Car car = new Bus();
car.run();
car.ppangppang(); // err // 부모타입으로 자식객체를 참조하게 되면 부모가 가지고 있는 메소드만 사용할 수 있다.
Bus bus = (Bus)car; //부모타입을 자식타입으로 형변환
bus.run();
bus.ppangppang();
}
}
접근 권한 제어자
클래스 내에서 멤버의 변수, 메소드, 클래스의 접근 권한을 제어하는 것이다.
- public : 모든 곳에서 접근 가능, 대표 클래스를 의미할 때 사용, 어떤 클래스든 접근할 수 있다는 것을 의미한다.
- default : 다른 패키지에서 접근 불가(별도로 명시하지 않고 접근 권한 제어자 생략시 자동으로 default가 됨), 자기자신과 같은 패키지에서만 접근할 수 있다는 것을 의미한다.
- protected : 다른 패키지에서 접근 불가, 자기 자신, 같은 패키지, 다른 패키지에서 자식 클래스는 허용(상속 되었을 때)한다.
- private : 다른 클래스, 다른 패키지에서 접근 불가, 같은 클래스만 접근 허용한다.
- private : 메소드로만 접근(getter, setter) : 부모 클래스에서 Source -> Generate Getters and Setters
* getter, setter를 한 후에는 상속없이도 다른 패키지, 다른 클래스에서도 허용된다.
package access1;
// 부모 클래스
public class Access1 {
// 필드
int defaultData;
public int publicData;
protected int protectedData;
private int privateData;
// 메소드
void defaultMethod() {
System.out.println("defaultMethod");
}
public void publicMethod() {
System.out.println("publicMethod");
}
protected void protectedMethod() {
System.out.println("protectedMethod");
}
private void privateMethod() {
System.out.println("privateMethod");
}
// getter
public int getPrivateData() {
return privateData;
}
// setter
public void setPrivateData(int privateData) {
this.privateData = privateData;
}
}
package access1;
public class AccessTest1 {
public static void main(String[] args) {
Access1 access1 = new Access1();
// 필드
System.out.println(access1.defaultData);
System.out.println(access1.publicData);
System.out.println(access1.protectedData);
// private = 다른 클래스에서 접근 불가
// System.out.println(access1.privateData);
access1.getPrivateData();
// 메소드
access1.defaultMethod();
access1.publicMethod();
access1.protectedMethod();
// private = 다른 클래스에서 접근 불가
// access1.privateMethod();
}
}
package access2;
import access1.Access1;
// 다른 패키지, 다른 클래스
public class AccessTest2 extends Access1 {
public static void main(String[] args) {
Access1 access1 = new Access1(); // 다른 패키지에서 선언시 import가 되어야 할당된다.
AccessTest2 accessTest2 = new AccessTest2(); // main메소드가 static이기 때문에 부모클래스를 상속을 한 후에 객체화를 새로 해준다.
// 필드
// System.out.println(access1.defaultData);
System.out.println(access1.publicData);
// System.out.println(access1.protectedData);
System.out.println(accessTest2.protectedData); // 다른 패키지에서 접근할 경우 부모클래스를 상속을 받을 경우 허용된다.
// private = 다른 클래스에서 접근 불가
// System.out.println(access1.privateData);
// getter로 getPrivateData의 주소 값만 return 받고 있어서 출력이 안 된다.
access1.getPrivateData();
// getter를 출력하려면 변수명을 새로 할당한 다음 출력한다.
int data = access1.getPrivateData();
System.out.println(data);
// 메소드
// access1.defaultMethod();
access1.publicMethod();
// access1.protectedMethod();
accessTest2.protectedMethod(); // 다른 패키지에서 접근할 경우 부모클래스를 상속을 받을 경우 허용된다.
// private = 다른 클래스에서 접근 불가
// access1.privateMethod();
}
}
추상클래스
구체적이지 않은 클래스를 의미하며, 독수리, 타조는 구체적인 새를 지칭하는데 새, 포유류 같은 것은 구체적이지 않다.
이러한 것을 구현한 클래스를 추상 클래스라고 한다.
- 추상 클래스는 클래스 앞에 abstract 키워드를 이용해서 정의한다.
- 추상 클래스는 인스턴스 및 객체를 생성할 수 없다.
- 추상 메소드는 리턴 타입 앞에 abstract라는 키워드를 붙여야 한다.
- 추상 메소드란, 내용이 없는 메소드이다. 즉 구현이 되지 않은 메소드이다.
- 추상 메소드가 한개 이상있는 클래스는 반드시 추상 클래스로 선언해야 한다.
- 추상 클래스를 상속받고, 추상 클래스가 갖고 있는 추상 메소드를 구현하지 않으면 해당 클래스도 추상 클래스가 된다.
- 추상 클래스를 상속받은 자식 클래스는 반드시 추상 메소드를 재정의(오버라이딩)하여 구현해야
객체화 할 수 있으며, 이러한 강제성을 부여하기 위해 추상 메소드로 선언한다.
추상메소드
ex) abstract void sum();
public abstract class Bird{
// 추상 메소드
public abstract void sing();
// 일반 메소드
public void fly(){
System.out.println("날다");
}
}
// 추상 클래스를 상속받는 클래스 생성하기
public class Duck extends Bird{
@Override
public void sing() {
System.out.println("꽥꽥");
}
}
// 메인 메소드 출력하기
public class DuckExam {
public static void main(String[] args) {
Duck duck = new Duck();
duck.sing(); // 꽥꽥
duck.fly(); // 날다
// Bird는 추상 클래스 이므로 객체를 생성할 수 없다.
// Bird b = new Bird();
}
}'JAVA' 카테고리의 다른 글
| 다른 형식의 클래스 & Marker interface (0) | 2022.11.19 |
|---|---|
| 인터페이스(Interface) (0) | 2022.11.16 |
| 클래스 (0) | 2022.11.06 |
| 메소드 (0) | 2022.10.30 |
| 배열 (0) | 2022.10.23 |