56강. java.lang 패키지(1) - 자바 API 도큐먼트
57강. java.lang 패키지(2) - Object 클래스1
58강. java.lang 패키지(3) - Object 클래스2
59강. java.lang 패키지(4) - System 클래스, Class 클래스
56강. java.lang 패키지(1) - 자바 API 도큐먼트
ㅁ 이전까지는 자바 언어에 대한 내용. 11장~14장은 자바가 제공하는 다양한 표준 API에 대해 학습.
실제로 자바 프로젝트를 할 때는 자바가 제공하는 다양한 표준 API를 이용하게 됩니다.
ㅁ
- java.lang 패키지는 자바 프로그램의 기본적인 클래스를 담은 패키지이다.
- 그렇기에 java.lang 패키지의 클래스와 인터페이스는 import 없이 사용할 수 있다.
- 지금까지 System.out.println(); 메서드를 사용할 때 import java.lang; 없이 사용했음.
문자열을 저장할 때도 String 클래스를 많이 사용했는데 mport java.lang; 없이 사용했음.
이와 같이 Object, Class, Wrapper, Math 등도 import 없이 사용 가능.
- 모든 클래스는 Object를 상속해서 만들어지기 때문에 Object가 가진 필드와 메서드는 모든 클래스에서 사용 가능.
- System 클래스는 자바 프로그램이 실행하는 운영체제에 대한 정보를 가지고 있는 클래스.
운영체제가 가지고 있는 표준 입력 장치, 표준 출력장치, 자바프로그램 종료를 위해 운영체제가 자바 가상기계를 종료할 때도 사용. 메모리를 정리하기 위해 쓰레기 수집기를 실행 요청 할 때도 System 클래스 사용.
- Class 클래스는 우리가 작성한 바이트코드 파일을 메모리에 로딩할 때 사용.
그 외에도 리소스 파일을 찾을 때도 사용.
- String 클래스는 문자열을 저장할 때 사용.
- Wrapper 클래스는 포장 클래스라고도 함. 기본타입에 해당하는 클래스 타입을 Wrapper 타입이라고 함.
이들 클래스를 객체로 만들어서 기본 타입의 값을 저장시킬 수 있다.
기본 타입의 값을 객체로 만들 때 사용.
- Math 클래스는 수학 함수를 가지고 있다. 모두 정적 메서드로 선언되어 있다.
ㅁ 자바 API(Application Programming Interface)
- 자바 API는 자바 라이브러리라고도 함.
- 프로그램 개발에 자주 사용되는 자바(언어)에서 제공하는 클래스 및 인터페이스 모음.
(우리가 직접 작성하지 않고 가져다가 쓸 수 있는 다양한 클래스와 인터페이스 모음)
- 자바 API 도큐먼트는 웹페이지 형태로 제공. API 도큐먼트를 통해 사용방법을 확인할 수 있다.
- 기본 페이지: https://docs.oracle.com/en/java/javase/index.html
- 자바 8 API: https://docs.oracle.com/javase/8/docs/api/
- 자바 11 API: https://docs.oracle.com/en/java/javase/11/docs/api/
- Java Platform은 자바 언어가 실행되는 환경, Standard Edition은 JDK를 말함.
ㅁ 각 버전의 API 도큐먼트에서 java.lang 패키지에 포함된 String 클래스 찾기
ㅁ 이클립스에서 API 도큐먼트 보는 방법
- 코드 편집 뷰의 String 클래스 선택 후 F1 키 클릭 - Help 뷰로 이동 - java.lang.String 링크 클릭.
- 이클렙스에서 String 키워드를 한 번 클릭하고 F1,
Java help - Javadoc for 'java.lang.String' 클릭.
ㅁ API 도큐먼트에서 클래스 페이지 읽는 방법
- 최상단에 "SUMMARY: NESTED | FIELD | CONSTR | METHOD" 부분이 있음.
- SUMMARY: 클래스 내 선언된 멤버에 어떤 것들이 있는지 알려줌.
- NESTED: 중첩 클래스, 중첩 인터페이스
- FIELD: 필드
- CONSTR: 생성자
- METHOD: 메서드
- String 클래스의 경우 NESTED 부분은 링크가 안 걸려 있음. 링크가 없는건 이 클래스에서 제공하지 않는 것.
String에선 중첩된 클래스나 인터페이스가 없다는 뜻.
(1) 선언부
- final, abstract 키워드가 있는지 확인.
- extends 뒤 언급된 부모 클래스 확인.
- implements 뒤 인터페이스 확인. (String은 3개의 인터페이스를 구현하고 있다.)
(2) 상속 계층도
- Object가 부모다.
(3) 1번의 클래스 선언부 다음은 이 클래스를 어떻게 사용할 수 있는지 간단한 설명이 나오고 있다.
(4) Since
- 자바 몇 버전부터 이 클래스가 존재해왔는지
(5) See Also
- String과 매우 밀접한 클래스, 메서드
(6) 그리고 뒤에 Field Summary, Constructor Summary, Method Summary가 나옴.
- 최상단의 "SUMMARY: NESTED | FIELD | CONSTR | METHOD"를 클릭하면 여기로 가짐.
ㅁ Field Summary
- 필드명은 Field 칼럼에 있는 것이 필드 명
- 필드를 선언할 때 앞에 붙은게 뭐냐. 그게 Modifier and Type.
Modifier(수식자)는 접근제한자, static, abstract, final 등이 있음.
Comparator 라는 타입으로 선언함.
- Description에는 이 필드에 대한 간단한 설명.
필드를 전부 대문자로 선언하는 경우 보통 상수였다. 상수는 보통 static final로 선언하는데 static은 보이는데 final은 안 보임.
자세한 선언부를 보려면 필드명을 클릭하면 됨. 필드 선언부가 다 나옴. final도 붙어 있음.
ㅁ Constructor Summary
- 생성자 이름 누르면 생성자 선언부 나옴.
- 그런데 Description에 'Deprecated'가 있음. 이건 되도록 쓰지 말아달라는 것. 이후 버전에선 사라질 수도 있는 것.
ㅁ Method Summary
- All method(모든 메서드), Static Mehtods, Instance Methods.
- Modifier and Type은 수식자와 리턴 타입을 말함.
- Description에는 이 메서드에 대한 간단한 설명이 나옴.
메서드 명을 클릭하면 메서드에 대한 더 자세한 설명이 나옴.
- 개발을 할 때 항상 이 도큐먼트를 보면서 어떤 클래스의 어떤 필드, 어떤 생성자, 어떤 메서드를 사용하고 있는지 확인하는 습관을 기르시는게 좋습니다. 개발하다보면 API 도큐먼트 없이는 개발하기 힘듦.
- 11장 부터는 예제를 작성하거나 교재에서 설명하고 있는 클래스를 볼 때 항상 API 도큐먼트를 열어서 해당 클래스의 필드, 생성자, 메서드를 확인해가면서 공부하는 것이 중요.
57강. java.lang 패키지(2) - Object 클래스1
ㅁ Object 클래스
- 모든 클래스는 Object 클래스의 자식이거나 자손 클래스이다.
- 모든 클래스는 Object가 가진 메서드들을 그대로 사용하거나 재정의해서 사용할 수 있다.
ㅁ Object이 가진 중요한 메서드
(1) 객체비교 equals()
- equals() 메서드의 매개 타입은 Object로, 모든 객체가 매개값으로 대입될 수 있음.
- Object 클래스의 equals() 메서드는 비교 연산자인 ==와 동일 결과 리턴. (두 변수의 번지가 같은지를 봄)
- Object 클래스가 equals()를 가지고 있는 이유는 자식 클래스에서 재정의해서 쓰게끔 함이다.
두 객체가 비록 다르다 할지라도(new로 만들어 번지수가 다름), 필드값(데이터)이 같은지 비교하기 위해.
(이를 동등 객체라고 함.)
같으면 true, 그렇지 않으면 false 리턴. <- 이렇게 재정의해서 쓸 수 있다.
- equals() 메서드의 전제 조건은 두 객체가 같은 종류의 객체여야 함.
new Member()와 new Member()일 때. 다른 종류면 불가능(new Cat()과 new Dog())
- Object 클래스의 기본 equals 구현은 다음과 같습니다.
- 실행 클래스 말고 xxx 클래스에서 ctrl + 스페이스 바 해서 equals()를 오버라이딩하면 아래와 같이 나옴.
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
이 코드는 equals 메서드를 오버라이드하고 있지만, 사실상 상위 클래스의 equals 메서드를 그대로 호출하고 있습니다.
즉, 현재 클래스의 equals 메서드가 호출되면, 상위 클래스의 equals 메서드가 호출되고 그 결과가 반환됩니다.
super.equals(obj)를 호출하면 Object 클래스의 equals 메서드를 호출하게 됩니다.
이 경우, this는 여전히 equals 메서드를 호출한 현재의 자식 클래스 인스턴스입니다.
-
지금은 Member 클래스끼리 비교하고 싶은건데 Object 클래스는 모든 클래스의 최상위 클래스이므로 매개변수 obj에 어떤 타입의 객체도 다 들어갈 수 있음. 그래서,
public String id;
@Override
public boolean equals(Object obj) {
if(obj instanceof Member) {
Member member = (Member) obj;
if(id.equals(member.id)){
return true;
}
}
return false;
}
(Member 클래스 13줄) Member member = (Member) obj;
여기서 obj는 Object 타입으로 전달된 객체입니다. 부모타입의 객체를 자식타입의 객체로 다운캐스팅.
(Member 클래스 14줄) if(id.equals(member.id){
이 equals() 메서드는 String 클래스가 갖고 있는 메서드.
id 필드가 String 타입인 경우, equals 메서드는 String 클래스의 메서드를 호출하게 됩니다.
자바에서 String 클래스는 Object 클래스의 equals 메서드를 오버라이드하여 문자열 값을 비교합니다.
문자열이 같으면 true, 다르면 false 리턴.
- 객체 타입의 필드는 해당 클래스의 인스턴스를 참조합니다.
- 객체 타입 필드는 그 클래스가 제공하는 메서드를 호출할 수 있습니다.
- 예를 들어, String 타입의 필드는 String 클래스의 메서드(equals, length, charAt 등)를 호출할 수 있습니다.
(실행 클래스 10줄) Main 메서드 if 괄호 안의 equals()는 Member 클래스에서 재정의된 equals()를 호출하는거.
다른 객체라도 id가 같기 때문에 true가 나옴.
(2) 객체 해시코드 hashCode() 메서드
- 매개변수는 없고, 리턴 타입은 int.
- hashCode() 메서드가 리턴하는 값은 객체를 식별하는 하나의 정수값.
- 이 정수값은 객체가 생성될 때 해당 메모리 번지를 이용해서 만들어짐. 그래서 객체마다 다 다른 값.
- 그런데 hashCode() 메서드를 재정의 하는 경우가 있다.
메모리 번지를 이용해서 만들어진 정수값이 아닌 임의의 정수값을 리턴하도록 재정의하는 경우.
주로 두 객체가 동등한지 비교할 때.
- 일반적으로 다른 두 객체가 있는 경우, 이 두 객체를 논리적으로 동등하게 만들기 위해서는, equals() 메서드만 재정의하는게 아니라 hashCode()도 재정의해서 똑같이 만드는 작업을 하게 된다.
- 우리가 동등한지 그렇지 않은지 비교할 때 제일 먼저 뭘 검사하냐면 두 객체의 hashCode() 메서드를 호출해서 이 두 객체가 같은 값을 갖고 있는지 확인함. 같다면, equals() 메서드를 호출해서 안에 있는 데이터가 모두 똑같다면 비로소 이 두 객체는 동등 객체라고 판단.
- a.equals(b)가 true라면, a.hashCode()와 b.hashCode()는 같은 값을 반환해야 합니다
- 실제로 이런 원리로 동등 객체냐 아니냐를 판단하는 자바 API가 있음.
HashSet, Hashtable, HashMap 이들 API는 이와 같은 방법으로 동등 객체인지를 판단해서 자체적으로 처리.
-
package sec01.exam02;
public class KeyExample {
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<String, String>();
}
}
- HashMap은 13장 컬렉션 프레임워크에서 배울 클래스. key가 동등하냐 동등하지 않냐를 해시코드를 가지고 활용함.
HashMap<String, String>에서 첫번째 String은 키의 타입을 의미, 두번째 String은 값의 타입을 의미.
HashMap은 키-값으로 데이터를 저장하는 자료구조를 가지고 있다.
HashMap<String, String>은 이 키에 들어가는 타입이 String이고, 값에 들어가는 타입이 String이라는 것.
String이 같으면 같은 키로, 다르면 다른키로 인식함.
HashMap은 동일한 키를 중복저장하지 않음. 문자열이 동일한 키는 중복해서 저장될 수 없다는 것.
- ctrl + shift + o 혹은 빨간 밑줄을 클릭해서 import java.util.HashMap;를 상단에 삽입한다.
package sec01.exam02;
import java.util.HashMap;
public class KeyExample {
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("key1", "value1");
hashMap.put("key2", "value2");
hashMap.put("key1", "value3"); // 키가 같으면 예전 키를 없애고, 새로운 키로 새로운 값을 저장.
System.out.println(hashMap.size()); // 2
}
}
- hashMap은 key가 동등 객체인지 아닌지 판단할 때 우선 해시코드를 검사하고, 그 해시코드가 동일하다면 equals() 메서드를 통해서 다시 true가 나오는지 확인해서 동등 객체인 경우에는 한번만 저장이 되도록 되어있다.
- HashMap의 key 타입에 String 대신 임의의 클래스 넣기.
package sec01.exam02;
public class Momo {
public int number;
public Momo(int number) {
this.number = number;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Momo) {
Momo compareKey = (Momo) obj;
if(this.number == compareKey.number) {
return true;
}
}
return false;
}
}
package sec01.exam02;
import java.util.HashMap;
public class KeyExample {
public static void main(String[] args) {
HashMap<Momo, String> hashMap = new HashMap<Momo, String>();
hashMap.put(new Momo(1), "value1");
hashMap.put(new Momo(2), "value2");
hashMap.put(new Momo(1), "value3");
System.out.println(hashMap.size()); // 3
}
}
- 3이 나왔다는 얘기는 첫번째 Momo 객체와 두번째 Momo 객체를 서로 다른 객체로 보고 따로 따로 저장했다는 것.
- equals만 재정의해서는 hashMap은 Momo 객체를 같은 동등 객체로 판단하지 않는다는 것.
@Override
public int hashCode() { // Momo에 hashCode() 메서드 오버라이딩. 이러면 결과는 2
return number;
}
- Momo에서 equals()와 hashCode()를 재정의하는 이유는, Object를 상속받아서 다 가지고 있기 때문이다.
- HashMap 클래스 자체에는 equals()와 hashCode() 메서드가 직접 구현되어 있지 않습니다. 이 메서드들은 Object 클래스에서 상속받은 것입니다. HashMap 클래스는 키와 값으로 사용되는 객체의 equals()와 hashCode() 메서드를 사용합니다.
HashMap 클래스는 내부적으로 해시 테이블을 사용하여 데이터를 저장하며, 키를 기준으로 데이터를 관리합니다. 이때 키의 동등성 비교와 해시 코드 계산은 객체의 equals()와 hashCode() 메서드에 의존합니다.
- Java에서 객체의 equals() 메서드는 기본적으로 객체의 참조(메모리 위치)를 비교합니다. 따라서 두 객체가 동일한 메모리 위치를 가리킬 때만 equals()는 true를 반환합니다. 그러나 때로는 객체의 내부 상태를 기준으로 동등성을 판단해야 할 필요가 있습니다. 예를 들어, Momo 클래스의 경우 숫자(number 필드)를 기준으로 동일성을 판단할 수 있습니다. 이를 위해 equals() 메서드를 재정의하여 내부 필드들을 비교하는 방식으로 동등성을 정의할 수 있습니다.
58강. java.lang 패키지(3) - Object 클래스2
ㅁ 이어서 예제 하나 더.
public static void main(String[] args) {
HashMap<Member, String> hashMap2 = new HashMap<Member, String>();
hashMap2.put(new Member("fall"), "value1");
hashMap2.put(new Member("winter"), "value2");
hashMap2.put(new Member("fall"), "value3");
System.out.println(hashMap2.size()); // 2
}
public class Member {
public String id;
Member(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Member) {
Member member = (Member) obj;
if(id.equals(member.id)){
return true;
}
}
return false;
}
@Override
public int hashCode() {
return id.hashCode();
}
}
- id는 String 타입. String 타입은 문자열이 같으면 동일한 해시코드가 나오도록 재정의되어 있다.
(3) 객체 문자 정보 toString()
- Object 클래스의 toString() 메서드는 개체의 문자 정보를 리턴함.
기본적으로 '클래스이름@16진수해시코드'로 구성된 문자 정보.
- toString() 메서드를 재정의하는 경우. 유익한 정보를 리턴하기 위해.
이 기본 구현은 객체의 클래스 이름과 해시 코드를 반환하는 간단한 문자열을 생성합니다. 하지만 이는 대개 개발자가 원하는 형태의 객체 정보를 제공하지 않습니다. 따라서 일반적으로 클래스에서 toString() 메서드를 오버라이드하여 객체의 상태를 문자열로 표현하는 방식을 변경합니다
-
import java.util.Date;
public class ToStringExample {
public static void main(String[] args) {
Object obj1 = new Object();
Date obj2 = new Date();
System.out.println(obj1.toString());
System.out.println(obj2.toString());
}
}
[출력 결과]
java.lang.Object@7a0ac6e3
Sun Jun 16 00:36:38 KST 2024
- Date 타입 변수 obj2를 선언하고 Date 타입 객체 대입.
- ctrl + shift + o 해서 import java.util.Date; 선택.
Date 클래스는 java.util에 소속된 표준 API.
- Date라는 클래스는 Object이 가진 toString() 메서드를 재정의해서 날짜 정보 출력.
= System.out.println() 메서드는 객체를 출력할 때 내부적으로 toString() 메서드를 호출하여 객체의 문자열 표현을 출력합니다.
System.out.println(obj1);
System.out.println(obj2); // 이래도 결과는 같다.
-
public class SmartPhone {
private String company;
private String os;
public SmartPhone(String company, String os) {
this.company = company;
this.os = os;
}
@Override
public String toString() {
return company + ", " + os;
}
}
public static void main(String[] args) {
SmartPhone myPhone = new SmartPhone("구글", "안드로이드");
System.out.println(myPhone); // 구글, 안드로이드
}
59강. java.lang 패키지(4) - System 클래스, Class 클래스
ㅁ System 클래스
- 운영체제가 가진 기능(입출력장치)을 이용할 수 있도록 자바에서는 System 클래스에서 필드와 메서드를 제공한다.
- System 클래스의 모든 필드와 메서드는 정적 필드 및 정적 메서드로 구성.
※ System.out.println
- System 클래스는 java.lang 패키지에 포함된 자바의 기본 클래스입니다.
- System 클래스는 시스템 관련 정보와 기능을 제공하며, 그 중 하나가 표준 입출력 스트림 관리입니다.
- PrintStream 클래스는 java.io 패키지에 포함되어 있습니다.
- 텍스트 출력 기능을 제공하는 클래스입니다. 데이터를 텍스트 형식으로 출력하고, 다른 출력 스트림(OutputStream)으로 데이터를 보냅니다.
- PrintStream은 자동으로 문자열, 숫자, 객체 등을 적절한 형식으로 변환하여 출력합니다.
- System 클래스에는 out이라는 정적(static) 필드가 있습니다.
- 이 필드는 PrintStream 타입이며, 기본적으로 표준 출력 스트림을 가리킵니다.
- 표준 출력 스트림은 콘솔(터미널)로 데이터를 출력하는 데 사용됩니다.
- 자바 프로그램이 실행될 때, System 클래스의 out 필드는 JVM(Java Virtual Machine)에 의해 초기화됩니다.
- 초기 값은 PrintStream 객체로 설정되며, 이 객체는 표준 출력 스트림(System.out)을 가리킵니다.
- System.out.println("Hello, World!");와 같은 명령을 호출하면, System 클래스의 out 필드에 있는 PrintStream 객체의 println 메서드가 호출됩니다.
- PrintStream 객체는 println 메서드를 통해 전달된 문자열("Hello, World!")을 적절한 형식으로 변환하고, 내부적으로 보유한 출력 스트림으로 데이터를 보냅니다.
- 기본적으로 이 출력 스트림은 표준 출력 스트림, 즉 콘솔입니다.
(1) 프로그램 종료 exit()
- exit() 메서드 호출하여 JVM을 강제 종료하는 역할. ( = 자바 프로그램 종료)
- exit() 메서드를 호출할때 지정하는 int 매개값을 종료 상태값이라 함.
- status: 정수형 매개변수로, 프로그램의 종료 상태를 나타냅니다. 일반적으로, 0은 정상 종료를 의미하고, 0이 아닌 다른 값은 비정상 종료나 오류를 의미합니다.
- 즉시 종료: System.exit() 메서드는 프로그램을 즉시 종료하며, 메서드 호출 후의 코드는 실행되지 않습니다.
- System.exit(0); // System이라는 클래스로 접근했기 때문에 exit은 틀림없이 정적 메서드.
(2) 현재 시각 읽기 currentTimeMillis(), nanoTime()
- currentTimeMillis(): 1000분의 1초 단위 long 값 리턴.
- nanoTime(): 10억분의 1초 단위 long 값 리턴.
-
System.out.println(System.currentTimeMillis()); // 1718523226059
System.out.println(System.nanoTime()); // 19961890053400
System.currentTimeMillis()
- 기능: 현재 시스템 시간을 1970년 1월 1일 UTC 자정 이후 경과한 시간으로 반환합니다. 반환 값은 밀리초(milliseconds) 단위의 long 값입니다.
- 사용 목적: 일반적으로 날짜와 시간을 기준으로 특정 시점을 구하거나, 일정 기간(시간, 분, 초, 밀리초)을 계산할 때 사용합니다.
- 예를 들어, System.currentTimeMillis()가 1687027200000을 반환한다고 하면, 이는 1970년 1월 1일 이후 경과한 총 밀리초를 나타냅니다.
System.nanoTime()
- 기능: 상대적인 시간을 나노초(nanoseconds) 단위의 long 값으로 반환합니다. 이 값은 JVM의 시작 시점 이후 경과된 시간을 나타냅니다.
- 사용 목적: 코드 블록의 실행 시간 등을 정밀하게 측정할 때 사용됩니다. 절대적인 시간을 측정하는 용도로는 사용되지 않습니다.
- 예를 들어, System.nanoTime()이 2734653000000을 반환한다고 하면, 이는 JVM이 시작된 이후 경과된 나노초를 의미합니다.
-
long time1 = System.nanoTime(); // 시작시간
int sum=0;
for(int i=1; i<1000000; i++) {
sum = sum +i;
}
long time2 = System.nanoTime(); // 종료시간
System.out.println(time2 - time1); // 2540200 나노초 <- 0.0025초 정도
어떤 프로그램의 실행시간을 측정하기 위해서는 시작시간과 종료시간을 측정해서, 종료시간에서 시작시간을 빼서 실행시간을 구할 수 있다.
ㅁ Class 클래스
- 자바는 클래스와 인터페이스의 메타 데이터를 Class 클래스로 관리
- 메타데이터: 타입 이름(클래스, 인터페이스의 이름) 및 파일 경로 정보, 필드 정보, 생성자 정보, 메서드 정보
- Class 객체는 해당 클래스의 이름, 패키지, 메서드, 필드, 인터페이스, 슈퍼클래스 등 클래스 자체에 대한 메타데이터를 포함합니다.
- Class 객체는 자바 클래스에 대한 메타데이터를 포함하고 있는 객체입니다.
- 자바의 모든 클래스는 런타임에 자신을 나타내는 Class 객체를 가지고 있습니다.
ㅁ Class 객체 얻기 getClass(), forName()
- 자바에서 "클래스 객체(Class object)를 얻는다"는 것은, 자바의 Class 클래스의 인스턴스를 얻는다는 의미입니다.
(1) 클래스로부터 얻는 방법
i) Class clazz = 클래스이름.class
- 클래스 타입의 변수를 선언하고 해당 클래스이름.class를 하게 되면, "클래스이름"의 클래스의 클래스 객체의 참조가 clazz에 저장이 된다.
ii) Class clazz = Class.forName("패키지...클래스이름")
- 클래스 타입의 변수를 선언하고 Class가 가지고 있는 정적 메서드인 forName을 호출해서 문자열로 "패키지...클래스이름" 이와 같이 클래스의 전체 이름을 주게되면, 문자열에 있는 해당 클래스의 클래스 객체가 생성되고 그 번지가 clazz에 저장된다.
(2) 객체로부터 얻는 방법
- 객체가 이미 생성되어 있는 경우, 객체로부터 class 객체를 얻을 수 있다.
iii) Class clazz = 참조변수.getClass();
- 객체를 참조하는 변수.getClass() 메서드를 호출하게 되면 이 변수가 참조하는 객체의 클래스 객체를 얻어서 그 번지를 clazz에 저장함.
ex) String 클래스
i) Class var1 = String.class;
- String 클래스의 클래스 객체가 생성되어서 그 번지가 var1 변수에 저장됨.
ii) Class clazz = Class.forName("java.lang.String");
- String 클래스의 전체 이름(패키지 이름을 포함한 전체 이름).
- 이 경로의 String 클래스의 Class 객체를 생성하고 그 번지를 clazz에 저장함.
iii) String str = "감자바";
Class clazz = str.getClass();
- str이라는 참조변수로 getClass() 메서드를 호출하면 String 클래스를 가리키는 Class 객체를 얻을 수 있다.
- String 객체 str을 통해 getClass() 메서드를 호출하면, 이는 String 클래스에 대한 Class 객체를 반환합니다.
- ClassExample.java
package sec01.exam08;
public class ClassExample {
public static void main(String[] args) throws ClassNotFoundException {
Class var1 = Car.class;
Class var2 = Class.forName("sec01.exam08.Car"); // 빨간 밑줄.
Car car = new Car();
Class var3 = car.getClass();
System.out.println(var1); // class sec01.exam08.Car
System.out.println(var2); // class sec01.exam08.Car
System.out.println(var3); // class sec01.exam08.Car
System.out.println(car); // sec01.exam08.Car@17c68925
}
}
- 빨간 밑줄이 뜨는 이유.
forName이라는 메서드는 ClassNotFoundException을 발생시킬 수 있음.
저 문자열의 경로에 클래스가 존재하면 ClassNotFoundException가 발생하지 않지만,
없으면 ClassNotFoundException이 발생하니 예외처리를 하라는 거.
해결법 1. Add throws declaration
해결법 2. Surround with try/catch
- Car 클래스의 Class 객체를 3가지 방법으로 얻어서 대입을 했는데, 참조하는 객체는 모두 같은 객체이다.
Car 클래스는 하나기 때문에 이들 변수가 참조하는 Class 객체도 하나다.
ㅁ 이렇게 Class 객체를 얻고 나서는?
- 타입 이름(getName() 메서드)을 조사할 수도 있고, 클래스와 인터페이스가 저장된 경로 정보, 클래스와 인터페이스가 가진 필드, 생성자, 메서드 정보도 얻을 수 있다.
- 자바에서는 이러한 필드, 생성자, 메서드 정보를 얻어내는 것을 reflection이라고 함.
- 자바에서 리플렉션(reflection)은 프로그램이 자신의 구조를 분석하고 수정할 수 있는 능력을 의미합니다. 이는 실행 중에 클래스의 정보(메서드, 필드, 생성자 등)를 검사하거나 수정할 수 있도록 하는 메커니즘을 제공합니다. 리플렉션을 사용하면 컴파일 시간에는 알 수 없었던 클래스의 정보를 동적으로 얻어내어 처리할 수 있으며, 일반적으로 런타임 환경에서 자바 객체와 클래스를 조작하는 데 사용됩니다.
ㅁ
System.out.println(var1.getName()); // sec01.exam08.Car
- Car클래스의 전체 이름을 얻을수있다.
System.out.println(var1.getSimpleName()); // Car
- 패키지 이름을 제외한 클래스 이름만 출력.
System.out.println(var1.getPackage()); // package sec01.exam08
- getPackage() 메서드는 패키지라고 하는 타입의 객체를 리턴함.
System.out.println(var1.getPackage().getName()); // sec01.exam08
- getPackage()가 리턴하는 객체(패키지)가 가지고 있는 getName() 메서드를 호출. 패키지 이름만 출력.
ㅁ java.lang.Class의 메서드들
- getDeclaredConstructors(), getDeclaredMethods(), getDeclaredFields()는 getXXX() 메서드와 달리 해당 클래스의 모든 생성자, 메서드, 필드에 접근할 수 있습니다. 따라서 private 접근 제어자를 가진 생성자, 메서드, 필드도 포함됩니다
- getMethod()과 getField() 메서드는 public 접근 제어자를 가진 메서드와 필드만 접근할 수 있습니다.
ㅁ Class 클래스의 또 다른 용도
- 클래스 경로를 활용하여 리소스 절대 경로 얻기
- Class 객체는 파일 경로 정보를 가지고 있어 이 경로를 활용해서 주위의 다른 리소스 파일의 경로를 얻을 수 있음.
- photo1과 photo2라는 그림파일의 경로를 얻고 싶다면,
Class var1 = Car.class; // Car 클래스의 Class 객체를 저장.
String photo1Path = var1.getResource("photo1.jpg").getPath();
String photo2Path = var1.getResource("images/photo2.jpg").getPath();
- Class가 가지고 있는 getResource()메서드 호출. 매개 변수에 파일이름을 줌.
- photo1.jpg는 Car.class와 같은 위치에 있어서 "photo1.jpg" 이렇게 줄 수 있다.
- photo2.jpg는 하위폴더에 있기 때문에 "images/photo2.jpg" 이렇게 준다.
- 동일한 위치에 있으면 파일명만, 하위 폴더에 있으면 하위폴더명/파일명.
- 이렇게 URL을 얻어서 URL객체가 가지고 있는 메서드 중에서 getPath()를 호출하면 photo1.jpg에 대한 절대 경로를 얻을 수 있다. String형 변수 photo1path에는 이 그림 파일의 절대 경로가 저장됨.
C:/SelfStudyJava/chap11/bin/sec01/exam09/photo1.jpg // photo1Path
C:/SelfStudyJava/chap11/bin/sec01/exam09/images/photo2.jpg // photo2Path
- 절대경로를 구해서 이미지 데이터를 읽고 그것을 UI에 나타낼 수 있다.
UI 프로그램에서 이미지에 대한 절대경로가 필요할 때 이와 같은 방법으로 많이 사용한다.
- Class var1 = ResourcePathExample.class; 이거 대신에 exam09에 Car 클래스를 만들고,
Class var1 = Car.class; 해도 결과는 같다.
- 리소스 파일의 위치를 URL 형태로 얻고자 할 때는 getResource()를 사용하고, 리소스 파일의 내용을 InputStream으로 읽고자 할 때는 getResourceAsStream()을 사용하는 것이 적절합니다.
'혼자 공부하는 자바' 카테고리의 다른 글
혼자 공부하는 자바 (65강 ~ 66강) (0) | 2024.06.23 |
---|---|
혼자 공부하는 자바 (60강 ~ 64강) (0) | 2024.06.17 |
혼자 공부하는 자바 (51강 ~ 55강) (0) | 2024.06.14 |
혼자 공부하는 자바 (46강 ~ 50강) (1) | 2024.06.09 |
혼자 공부하는 자바 (40강 ~ 45강) (0) | 2024.05.31 |