※ 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. 형변환 처리 과정
- 참조변수의 클래스타입과 생성된 객체의 클래스타입이 같을 때
- Phone p = new Phone();
- Phone객체를 생성한다.
- 참조변수의 클래스타입과 생성된 객체의 클래스타입이 동일한 타입인지 체크한다.
- 참조변수의 클래스타입과 생성된 객체의 클래스타입이 같은 타입임을 확인함
- 객체의 주소값이 참조변수에 대입된다.
- 참조변수는 주소값이 가르키는 객체를 참조한다.
- 참조변수의 클래스타입이 생성된 객체의 상위클래스 타입일 때
- Phone p = new Iphone();
- Iphone객체를 생성한다.
- 참조변수의 클래스타입과 생성된 객체의 클래스타입이 동일한 타입인지 체크한다.
- 참조변수의 클래스타입과 생성된 객체의 클래스타입이 다른 타입임을 확인함.
- 생성된 객체에서 부터 조상객체를 탐색해서 참조변수의 클래스타입과 동일한 클래스타입의 객체를 탐색한다.
- Iphone객체 안에 있는 Phone객체를 발견한다.
- 발견된 Phone객체의 주소값이 참조변수에 대입된다.
- 참조변수는 주소값이 가르키는 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 참조변수로 사용할 수 없다.
}
}
'수업내용 > Java' 카테고리의 다른 글
[2022.09.23.금] 추상화, 인터페이스 (0) | 2022.09.24 |
---|---|
[2022.09.22.목] 강제 형변환, 메소드 재정의와 다형성 (0) | 2022.09.22 |
[2022.09.20.화] static, 상속 (0) | 2022.09.20 |
[2022.09.19.월] 클래스의 역할 분담 (0) | 2022.09.20 |
[2022.09.17.토] 숙제1 (0) | 2022.09.18 |