수업내용/Java

[2022.09.21.수] 생성자 메소드, 클래스형변환

주니어주니 2022. 9. 21. 19:09

 

※ get, set 메소드 자동완성 하는법
    : getname + ctrl+space 

 

1. 상속관계의 생성자 메소드 실행 과정

 

 

1-1. 상속관계에서 생성자 메소드의 실행 

 

 

- Person객체 (부모객체) 

public class Person {

	private String name;
	private String tel;
	
	public Person() {					// 기본생성자
		System.out.println("Person() 생성자 실행됨");
	}
	
	public Person(String name, String tel) { 		// 생성자
		this.name = name;
		this.tel = tel; 
		System.out.println("Person(String, String) 생성자 실행됨");
	}
	
	public String getName() {				// getname + ctrl + space 자동생성 
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getTel() {
		return tel;
	}
	public void setTel(String tel) {
		this.tel = tel;
	}
	
}

- Employee 객체 

public class Employee extends Person {

	private String department;
	private int salary;
	
	public Employee() {
		super();
		System.out.println("Employee() 생성자 실행됨");
	}
	public Employee(String department, int salary) {
		super();
		this.department = department;
		this.salary = salary;
		System.out.println("Employee(String, int) 생성자 실행됨");
	}
	public String getDepartment() {
		return department;
	}
	public void setDepartment(String department) {
		this.department = department;
	}
	public int getSalary() {
		return salary;
	}
	public void setSalary(int salary) {
		this.salary = salary;
	}
	
}

- Student 객체

public class Student extends Person {

	private String major;
	private int grade;
	
	public Student() {
    		super();
		System.out.println("Student() 생성자 실행됨");
	}
	public Student(String major, int grade) {
    		super();
		this.major = major;
		this.grade = grade;
	}
	public String getMajor() {
		return major;
	}
	public void setMajor(String major) {
		this.major = major;
	}
	public int getGrade() {
		return grade;
	}
	public void setGrade(int grade) {
		this.grade = grade;
	}
	
}

- PersonApp (실행 객체) 

public class PersonApp {

	public static void main(String[] args) {
		System.out.println("## Employee 객체 생성하기");
		Employee emp = new Employee();
		
		System.out.println("## Student 객체 생성하기");
		Student stud = new Student();
		
	}
}

 

## Employee 객체 생성하기
Person() 생성자 실행됨
Employee() 생성자 실행됨

## Student 객체 생성하기
Person() 생성자 실행됨
Student() 생성자 실행됨

 

 

  •  Employee객체, Student객체를 생성했는데 왜 Person객체의 생성자가 실행됐을까?

 

 

 

실행객체에서 Employee emp = new Employee(); 작성하고 컴파일하면, 

(Employee객체)
Employee( ) {     ---> 1) Employee 객체로 일단 와서 
   super( ) ;        ---> 2) 부모객체 Person으로 먼저 가

(Person객체)
Person( ) {         
   super( ) ;        ---> 3) 근데 super가 있어? 부모객체 Object로 가

(Object객체)
Object( ) { }        ---> 4) Object 생성자를 가장 먼저 실행해
                          ---> 5) Person 객체로 돌아와서 생성자 실행해
                          ---> 6) Employee 객체로 돌아와서 생성자 실행해  


※ 생성자 실행 순서 ( 부모 -> 자식 ) 
    Object 객체 -> Person 객체 -> Employee 객체 
    상위객체부터 먼저 초기화 

 

 

* 부모객체에 기본 생성자가 없으면, 자식객체의 모든 생성자 실행이 안됨 

 

 

 

  • 은닉화, 생성자는 상속 x 인데 왜 super를 통해서 상위 생성자가 실행되는걸까?
    : 생성자를 상속받은 것이 아니라, 부모객체의 기능을 쓰기 위해 부모객체의 생성자를 호출하는 것! 

 

- 상속 받았다 : 부모객체에 있는 변수, 메소드를 자식객체에서 직접 실행할 수 있다 

                        ( 자식객체에서 p.setNumber("010-1111-1111"); 를 바로 실행할수가 있다 ) 

- 상속을 못받는다 : 부모객체의 은닉화된 변수, 생성자를 자식객체에서 직접 접근할 수 없어서, 호출을 통해 부모객체로 가
                                ( p.number = "010-1111-1111"; (은닉화된 변수 사용),  p.Person() {} (생성자 사용) )

                        

( 만약 생성자 Person(); 을 상속받았다면, 

  SmartPhone생성자메소드에서 Person(); 을 직접 실행할 수가 있는것 

  근데 SmartPhone생성자메소드에서 Person();생성자를 실행할 수 없어

  (두개의 생성자를 사용할 수 없어서? / 생성자는 객체 생성과 동시에 초기화하는 건데 부모객체를 이미 갖고있어서?) 

  그래서, Person 객체의 생성자를 호출하는 특별한 메소드 super( ); ) 

 

 

 

 

1-2. 부모객체의 생성자 메소드를 지정해서 호출하기

 

  • 지정을 안하면, 부모객체의 기본 생성자 메소드가 자동으로 호출됨
  • super( 인자값1 , 인자값2 , 인자값3 , ... );
    자식 객체에서 부모 객체의 생성자 메소드를 호출하면서 인자값을 전달하면, 
    부모 객체의 은닉화된 멤버변수를 초기화할 수 있다.

    *단, 부모 객체의 생성자는 상속받지 않기 때문에 super( ) 메소드 사용 

 

 

  • (Employee객체) 
    Employee(
    String name, String tel, String department, int salary) {
       super(name, tel);                      
       this.department = department; 
       this.salary = salary; 

    // 부모에 있는 생성자 중 어떤걸 호출받을건지 지정할 수 있음
      (Person객체의 Person(String, String) 생성자 메소드 호출)
      자식객체에서 부모객체의 생성자를 활용해서 내가 초기화할 수 없는 부모 객체의 멤버변수를 초기화할 수 있다

    // department, salary 는 이 객체의 은닉화된 변수에 초기화해서 넣고,
       name, tel은 이 객체의 부모객체에 초기화



  • (실행객체)
    Employee emp = new Employee("홍길동", "010-1111-1111", "영업1팀", 600000);

    -> "홍길동" 이름이 -> Employee생성자의 매개변수 String name으로 대입
    -> super를 통해 부모객체의 Person생성자의 매개변수 String name으로 대입
    -> 대입된 name이 this.name을 통해 부모 객체의 멤버변수로 초기화


  •  자동 생성되는 super( );                  --> 부모 객체의 기본 생성자 메소드 호출
     내가 지정하는 super(name, tel);   --> 부모 객체의 생성자 중에서 String, String 을 받는 생성자 메소드 호출 

 

 

 

- Person 객체 

	public Person() {				// 기본생성자
		System.out.println("Person() 생성자 실행됨");
	}
	
	public Person(String name, String tel) { 	// 생성자
		this.name = name;
		this.tel = tel; 
		System.out.println("Person(String, String) 생성자 실행됨");
	}

- Employee 객체 

	public Employee() {
		super();			// Person 객체의 기본 생성자 메소드를 호출
		System.out.println("Employee() 생성자 실행됨");
	}
	public Employee(String name, String tel, String department, int salary) {
		// department, salary는 Employee객체에 넣고, name, tel은 이 객체랑 연결되어 있는 객체에 초기화
		//super();			// Person 객체의 기본 생성자 메소드를 호출
		super(name, tel);		// Person 객체의 Person(String, String) 생성자 메소드 호출 
		this.department = department;
		this.salary = salary;
		System.out.println("Employee(String, String, String, int) 생성자 실행됨");
	}

- PersonApp 개체 (실행객체) 

	public static void main(String[] args) {
		System.out.println("## Employee 객체 생성하기");
		Employee emp = new Employee("홍길동", "010-1111-1111", "영업팀", 600);
		System.out.println("## 직원정보 출력");
		System.out.println();
		
		System.out.println("## Student 객체 생성하기");
		Student stud = new Student("김유신", "010-2222-2222", "컴퓨터공학", 4);
		System.out.println("## 학생정보 출력");
		
		
	}

 

## Employee 객체 생성하기
Person(String, String) 생성자 실행됨
Employee(String, String, String, int) 생성자 실행됨
## 직원정보 출력

## Student 객체 생성하기
Person(String, String) 생성자 실행됨
Student(String, String, String, int) 생성자 실행됨
## 학생정보 출력

(첫번째 예시 출력된 값이랑 비교) 

 

 

 

 

  • 값 넣고 출력해보기 

 

- Employee객체 

public class Employee extends Person {

	private String department;
	private int salary;
	
	public Employee() {
		super();		// Person 객체의 기본 생성자 메소드를 호출
		System.out.println("Employee() 생성자 실행됨");
	}
	public Employee(String name, String tel, String department, int salary) {
		// department, salary는 Employee객체에 넣고, name, tel은 이 객체랑 연결되어 있는 객체에 초기화
		//super();		// Person 객체의 기본 생성자 메소드를 호출
		super(name, tel);	// Person 객체의 Person(String, String) 생성자 메소드 호출 
		this.department = department;
		this.salary = salary;
		System.out.println("Employee(String, String, String, int) 생성자 실행됨");
	}
    
    /// getter, setter 메소드 
    
    	public void display() {
		System.out.println("-------------------------------------------");
		System.out.println("직원 이름: "+getName());		// name은 이 객체가 아니라, 부모객체의 은닉화된 변수
		System.out.println("직원 연락처: "+getTel());		// 이 get 메소드들을 Person으로부터 상속
		System.out.println("직원 소속부서: "+department);	//이건 내가 갖고있으니까 바로 쓸 수 있음
		System.out.println("직원 급여: "+salary);
		System.out.println("-------------------------------------------");
		System.out.println();
	}

- Strudent 객체도 똑같이 

public class Student extends Person {

	private String major;
	private int grade;
	
	public Student() {
		System.out.println("Student() 생성자 실행됨");
	}
	public Student(String name, String tel, String major, int grade) {
		//super();		//Person객체의 기본 생성자 메소드 호출 
		super(name, tel);	//Person객체의 Person(String,String) 생성자 메소드 호출  
		this.major = major;
		this.grade = grade;
		System.out.println("Student(String, String, String, int) 생성자 실행됨");
        
        /// getter, setter 메소드 
    
    	public void display() {
      		System.out.println("-------------------------------------------");
		System.out.println("학생 이름: "+getName());
		System.out.println("학생 전화번호: "+getTel());
		System.out.println("학생 전공: "+major);
		System.out.println("학생 학년: "+grade);
      		System.out.println("-------------------------------------------");
		System.out.println();
	}

- PersonApp 객체 (실행객체) 

public class PersonApp {

	public static void main(String[] args) {
		System.out.println("## Employee 객체 생성하기");
		Employee emp = new Employee("홍길동", "010-1111-1111", "영업팀", 600);
		
		System.out.println("## 직원정보 출력");
		emp.display();	//자식객체랑 연결되어있는 부모객체의 name,tel에 저장
		
		System.out.println("## Student 객체 생성하기");
		Student stud = new Student("김유신", "010-2222-2222", "컴퓨터공학", 4);
		
		System.out.println("## 학생정보 출력");
		stud.display();	//자식객체랑 연결되어있는 부모객체의 name,tel에 저장
	}
}

 

## Employee 객체 생성하기
Person(String, String) 생성자 실행됨
Employee(String, String, String, int) 생성자 실행됨
## 직원정보 출력
-------------------------------------------
직원 이름: 홍길동
직원 연락처: 010-1111-1111
직원 소속부서: 영업팀
직원 급여: 600
-------------------------------------------

## Student 객체 생성하기
Person(String, String) 생성자 실행됨
Student(String, String, String, int) 생성자 실행됨
## 학생정보 출력
-------------------------------------------
학생 이름: 김유신
학생 전화번호: 010-2222-2222
학생 전공: 컴퓨터공학
학생 학년: 4
-------------------------------------------

 

 


 

 

2. 자바의 형변환

 

2-1. 기본 자료형의 형변환

  • 정수 -> 실수
    double x = 10;                             // 정수 10을 실수 10.0으로 변환
    double x = (double) 250/3;          // 정수 250을 실수 250.0으로 변환 후 계산한 값도 실수 
  • 실수 -> 정수
    int x = (int) 3.14;                          // 실수 3.14를 정수 3으로 변환
  • 정수 -> 문자
    char x = 65;                                 // 정수 65를 문자 'A'로 변환
    System.out.println( (char) 65 );   // 정수 65를 문자 'A'로 변환
  • 문자 -> 정수
    int x = 'A';                                    // 문자 'A'를 정수 65로 변환
    int x = (int) 'A' - 0;                        // 문자 'A'를 정수 65로 변환

 

2-2. 참조 자료형의 형변환  

: 상위클래스- 하위클래스(부모자식) 관계에 있는 타입끼리만 형변환 가능

 

- 객체의 타입과 참조변수의 타입이 서로 다를 때 클래스 형변환 발생

- 객체의 타입과 참조변수의 타입이 상속관계일 때 때 클래스 형변환

- 참조변수의 타입이 객체의 타입보다더 상위객체일 때 자동으로 클래스 형변환 발생

  ( 하위객체들은 상위객체를 항상 갖고있으니까 -> 참조할 수 있는 객체가 있어 )

- 참조변수의 타입객체의 타입보다 더 하위객체일 때 강제 클래스 형변환 필요 (개발자의 개입)

  ( 참조할 수 있는 객체가 없어 )

 

 

  • 1) 원래 알던 것 ( 참조변수 타입 = 객체 타입 ) 
  Iphone p1 = new Iphone( );

// 클래스형변환 발생 X
// 객체의 타입과 참조변수의 타입이 동일 

 

 

 

  • 2) 클래스 형변환 ( 참조변수 타입(상위)  ≠  객체 타입(하위) ) 

 

 

 SmartPhone p3 = new Iphone( );

// 객체의 타입과 참조변수의 타입이 서로 다름
// 참조변수의 타입이 객체의 상위 타입
// 클래스형변환 발생 O (자동형변환) 

- iphone객체가 생성되면 그 부모인 smartphone객체, phone객체, Object객체도 생성
- 변수 p3의 타입은 SmartPhone이고, 다른 타입은 절대 들어갈 수 없음 
- 근데 이 변수에 하위객체인 Ipnohe 객체의 주소값을 담으려고 해, 안담기네? 
- 참조변수의 타입을 바꿀 수는 없으니, 대입하려고 하는 값의 타입을 형변환 해야함 
원래는 Iphone객체를 참조해야 하는데 ( Iphone객체의 주소값을 넣어야되는데 ) 
- 생성된 객체 안에 있는 super를 통해 iphone 상위 객체 중에 Smartphone 타입인걸 찾아 
Smartphone 객체의 주소값을 넣어
- 실제로 생성된건 Iphone객첸데, 바라보는건  그 안에 있는 상위객체인 Smarphone 객체 
- 처음부터 SmartPhone 객체로 연결하는 거랑은 다름 ! 


=> 하위를 상위에 담을 수 o  ( ∵ 하위객체들은 상위객체를 항상 갖고있으니까 참조할 객체가 있어 )

 

 

 

  • 3) 클래스 형변환 오류 ( 참조변수 타입(하위)  ≠  객체 타입(상위) ) 

 

 

 Iphone p2 = new Phone( );

// 객체의 타입과 참조변수의 타입이 서로 다름
// 참조변수의 타입이 객체의 하위 타입
// 클래스형변환이 발생 X
// 컴파일 오류 

- Phone객체와 그 부모인 Object 객체가 같이 생성
- Phone 객체가 Iphone형태인 참조변수 p2에 안담겨  
- 객체 중에 참조변수와 같은 Iphone 타입에 담을 수 있는 객체를 부모중에 찾아도 없어 -> 컴파일 오류
  ( Phone 객체 중에는 Iphone 객체가 없음
- 하위클래스로 형변환 할 수 없음!

=> 상위를 하위에 담을 수 x ( ∵ 상위객체에는 하위객체가 없으니까 참조할 수가 없음  ) 

 

 


 

2-3. 형변환 처리 과정

 

 

 

 

  • 참조변수의 클래스타입과 생성된 객체의 클래스타입이 같을 때
  1. Phone p = new Phone();
  2. Phone객체를 생성한다.
  3. 참조변수의 클래스타입과 생성된 객체의 클래스타입이 동일한 타입인지 체크한다.
  4. 참조변수의 클래스타입과 생성된 객체의 클래스타입이 같은 타입임을 확인함
  5. 객체의 주소값이 참조변수에 대입된다.
  6. 참조변수는 주소값이 가르키는 객체를 참조한다.

 

 

 

  • 참조변수의 클래스타입이 생성된 객체상위클래스 타입일 때
  1. Phone p = new Iphone();
  2. Iphone객체를 생성한다.
  3. 참조변수의 클래스타입과 생성된 객체의 클래스타입이 동일한 타입인지 체크한다.
  4. 참조변수의 클래스타입과 생성된 객체의 클래스타입이 다른 타입임을 확인함.
  5. 생성된 객체에서 부터 조상객체를 탐색해서 참조변수의 클래스타입과 동일한 클래스타입의 객체를 탐색한다.
  6. Iphone객체 안에 있는 Phone객체를 발견한다.
  7. 발견된 Phone객체의 주소값이 참조변수에 대입된다.
  8. 참조변수는 주소값이 가르키는 Phone객체를 바라본다.

 

 

 

 


 

 

2-4. 부모 객체로의 형변환

 

 

 

Phone 객체 - 자기포함 그 하위 객체를 모두 참조 가능 
SmartPhone 객체 - 자기포함 그 하위 객체 모두 참조 가능 
부모타입의 참조변수 => 어떤 자식 객체도 연결가능  ( 교체가능성, 확장성 ) 

 

 

public class Sample {

   private Phone phone;                         // 전화, 문자 기능이 가능한 객체 요구 (Phone의 하위 모두) 

}

public class Sample {

   private SmartPhone phone;               // 인터넷, 이메일이 가능한 객체 요구 (SmartPhone의 하위) 

}

public class Sample {

   private IPhone phone;                        // 애플페이, 애플뮤직, 페이스타임이 가능한 객체 요구 (Iphone의 하위) 

}

public class Sample {

   private Galaxy phone;                        // 삼성페이, 빅스비가 가능한 객체 요구  (Galaxy의 하위) 

}

 

 

 

-Car 객체 (부모객체)

/**
 * 모든 차량이 공통으로 갖는 속성과 기능이 정의된 클래스
 * @author wnnns
 *
 */
public class Car {

	private int speed;
	
	public void speedUp() {
		if(speed == 250) {
			return; 
		}
		speed += 10;
		System.out.println("## 속도 증가. 현재속도: "+speed);
	}
	
	public void speedDown() {
		if(speed ==10) {
			return;
		}
		speed -= 10;
		System.out.println("## 속도 감소. 현재속도: "+speed);
	}
	
	public void drive() {
		System.out.println("## 운전 중 ##");
	}
	
	public void stop() {
		System.out.println("## 정차 중 ##");
	}
}

 

-LightCar 객체

public class LightCar extends Car{
	
	public void audio() {
		System.out.println("## 오디오 재생 ##");
	}
}

-MediumCar 객체

public class MediumCar extends LightCar {
	
	public void aircon() {
		System.out.println("## 에어컨 가동중 ##");
	}
	
	public void navigation() {
		System.out.println("## 길안내 실행중 ##");
		
	}
}

-LuxuryCar 객체

public class LuxuryCar extends MediumCar {
	
	public void autoDrive() {
		System.out.println("## 자율운전중 ##");
	}
}

 

-CarApp 객체 (실행 객체) 

public class CarApp {

	public static void main(String[] args) {
		// 참조자료형의 형변환
		// 참조변수의 타입과 객체의 타입이 서로 다를 때 클래스 형변환 발생
		// 참조변수의 타입이 객체의 타입과 동일하거나, 상위타입일 때만 객체를 참조변수에 대입할 수 있다
		
		Car car1 = new Car();			// car1은 생성된 Car객체를 참조
		Car car2 = new LightCar();		// car2는 LightCar객체가 생성될 때 같이 생성된 Car객체를 참조
		Car car3 = new MediumCar();		// car3는 MediumCar객체가 생성될 때 같이 생성된 Car객체를 참조
		Car car4 = new LuxuryCar();		// car4는 LuxurytCar객체가 생성될 때 같이 생성된 Car객체를 참조
		
//		LightCar car5 = new Car();		// 컴파일 오류 (상위타입을 하위타입에 담을 수 X) 
		LightCar car7 = new LightCar();
		LightCar car6 = new MediumCar();
		LightCar car8 = new LuxuryCar();
		
//		MediumCar car9 = new Car();		// 컴파일 오류 (상위타입을 하위타입에 담을 수 X) 
//		MediumCar car10 = new LightCar();	// 컴파일 오류 (상위타입을 하위타입에 담을 수 X) 
		MediumCar car11 = new MediumCar();
		MediumCar car12 = new LuxuryCar();
		
//		LuxuryCar car13 = new Car();		// 컴파일 오류 (상위타입을 하위타입에 담을 수 X)
//		LuxuryCar car14 = new LightCar();	// 컴파일 오류 (상위타입을 하위타입에 담을 수 X)
//		LuxuryCar car15 = new MediumCar();	// 컴파일 오류 (상위타입을 하위타입에 담을 수 X)
		LuxuryCar car16 = new LuxuryCar();
		
	}
}

 

 

 

  • 참조변수의 타입을 부모객체로 하는 이유 

 

 

- Car타입의 참조변수에는 Car, LightCar, MediumCar, LuxuryCar 객체를 대입할 수 있다. (모두 Car객체를 포함하니까) 

- Car타입의 참조변수에 대입된 객체의 종류에 상관없이 Car타입의 참조변수는 무조건 Car 객체만 참조한다.(바라본다) 

- Car타입의 참조변수에 대입된 객체의 종류에 상관없이

  Car타입의 참조변수로 car.speedUp();  car.speedDown(); car.drive(); car.stop(); 기능은 확실히 실행할 수 있다.

  내가 이 기능들은 확실하게 실행하고 싶어 + 거기다가 이제 무슨기능을 더 넣고싶은지 아직 모르겠어 -> Car타입 연결

 

 

 

Q.  LuxuryCar 하위객체가 제일 기능이 많으니까 , 처음부터 얘한테 연결하면 되지않나? 부모객체에 연결하는 이유

 

* 부모타입의 참조변수 ==> 어떤 자식 객체도 연결가능  ( 교체가능성, 확장성 ) 

 ( Mouse 타입의 mouse 변수에는 일반마웃, 광마우스, 게이밍마우스를 모두 연결가능 ) 

- 기능이 제일 많은 하위객체 중에서도, Iphone 도 있고, Galaxy도 있고 여러개가 있을 수 있음.

  그니까 처음부터 그냥 모든 객체를 연결할 수 있는 부모객체에 연결  

  무슨 기능을 추가하든간에, Car 객체는 어쨌든 무조건 가지게 되니까 

- 미래에 무슨일이 생길지 모르는데, 미래에 만들어지는 것까지도 연결이 가능

 

 

 


 

 

2-5. 형변환된 객체에서의 변수, 메소드 사용

 

 

  • 참조변수의 타입에 따른 메소드 실행 
    - 똑같은 MediumCar 객체를 만들었는데, 바라보는게 다 달라
    - 하위객체를 상위객체에 담을 수는 있는데, 내가 바라보는 객체(+상위객체)의 기능만 이용할 수 있어
    - 참조하는 객체의 바깥쪽에 있는 것들은 실행할 수 없어

 

 

 

 

 

 

  • 클래스 형변환된 객체의 속성과 기능 사용하기
public class CarApp2 {
	public static void main(String[] args) {
		/*
		 * 클래스 형변환된 객체의 속성과 기능 사용하기
		 * 
		 * 생성한 객체는 동일한 객체여도, 그 객체를 참조하는 참조변수의 타입에 따라서 
		 * 사용가능한 속성이나 기능의 범위가 달라진다.
		 */
		
		// car1 참조변수는 MediumCar, LightCar, Car 객체의 공개된 속성과 기능을 사용할 수 있다.
		MediumCar car1 = new MediumCar();
		car1.speedUp();		// Car에 있는 기능 사용가능
		car1.speedDown();	// Car에 있는 기능 사용가능
		car1.drive();		// Car에 있는 기능 사용가능
		car1.stop();		// Car에 있는 기능 사용가능
		car1.audio();		// LightCar에 있는 기능 사용가능
		car1.aircon();		// MediumCar에 있는 기능 사용가능
		car1.navigation();	// MediumCar에 있는 기능 사용가능
		
		// car2 참조변수는 LightCar, Car 객체의 공개된 속성과 기능을 사용할 수 있다.
		LightCar car2 = new MediumCar();
		car2.speedUp();		// Car에 있는 기능 사용가능
		car2.speedDown();	// Car에 있는 기능 사용가능
		car2.drive();		// Car에 있는 기능사용가능
		car2.stop();		// Car에 있는 기능 사용가능
		car2.audio();		// LightCar에 있는 기능 사용가능
//		car2.aircon();		// 컴파일 오류. MediumCar에 있는 기능을 car2 참조변수로 사용할 수 없다.  
//		car2.navigation();	// 컴파일 오류. MediumCar에 있는 기능을 car2 참조변수로 사용할 수 없다.  
		
		// car3 참조변수는 Car 객체의 공개된 속성과 기능을 사용할 수 있다.
		Car car3 = new MediumCar();
		car3.speedUp();		// Car에 있는 기능 사용가능
		car3.speedDown();	// Car에 있는 기능 사용가능
		car3.drive();		// Car에 있는 기능 사용가능
		car3.stop();		// Car에 있는 기능 사용가능
//		car3.audio();		// 컴파일 오류. LightCar에 있는 기능을 car3 참조변수로 사용할 수 없다. 
//		car3.aircon();		// 컴파일 오류. MediumCar에 있는 기능을 car3 참조변수로 사용할 수 없다.
//		car3.navigation();	// 컴파일 오류. MediumCar에 있는 기능을 car3 참조변수로 사용할 수 없다. 
	
	}
}