클래스의 형 변환이란?
: 객체가 다른 타입으로 변환되는 것
업캐스팅과 다운캐스팅이 있다.
업캐스팅
: 하위 클래스의 객체를 상위 클래스 타입으로 변환하는 것
업캐스팅은 암시적으로 이루어지기 때문에 명시적으로 변환할 필요가 없음
🔸 업캐스팅을 하면 상위 클래스에 정의된 메서드들만 사용할 수 있고, 하위 클래스에 추가된 메서드는 사용할 수 없다.
🔸 업캐스팅을 하면 객체는 실제로는 여전히 원래의 하위 클래스의 인스턴스이지만, 상위 클래스 타입으로 참조하게 된다. => 객체의 실제 타입이 바뀌는 것이 아니라 그 객체를 가리키는 참조 변수의 타입이 바뀌는 것
다운캐스팅
: 상위 클래스 타입의 객체를 하위 클래스 타입으로 변환하는 것
업캐스팅과 달리 명시적으로 변환을 해주어야 한다
🔸 잘못된 다운캐스팅은 ClassCaseException 을 발생시킬 수 있으므로 다운캐스팅 전에 해당 객체가 실제로 해당 하위 클래스의 인스턴스인지 확인하는 것이 좋다.
Animal animal = new Cat(); // Cat 객체를 Animal 타입으로 업캐스팅
Dog dog = (Dog) animal; // 잘못된 다운캐스팅 - ClassCastException 발생
클래스의 형 변환 예
Animal 클래스 (상위클래스)
public class Animal { // 상위클래스
protected String name;
protected int age;
protected String color;
public Animal(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
public void bark() {
System.out.println("하하하~");
}
public String toString(){
return String.format("이름 : %s, 나이 : %d, 색 : %s",name,age,color);
}
}
하위 클래스들 - Cow, Horse
public class Cow extends Animal{ // 하위클래스
public Cow(String name, int age, String color) {
super(name,age,color);
}
// bart() 메소드를 overriding
public void bark() {
System.out.println("음메~ 음메~");
}
}
public class Horse extends Animal{
public Horse(String name, int age, String color){
super(name,age,color);
}
// bark() 메소드를 overriding
public void bark(){
System.out.println("히힝~ 히힝~");
}
}
테스트 코드
public class ClassTypeCastingTest_01 {
public static void main(String[] args) {
Cow cow = new Cow("누렁이",2,"노란색");
System.out.print("Cow : "+cow.toString()+", ");
cow.bark();
Horse horse = new Horse("적토마",3,"검정색");
System.out.print("Horse : " + horse.toString() + ", ");
horse.bark();
Animal animal = new Animal("",0,"");
System.out.print("Animal : " + animal.toString() + ", ");
animal.bark();
animal = cow; // Cow 클래스를 Animal 클래스에 치환. 업캐스팅
System.out.print("Animal : " + animal.toString() + ", ");
animal.bark();
animal = horse; // Horse 클래스를 Animal 클래스에 치환. 업캐스팅
System.out.print("Animal : " + animal.toString() + ", ");
animal.bark();
horse = (Horse)animal; // Animal 클래스를 Horse 클래스로 형 변환. 다운캐스팅
System.out.print("Horse : " + horse.toString() + ", ");
horse.bark();
}
}
자바에서 static 이란?
클래스 수준의 멤버를 정의할 때 사용.
- 공유 : static 변수와 메서드는 클래스의 모든 인스턴스에서 공유된다.
- 인스턴스 필요 없음 : static 멤버는 객체를 생성하지 않고도 사용할 수 있다.
- 메모리 관리 효율성 : 프로그램이 실행될 때 메모리에 로드되며 클래스가 언로드될 때 해제된다.
static 변수 (클래스 변수)
: 클래스 자체에 속하는 변수.
모든 인스턴스가 공유한다.
클래스의 모든 객체가 동일한 static 변수를 참조하기 때문에 값이 변경되면 모든 인스턴스에서 그 변경 사항이 반영된다.
static 메서드 (클래스 메서드)
: 객체 인스턴스 없이 호출할 수 있는 메서드
static 메서드는 인스턴스 변수에 접근할 수 없고, 클래스 변수나 다른 static 메서드만 사용할 수 있다.
static이 필요한 이유
메모리 사용의 효율성 (불필요한 객체 생성을 줄이고 클래스 수준의 데이터를 공유함)
유틸리티 제공 (객체와 독립적인 유틸리티 메서드와 상수를 쉽세 사용할 수 있음)
독립성 (특정 객체의 상태에 의존하지 않고도 동작하는 기능을 명확히 정의할 수 있음)
데이터 공유 (모든 인스턴스가 동일한 데이터를 사용할 수 있게 해줌으로써 일관성을 유지함)
static 멤버변수를 사용한 예
정적 멤버변수를 사진 클래스 ChildInfo
public class ChildInfo {
static int cnt; // 정적 멤버변수 선언
String name;
int age;
String telNo;
// 생성자
ChildInfo(String name, int age, String telNo) {
this.name = name;
this.age = age;
this.telNo = telNo;
cnt++;
}
static int getCnt() {
return cnt;
}
public String toString() {
return String.format("이름 : %s, 나이 : %d, 전화번호 : %s\n",name,age,telNo);
}
}
테스트코드
public class StaticMemberTest_01 {
public static void main(String[] args){
ChildInfo c1 = new ChildInfo("박인비",31,"010-1111-1111");
System.out.print(c1);
ChildInfo c2 = new ChildInfo("고구마",33,"010-3333-4444");
System.out.print(c2);
ChildInfo c3 = new ChildInfo("나폴리",12,"010-5555-6666");
System.out.print(c3);
System.out.printf("static 멤버변수 cnt : %d\n",ChildInfo.cnt);
System.out.printf("생성된 객체 갯수 : %d",ChildInfo.getCnt());
}
}
-> ChildInfo.cnt 와 ChildInfo.getCnt() 처럼 static 을 사용가능하다.
자바에서 final 이란?
: 값의 변경을 방지하거나 상속, 오버라이딩을 제한하기 위해 사용한다.
final 변수
: 값이 변경되지 않는 변수
- 초기화 이후에 값을 변경할 수 없다.
- 초기화하는 방법은 선언 시 직접 초기화하거나, 생성자를 통해 초기화할 수 있다.
final int MAX_VALUE = 100;
MAX_VALUE = 200; // 오류 발생! final 변수는 값을 변경할 수 없음
final 메서드
: 하위 클래스에서 오버라이드할 수 없는 메서드
🔸 시도시 에러 남
final 클래스
: 상속할 수 없는 클래스. 다른 클래스가 그 클래스를 확장하지 못하게 막을 수 있다.
클래스의 구현이 더 이상 변경되지 않도록 할 수 있다.
final이 필요한 이유
- 불변성 : final 키워드를 사용하여 값이 변경되지 않도록 함으로써 데이터의 불변성을 보장할 수 있다. 이는 프로그램의 예측 가능성을 높이고, 버그를 줄이는 데 도움이 된다.
- 보안 및 유지 보수 : 클래스나 메서드를 final로 선언함으로써 외부에서 임의로 변경되지 않도록 하여 코드의 안정성을 확보할 수 있다. 특히 라이브러리나 API에서 중요한 동작이 변경되지 않도록 보호하는 데 유용하다.
- 성능 최적화 : 컴파일러는 final 키워드를 사용하여 더 많은 최적화를 수행할 수 있다. 예를 들어 final 변수는 상수처럼 취급되므로 컴파일 시에 값을 인라인으로 대체할 수 있다.
'JAVA > 기초공부' 카테고리의 다른 글
[JAVA] 인터페이스 (Interfaces) (1) | 2024.10.09 |
---|---|
[JAVA] 추상 클래스 (5) | 2024.10.09 |
[JAVA] 접근 제한자 (11) | 2024.10.03 |
[JAVA] 메소드 오버라이딩 (0) | 2024.10.01 |
[JAVA] 패키지 (3) | 2024.09.29 |