최상위에는 Trowable 예외 클래스를 상속하고 그 후에 Error와 Exception으로 나누어진다.
모든 Runtime에러가 Exception으로 구서오딘 것은 아니다. 바로 종료하게 되는 Error도 있음
Error는 Handling 할 수 없음
화면에 뜨는 오류 Exception 뒤에 오게 되는 내용임
중요 예외 객체 생성자에 문자열을 넣음으로써 그 문자열이 getMessage() 메소드의 리턴값이 되게 할 수 있다.
IOException
의 하위 클래스)IOException
발생 가능이를 try의 파라미터에서 resource를 넣어줌으로써 close() 메소드를 호출할 필요 없이, 자원을 자동으로 해제해줌 (try 블록이 끝날 때 자동으로 자원이 해제됨) , close 보장!
주의! 이 자원은 AutoCloseable 인터페이스를 구현해야만함
이 자원은 try문 내부에서만 사용됨
정상적인 상황: try문 들어가기 전 resource 할당, try문 실행, try 끝나면 바로 close, 그 후 catch, finally절이 실행됨
비정상적인 상황: try문 들어가기 전 resource 할당, try문 실행중 예외발생, catch가기 전 바로 close, 그 후 catch, finally절이 실행됨
정적 초기화 블록: static 멤버를 초기화하는 블록이다. 초기화는 처음 클래스 로드 바로전에 한 번만 실행된다. 정적 초기화 블록은 static 키워드를 사용하여 정의함
정적 초기화 블록 초기화 과정
주의! 선언과 함께 초기화하는 경우
정적 초기화 블록 내에서 선언된 위치보다 위에서 초기화(쓰는 것)는 가능하지만, 읽어가는것은 안된다!
선언부를 정적 초기화 블록 위에서 해주어서 읽고 쓰기를 가능하게 함

정적 초기화 블록 예시
java코드 복사
public class Example {
static int staticVar;
static {
// 정적 초기화 블록
staticVar = 10;
System.out.println("Static initialization block executed.");
}
public static void main(String[] args) {
System.out.println("StaticVar: " + staticVar);
}
}
위 예제에서 static
블록은 staticVar
를 초기화하고, 클래스가 처음 로드될 때 "Static initialization block executed." 메시지를 출력한다. 주의! public class에서 정적 초기화 블록은 main함수 실행 전에 바로 클래스가 로딩되어 가장 먼저 실행된다!
인스턴스 초기화 블록: 생성자와 비교하자면, 생성자는 외부값을 받아서 초기화하는 것이지만, 내부적으로 초기화할때는 인스턴스 초기화 블록을 사용한다.
클래스의 객체가 생성될 때마다 실행된다. 인스턴스 필드를 초기화하거나 객체 생성 시에 필요한 설정을 수행하는 데 사용된다.
인스턴스 초기화 블록 초기화 과정
static 초기화 먼저 진행한다 → static 필드 공간 및 기본값 할당, 정적 초기화 블록 및 초기화 위에서부터 아래로 실행
<클래스 로딩>
<객체 생성>
new를 통해 heap에 객체가 생겨서 nonstatic 필드의 공간과 기본값을 할당한다.
그 후 nonstatic 초기화 블록 및 초기화 위에서부터 아래로 실행
그 다음 생성자 호출
인스턴스 초기화 블록에서도 선언의 위치 주의!

인스턴스 초기화 블록 예시
java코드 복사
public class Example {
int instanceVar;
{
// 인스턴스 초기화 블록
instanceVar = 20;
System.out.println("Instance initialization block executed.");
}
public Example() {
System.out.println("Constructor executed.");
}
public static void main(String[] args) {
Example example = new Example();
System.out.println("InstanceVar: " + example.instanceVar);
}
}
위 예제에서 인스턴스 초기화 블록은 instanceVar
를 초기화하고, 인스턴스가 생성될 때마다 "Instance initialization block executed." 메시지를 출력합니다. 이후 생성자가 호출되어 "Constructor executed." 메시지를 출력합니다.
Cloneable
인터페이스와 Object
클래스의 clone()
메서드를 사용하여 객체를 복제할 수 있습니다. 객체 복제는 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy) 두 가지 방식으로 나뉩니다.Cloneable
인터페이스는 마커 인터페이스(Marker Interface)로, 아무 메서드도 선언하지 않습니다. 이 인터페이스는 해당 클래스가 clone()
메서드를 사용할 수 있다는 신호로 사용됩니다.
중요 clone()의 오버라이딩 방법
public Object clone() throws CloneNotSupportedException {
return super.clone();}
형식으로 clone()함수를 오버라이드 해준다! 구현이 간단
- throws를 해주어야함 → 컴파일 에러
- clone()메소드를 사용하는 부분에서 try catch를 사용해야함
→ 컴파일 에러
- Object형식으로 리턴하기 때문에 clone()메소드 사용 후에 타입캐스팅을 해주어야함
- Closeable을 구현하지 않으면 무조건 예외를 발생시킴
clone() 메소드를 오버라이딩한 후에 클래스에 implements Cloneable을 해주어야 정상적으로 작동함
주의! Cloneable을 구현해주지 않으면 clone을 만들 수 없는 클래스라고 인식하여서 예외를 발생시킴!
클론 메소드에서 여러 메소드 사용가능
중요 p1과 p2는 같은 필드값을 가지지만 같은 레퍼런스를 가리키는 것이 아님을 알 수 있음
얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)
주의! String은 깊은 복사가 이뤄지니 상관하지 말 것!
clone() 함수를 사용자 클래스 타입으로 return
얕은 복사 예제
java코드 복사
class Person implements Cloneable {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
public static void main(String[] args) {
try {
Person person1 = new Person("John", 30);
Person person2 = (Person) person1.clone();
System.out.println("person1: " + person1);
System.out.println("person2: " + person2);
System.out.println("Are they the same object? " + (person1 == person2));
System.out.println("Do they have the same name? " + (person1.name == person2.name));
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
위의 코드에서 person1
과 person2
는 다른 객체이지만, 그 안의 필드 name
은 동일한 문자열 객체를 참조합니다.
깊은 복사 예제
깊은 복사를 위해서는 모든 참조된 객체들도 복제해야함
java코드 복사
class Address implements Cloneable {
String city;
String country;
Address(String city, String country) {
this.city = city;
this.country = country;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable {
String name;
int age;
Address address;
Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone();
cloned.address = (Address) address.clone();
return cloned;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + ", address=" + address.city + ", " + address.country + "}";
}
public static void main(String[] args) {
try {
Address address = new Address("New York", "USA");
Person person1 = new Person("John", 30, address);
Person person2 = (Person) person1.clone();
System.out.println("person1: " + person1);
System.out.println("person2: " + person2);
System.out.println("Are they the same object? " + (person1 == person2));
System.out.println("Do they have the same address object? " + (person1.address == person2.address));
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
위의 코드에서 person1
과 person2
는 서로 다른 객체이며, address
필드도 각각 독립적인 객체를 가집니다.
public
으로 변경해야 함.멤버로 사용하기 때문에 static으로 정의가 가능하다
내부 클래스에서도 static이든 아니든 똑같이 필드, 메소드, 생성자를 만들어 줄 수 있음
Local 클래스에서 외부클래스 접근하는 경우: 내부 클래스에서 외부클래스 접근하는 것과 접근 방법에 차이 없음!! 이름 겹쳐도 클래스타입이름.this로 접근하면 된다
중요 Local 클래스에서 메소드에 접근하는 경우:
메소드안에서 Local 클래스보다 위에서 선언 및 값이 할당된 것을 클래스 내부에서 사용가능하다!
이름이 없어서 생성자를 만들 수 없고, super 생성자를 사용하지 못하는데, ()안을 super와 동일하게 생각하고 사용해주면 된다!
인터페이스는 생성자 없지만, Anonymous Class 생성 시에는 괄호를 꼭 넣어줘야함
https://believed-poinsettia-f0f.notion.site/f05bfd3103ee4c1f88d079fda21dc5f1?pvs=4