Java day 13

유요한·2022년 11월 23일
1

Java

목록 보기
13/24
post-thumbnail

형변환

다른 형식으로 형태를 변환시키는 것
단, 클래스에서 상속관계에 있는 클래스만 형변환이 가능하다.

형변환은 크게 두 가지 형태

업 캐스팅(Up Casting)

  • 부모 타입의 객체에 자식 클래스의 필드를 담아주는 것
  • 부모 타입의 객체에 자식 객체를 넣어주는 것
  • 부모 타입의 객체에 자식 생성자를 호출해주는 것
  • 자식 타입의 객체를 부모 타입의 객체로 변환
  • 오버라이딩 된 메소드는 가지게 된다.
	② Parent(부모 클래스) p1 = ① new Child(자식 클래스)();
		→ ① new Child에서 주소값을 가져오고
		→ ② Parent(참조변수)에 집어 넣어준다. 그래서 부모 클래스로 형변환
			그래서 집어 넣어주면 업캐스팅 된 객체가 접근할 수 있는 범위
			즉, 업 캐스팅을 해주면 부모 클래스가 가지고 있는 메소드만 사용가능하고
			자식 클래스만 가지고 있는 메소드는 사용 할 수 없다.
			단, 오버라이딩된 것은 사용 가능하다.

다운 캐스팅(Down Casting)

  • 부모 타입의 객체를 자식 타입의 객체로 변환

  • 업 캐스팅 된 객체를 다시 자식 객체에 담는 기법

  • 업 캐스팅 시 잘려나갔던 자식 클래스의 내용들(메소드)을
    다시 사용할 수 있게 하려면 자식 클래스 타입으로 바꿔주어야 한다.

    		(자식클래스)업캐스팅 된 객체
    
    		자식 클래스 다운캐스팅객체 = (자식클래스)업캐스팅 된 객체;
    		다운 캐스팅
    		class Animal {
    	public void print() {
    		System.out.println("나는 동물입니다.");
    	}
    }

class Monkey extends Animal {

@Override
public void print() {

// super.print(); // 부모 클래스꺼를 가져와서 Animal print와 monkey print와 같이 출력
System.out.println("나는 원숭이 입니다.");
}

}
class Dog extends Animal {
@Override
public void print() {
System.out.println("나는 개 입니다.");
// super.print();
}
public void sound() {
System.out.println("개는 멍멍!!!");
}
}
class Cat extends Animal {
@Override
public void print() {
System.out.println("나는 고양이 입니다.");
// super.print();
}
public void sound() {
System.out.println("고양이는 야오오오오~옹!!!");
}
}

public class CastingExam {

public static void main(String[] args) {
	Monkey monkey = new Monkey();
	Dog dog = new Dog();
	Cat cat = new Cat();
	

// monkey.print();
// dog.print();
// cat.print();

	print(monkey);
	

// Animal a1 = (Animal)monkey; // Upcasting(명시적 업캐스팅) → 자기 자신께 있다면 자기것을 출력
// Animal a2 = dog; // 자동 형변환
// Animal a3 = cat;

// a1.print();
// a2.print();
// a3.print();

	// 업케스팅 예제

// print((Animal)monkey); // Upcasting
// print(dog);
// print(cat);

	// 다운캐스팅 예제
	cprint(dog);
	cprint(monkey);
	cprint(cat);
}
// 업캐스팅
public static void print(Animal p) {
	System.out.println("==========");
	System.out.println("안녕하세요");
	p.print();
}
// 다운캐스팅
public static void cprint(Animal p) {
	System.out.println("=============");
	System.out.println("안녕하세요");
	System.out.println("반갑습니다.");
	
	p.print();
	
	
	// 개의 목소리도 출력하고 싶지만, 고양이의 목소리도 출력하고 싶어요.
	if(p instanceof Dog) {
		Dog dog = (Dog) p;
		dog.sound();
	} else if(p instanceof Cat) {
		((Cat)p).sound();
	}
	
	
	System.out.println("============");
}

}

instanceof

  • 객체 instanceof 클래스명
    객체가 뒤에오는 클래스 타입이면 true
    아니면 false
  • 객체가 참조하고 있는 객체의 실제 타입(클래스타입)을 확인하기 위한 연산자
  • 이항연산자로 왼쪽에는 확인할 객체를 오른쪽에는 타입(클래스)을 피연산자로 사용

    부모객체 instanceof 부모클래스 : true
    자식객체 instanceof 자식클래스 : true
    부모객체 instanceof 자식클래스 : false
    자식객체 instanceof 부모클래스 : true
    업캐스팅객체 instanceof 부모클래스 : true
    업캐스팅객체 instanceof 자식클래스 : true

문법
```
	Car car = new Car();
if (car instanceof FirEngine) {   		// 형변환이 가능한지 확인

FireEngine fire = (FireEngine)car; // 형변환
}
Animal[] ani = {
new Cat(),
new Dog(),
new Animal()
};
→ Animal(부모 클래스)를 배열식으로 만들고 거기에 3개의 생성자의 주소값을 받아왔다.

Cat, Dog, Bird는 Animal의 자식 클래스라서 이 상태에서는 자동으로 업 캐스팅이 된다.
Animal ani = new Cat();
Animal ani = new Dog();
이런 구조이다. 하지만 Fish는 Animal의 자식 클래스가 아니라 업 캐스팅이 안된다.
그리고 Animal은 부모 클래스 자기 자신이라 업 캐스팅이 안된다.
이럴 때 instanceof사용해주면 된다.

정리

instanceof는 일반적으로 런타임에 발생할 오류를 방지하기 위해
형변환이 가능한지 확인하고 참인 경우 안전하게 형변환 하기 위해
사용된다. 즉, 오류를 방지하기 위한 목적으로 생겨난 것이다.
true를 얻었다는 것은 참조변수가 검사한 타입으로 형변환이 가능하다는 뜻


다형성(Polymorphism)

  • 여러 가지 형태를 가질 수 있는 능력
  • 조상 타입 참조 변수로 자손 타입 객체를 다루는 것
    1. 오버로딩(Overloading)

      메소드의 이름을 재사용하여 다른 기능을 해주는 메소드를 만드는 기능.
      오버로딩된 메소드 사용시, 전달된 값의 타입 혹은 개수로 구분하여
      알맞은 메소드가 자동으로 호출된다.

    오버로딩 조건

    메소드의 이름이 같아야 한다.
    매개변수의 개수 또는 타입으로 구분한다.
    반환 타입(값)은 관계없다. 즉 반환 값으로 구분하지 않는다.

          
  1. 오버라이딩(Overriding) : 메소드 재정의

부모 클래스에 a()라는 메소드가 존재한다면 자식 객체 생성시
부모 생성자가 먼저 호출되어 부모 클래스의 a()가 먼저 메모리에 올라간다.
그 다음 자식 클래스에서 생성한 a()라는 메소드가 선언된다면 부모 필드의 a()메소드에 메소드 내용이 덮어 씌어진다. 이것이 재정의라고 한다.

자식 클래스에서 동일한 메소드를 재정의하여 사용하는 것
즉, 부모의 특정 메소드를 내 필요에따라 다시 정의하여
다른 기능으로 또는 다른 기능을 추가하여 사용하는 것.
재정의하면 부모 객체의 메소드를 자식 객체의 메소드로 대체해버린다.

	class Car {
	private String name; // 차이름
	
	Car() {
		this.name = "";
	}

	Car(String name) {
		this.name = name;
	}
	
	public String getName() {
		return this.name;
	}
	
	public int getSpeed() {
		return 100;
	}
}

class SuperCar extends Car {
	SuperCar() {
		super();
	}

	SuperCar(String name) {	
		super(name);
	}
	
	@Override
	public int getSpeed() {
		return super.getSpeed() + 100;
	}
	
}

public class OverrideExam {
	public static void main(String[] args) {
		Car car = new Car("모닝");
		System.out.println(car.getSpeed());

		SuperCar supercar = new SuperCar("포르쉐");
		System.out.println(supercar.getSpeed());
	}
}

HomeWork

  • Human 클래스
    바뀐점 : class → 추상 클래스 사용

    	// 추상 클래스
    public abstract class Human {
    	private char type;
    
    	// 이름과 나이를 여기로 일반화 하자
    	// 모든 인간은 이름과 나이가 있다고 가정한다.
    	private String name;
    	private int age;
    
    	public Human() {
    		this.type = 0;
    		
    		// 초기화
    		this.name = "";
    		this.age = 0;
    	}
    	
    	public Human(char type, String name, int age) {
    		this.type = type;
    		
    		// 초기화
    		this.name = name;
    		this.age = age;
    	}
    	
    	// 추상 메소드
    	public abstract void print();
    
    	// getter
    	public char getType() {
    		return type;
    	}
    
    	// getName, getAge 메소드 추가
    	public String getName() {
    		return name;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	// setter
    	public void setType(char type) {
    		this.type = type;
    	}
    
    	// setName, setAge 메소드 추가
    	public void setName(String name) {
    		this.name = name;
    	}
    	
    	public void setAge(int age) {
    		this.age = age;
    	}
    }
● Student 클래스
  바뀐점 : int score → int[] score 배열화 해줌
import java.util.Arrays;

public class Student extends Human {
	private String className;
	// score를 배열로 변경하자.
	private int[] score;
	// age, name은 부모 클래스로 이동했다. 

	public Student() {
		// super() 메소드를 이용한 초기화로 부모의 생성자이용하여 초기화할 수 있다.
		super();	// type, name, age는 이제 여기서 초기화된다.

		className = "";
		
		// 배열 생성
		score = new int[5];
	}

	public Student(String className, char type, String name, int age, int[] score) {
		// super() 메소드를 이용한 초기화로 부모의 생성자이용하여 초기화할 수 있다.
		super(type, name, age);	// type, name, age는 이제 여기서 초기화된다.

		this.className = className;

		// 배열 초기값 설정
		this.score = score;	// 배열로 받은걸 그대로 배열로...
	}

	// setter
	public void setClassName(String className) {
		this.className = className;
	}
	
	// setName, setAge은 Human 클래스에 있다.

	// score가 배열이므로 각 배열 요소에 값을 저장하기 위해
	// index는 배열 요소의 위치를 나타낸다.
	public void setScore(int index, int score) {
		// 각 점수 배열의 index에 해당하는 요소의 점수 설정
		this.score[index] = score;
		
		// index = 0이면 this.score[0] 요소에 score를 저장;
		// index = 1이면 this.score[1] 요소에 score를 저장;
		// index = 2이면 this.score[2] 요소에 score를 저장;
		// index = 3이면 this.score[3] 요소에 score를 저장;
		// index = 4이면 this.score[4] 요소에 score를 저장;
	}

	// getter
	public String getClassName() {
		return this.className;
	}

	// getName, getAge은 Human 클래스에 있다.
	
	// score가 배열이므로 각 배열 요소에 값을 가져오기 위해
	// index는 배열 요소의 위치를 나타낸다.
	public int getScore(int index) {
		// 각 점수 배열의 index에 해당하는 요소의 점수 가져오기
		return this.score[index];
		
		// index = 0이면 this.score[0] 요소에 값을 반환;
		// index = 1이면 this.score[1] 요소에 값을 반환;
		// index = 2이면 this.score[2] 요소에 값을 반환;
		// index = 3이면 this.score[3] 요소에 값을 반환;
		// index = 4이면 this.score[4] 요소에 값을 반환;
	}
	
	// print 메소드(추상 메소드 오버라이드)
	@Override
	public void print() {
		System.out.println("============ 나의 학생 정보 =============");
		System.out.println(className + "입니다.");
		System.out.println("이름은 " + this.getName() + "입니다.");
		System.out.println("나이는 " + this.getAge() + "입니다.");
		System.out.println("성별은 " + this.getType() + "입니다.");
		// Arrays.toString을 이용하여 배열의 값을 문자열로 표시
		System.out.println("점수는 " + Arrays.toString(score) + "점 입니다.");
		System.out.println("총점은 " + this.getTotal() + "점입니다.");
		System.out.println("평점은 " + this.getAverage() + "점입니다.");
		System.out.println("=====================================");
	}

	// 총점 계산하기 메소드
	public int getTotal() {
		int total = 0;
		for (int i = 0; i < score.length; i++) {
			total += score[i];
		}
		return total;
	}

	// 평균 계산하기 메소드
	public double getAverage() {
		return getTotal() / this.score.length;
	}
}
  • Teacher 클래스
 	public class Teacher extends Human {
	private String className;
	// age, name은 부모 클래스로 이동했다.

	public Teacher() {
		// super() 메소드를 이용한 초기화로 부모의 생성자이용하여 초기화할 수 있다.
		// type, name, age는 이제 여기서 초기화된다.
		super();

		this.className = "";
	}

	public Teacher(String className, char type, String name, int age) {
		// super() 메소드를 이용한 초기화로 부모의 생성자이용하여 초기화할 수 있다.
		// type, name, age는 이제 여기서 초기화된다.
		super(type, name, age);
		
		this.className = className;
	}

	// setter
	public void setClassName(String className) {
		this.className = className;
	}
	
	// setName, setAge은 Human 클래스에 있다.
	
	// getter
	public String getClassName() {
		return className;
	}
	
	// getName, getAge은 Human 클래스에 있다.

	// print 메소드(추상 메소드 오버라이드)
	@Override
	public void print() {
		System.out.println("============ 나의 선생님 정보 =============");
		System.out.println(className + "입니다.");
		System.out.println("이름은 " + this.getName() + "입니다.");
		System.out.println("나이는 " + this.getAge() + "입니다.");
		System.out.println("성별은 " + this.getType() + "입니다.");
		System.out.println("=====================================");
	}
}
  • ClassRoom
	//학급 클래스로 선생님 객체와 학생 객체들을 가지고 있는 클래스이다.
public class ClassRoom {
	// 멤버 변수
	private String className;
	private Teacher teacher;
	private Student[] students;

	// 생성자
	ClassRoom() {
		className = "";
		teacher = new Teacher();
		students = new Student[10];
		for(int i = 0; i < students.length; i++) {
			students[i] = new Student();
		}
	}
	
	ClassRoom(String className) {
		this();
		this.className = className;
	}
	
	// setter
	public void setClassName(String className) {
		this.className = className;
		this.teacher.setClassName(className);
		for(int i = 0; i < students.length; i++ ) {
			students[i].setClassName(className);
		}
	}
	
	public void setStudent(int index, Student student) {
		this.students[index] = student;
	}
	
	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}

	// getter
	public String getClassName() {
		return this.className;
	}
	
	public Student getStudent(int index) {
		return this.students[index];
	}
	
	public Teacher getTeacher() {
		return teacher;
	}
	
	// print 메소드
	public void printClassName() {
		System.out.println(className + "입니다.");
	}
	
	public void printTeacher() {
		this.teacher.print();
	}

	public void printStudents() {
		for(int i = 0; i < students.length; i++) {
			System.out.println(i+1 + "번 학생정보.");
			students[i].print();
		}
	}
}
profile
발전하기 위한 공부

0개의 댓글