클래스 내에서 멤버의 접근을 제한하는 역할
public class AccessObj{
private int i = 1;
int k = 2; // default 접근 제한자
public int p = 3;
protected int p2 = 4;
}
public class AccessObjExam{
public static void main(String args[]){
AccessObj po = new AccessObj();
System.out.println(po.i); // 컴파일 오류 발생(private)
System.out.println(po.k);
System.out.println(po.p);
System.out.println(po.p2);
}
}
구체적이지 않은 클래스를 의미 ex) 독수리, 타조 등은 구체적인 새를 지칭하는 것인데 새, 포유류 같은 것은 구체적이지 않음
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 b = new Bird(); -> 추상 클래스여서 객체를 생성할 수 없다
}
}
class가 인스턴스화 될때 생성자가 실행되면서 객체의 초기화를 한다. 그 때 자신의 생성자만 실행이 되는것이 아니고, 부모의 생성자부터 실행된다.
public class Car{
public Car(){
System.out.println("Car의 기본생성자입니다.");
}
}
public class Bus extends Car{
public Bus(){
System.out.println("Bus의 기본생성자입니다.");
}
}
//생성자 테스트
public class BusExam{
public static void main(String args[]){
Bus b = new Bus();
}
}
Car의 기본생성자입니다.
Bus의 기본생성자입니다.
new 연산자로 Bus객체를 생성하면, Bus객체가 메모리에 올라갈때 부모인 Car도 함께 메모리에 올라간다.
생성자가 호출될 때 자동으로 부모의 생성자가 호출되면서 부모객체를 초기화 하게된다.
자신을 가리키는 키워드가 this 라면, 부모를 가리키는 키워드는 super
super() 는 부모의 생성자를 의미한다.
부모의 생성자를 임의로 호출하지 않으면, 부모 class의 기본 생성자가 자동으로 호출된다.
아래 예제처럼 호출해보면 위에서 super()를 호출하지 않을때와 결과가 같다.
public Bus(){
super();
System.out.println("Bus의 기본생성자입니다.");
}
public class Car{
public Car(String name){
System.out.println(name + " 을 받아들이는 생성자입니다.");
}
}
이런 경우 자식 클래스에서 컴파일 오류가 나므로 직접 부모의 생성자를 호출하기 위해 super();를 사용한다
public Bus(){
super("소방차"); // 문자열을 매개변수로 받는 부모 생성자를 호출하였다.
System.out.println("Bus의 기본생성자입니다.");
}
오버라이딩이란 부모가 가지고 있는 메소드와 똑같은 모양의 메소드를 자식이 가지고 있는 것이다. 즉 오버라이딩이란 메소드를 재정의 하는 것이다.
ex) 부모의 run 메소드를 자식한테 상속하여 이름이 같은 run 메소드를 재정의 하여 표현
//run 메소드를 가지고 있는 Car클래스
public class Car{
public void run(){
System.out.println("Car의 run메소드");
}
}
//Car 를 상속받는 Bus 클래스
public class Bus extends Car{
public void run(){ //메소드 제정의
System.out.println("Bus의 run메소드");
}
}
public class BusExam{
public static void main(String args[]){
Bus bus = new Bus();
bus.run(); //Bus의 run메소드가 실행된다.
}
}
이렇게 재정의를 통해 결과는 자식클래스에서 선언한 메소드로 나온다. 하지만 부모의 메소드는 사라지지 않고 남아있다. super();를 통해서 호출가능!
public class Bus extends Car{
public void run(){
**super.run();** // 부모의 run()메소드를 호출
System.out.println("Bus의 run메소드");
}
}
부모타입에서 자식객체가 가지고 있는 메소드나 속성을 사용하고 싶다면 형변환 해야 한다.
public class Car{
public void run(){
System.out.println("Car의 run메소드");
}
}
public class Bus extends Car{
public void ppangppang(){
System.out.println("빵빵.");
}
}
Bus에서 Car를 상속받으면, 부모인 Car타입으로 자식을 참조했을 때 오류 발생한다.
public class BusExam{
public static void main(String args[]){
Car car = new Bus();
car.run();
car.ppangppang(); // 컴파일 오류 발생
}
}
부모 타입에서 자식타입의 객체를 참조 할때 명시적 형변환을 통해 가능하다.
자식 객체를 생성할 때 부모객체 앞에 ()로 명시해 주면 가능
public class BusExam{
public static void main(String args[]){
Car car = new Bus();
car.run();
//car.ppangppang(); // 컴파일 오류 발생
Bus bus = (Bus)car; //부모타입을 자식타입으로 형변환
bus.run();
bus.ppangppang();
}
}