객체를 여러개 선언해야 하는 경우
배열 타입으로 한번에 선언 후 사용한다.
클래스 배열은 몇차원 배열일까? 2차원 배열
객체는 field의 주소값을 가지고 있다.
그 주소값을 가지고 있는 객체를 담는 배열이다
- 클래스명[] 배열명 = new 클래스명[길이];
- 클래스명[] 배열명 =
new 클래스명(),
new 클래스명(),
배열명[index].필드명
배열명[index].메서드명()
배열 예제
package extend;
import java.util.Scanner;
class Animal{
String name;
int age;
String feed;
public Animal() {
}
public Animal(String name, int age, String feed) {
this.name = name;
this.age = age;
this.feed = feed;
}
@Override // 정보를 담을 것
public String toString() {
// TODO Auto-generated method stub
return "이름 : " + name + "\n나이 : " + age + "살\n먹이 : "
+ feed;
}
}
public class ArInstance {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Animal[] arAni = new Animal[3];
for(int i = 0; i < arAni.length; i++) {
arAni[i] = new Animal();
System.out.println(i + 1 + "번 동물 이름 : ");
arAni[i].name=sc.next(); // 문자열
System.out.println(arAni[i].name + " 나이 : ");
arAni[i].age = sc.nextInt();
System.out.println(arAni[i].name + " 먹이 : ");
arAni[i].feed = sc.next();
}
for (int i = 0; i < arAni.length; i++) {
System.out.println(arAni[i]);
}
}
}
다른 방법
public class ArInstace {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Animal[] arAni = new Animal[3];
String name = "";
int age = 0;
String feed = "";
for(int i = 0; i < arAni.length; i++) {
System.out.println(i + 1 + "번 동물 이름 : ");
name = sc.next();
System.out.println(" 나이 : ");
age = sc.nextInt();
System.out.println(" 먹이 : ");
feed = sc.next();
arAni[i] = new Animal(name, age, feed);
}
for (int i = 0; i < arAni.length; i++) {
System.out.println(arAni[i]);
}
}
타입캐스팅이란 형을 변환하는 것.
부모 클래스명 객체 = new 자식생성자();
부모와 자식간의 공통 요소(재정의 메서드)만 사용 가능하며,
자식 클래스의 추가된 것들은 사용할 수 없다.
부모 타입으로 선언되었기 때문에 부모의 필드만 사용 가능하지만
자식 클래스에서 부모 메서드 내용을 재정의 했다면 재정의 된 메서드로 사용된다.
서브 클래스는 슈퍼 클래스의 모든 특성을 상속받는다. 따라서 서브 클래스는 슈퍼 클래스가 될 수 있다.
즉, 서브 클래스가 슈퍼 클래스가 되는 것을 업 캐스팅이라고 한다.
자식 클래스 타입으로 부모 생성자를 호출하는 오류
부모의 범위가 더 크기 때문에 자식에 담을 수 없다.
서브 클래스가 슈퍼 클래스로 변했을 때 서브 클래스의 인스턴스는 잠시 가려져 있을 뿐 사라지지 않는다.
서브 클래스의 원래 특성으로 돌려놓는 게 다운 캐스팅이다.
다운 캐스팅은 업 캐스팅과 달리 명시적으로 타입을 지정해야 한다.
각각의 타입을 확인할 때 사용하는 문법
값 instanceof 클래스타입 : 값이 클래스 타입이니?
참 또는 거짓의 결과
자식이 부모클래스 특성을 상속받아 부모 클래스 멤버에 접근가능하게 하는 것이 업캐스팅, 이 때 부모클래스 멤버만 사용가능. 자식클래스의 멤버 사용X. 사용을 원하면 명시적 형변환을 해주어야 자식클래스의 멤버도 사용이 가능 즉 부모클래스로 형 변환된 자식 클래스를 원래 자료형으로 형 변환해주어야 한다는 것. 이것이 다운캐스팅.
다운캐스팅을 하기 전에 부모 클래스로 형 변환된 인스턴스의 원래 자료형을 확인해야 변환할 때 오류를 막을 수 있다. 이를 확인하는 예약어가 바로 instanceof 이다.
instanceof 예약어는 왼쪽에 있는 변수의 원래 인스턴스형이 오른쪽 클래스 자료형인가를 확인한다.
아래 예시를 살펴보자.
package casting;
class Car {
String brand;
String color;
int price;
public Car() {
}
public Car(String brand, String color, int price) {
this.brand = brand;
this.color = color;
this.price = price;
}
void engineStart() {
System.out.println("열쇠로 시동 킴");
}
void engineStop() {
System.out.println("열쇠로 시동 끔");
}
}
class SuperCar extends Car {
String mode;
public SuperCar() {
}
public SuperCar(String brand, String color, int price, String mode) {
super(brand, color, price);
this.mode = mode;
}
void changeMode(String newMode) {
this.mode = newMode;
System.out.println("모드가 바뀌었습니다.");
}
@Override
void engineStart() {
System.out.println("음성으로 시동 킴");
}
@Override
void engineStop() {
System.out.println("음성으로 시동 끔");
}
}
public class CatingTest {
public static void main(String[] args) {
//up casting
// 부모 클래스 타입으로 자식 생성자를 호출하는 것
Car noOptionFerrari = new SuperCar();
// noOptionFerrari.engineStart(); // 자식클래스에서 재정의 한 메소드 내용으로 출력
// noOptionFerrari.changeMode(); // 자식 클래스 필드 사용 불가능
//down casting
// SuperCar brokenCar = new Car(); // 불가능
// SuperCar brokenCar = (SuperCar) new Car(); // 강제 형변환
// brokenCar.changeMode("스포츠"); // 하지만 오류
// Car클래스는 SuperCar로 형변환 할 수 없음.
Car car = new Car();
SuperCar ferrari = new SuperCar();
// 그 객체가 Car 타입이니?
if(car instanceof Car) {
System.out.println("nice casting"); // 참
} else {
System.out.println("err : wrong casting");
}
// 페라리가 Car 타입이니?
if(ferrari instanceof Car) {
System.out.println("nice casting"); // 참
} else {
System.out.println("err : wrong casting");
}
// car가 SuperCar 타입일까? 땡. 범위를 벗어났다.
if(car instanceof SuperCar) {
System.out.println("nice casting");
} else {
System.out.println("err : wrong casting"); // 거짓
}
// 타입은 Car타입이지만 SuperCar 자식 생성자가 들어가있다면?
// 내가 업캐스팅을 해도 타입만 맞다면 전부 Car 타입이다.
if(noOptionFerrari instanceof Car) {
System.out.println("nice casting"); // 참
} else {
System.out.println("err : wrong casting");
}
}
}
객체가 단 1개만 존재할 때 외부에서 new를 하지 못하게 막아주고 클래스 내부에서 new를 한 후 외부에서 선언이 아닌 사용만 해준다.
다른 패키지에서 아이언맨 이라는 클래스를 만들었다.
package single;
public class IronMan {
private IronMan() {}
public static IronMan getInstance() {
IronMan im = new IronMan();
return im;
}
public static void fight() {
System.out.println("빔 발사");
}
public void walk() {
System.out.println("날아간다");
}
}
클래스 내부에서 new를 한 getInstance();를 불렀고, 선언이 아닌 사용만 해준다. walk();의 사용이 가능해짐.
package single;
public class Stadium {
public static void main(String[] args) {
// IronMan i = new IronMan(); // 불가
// IronMan이 private이기 때문에 접근 X
IronMan i = IronMan.getInstance();
IronMan.fight();
i.walk();
}
}