java.lang 패키지 소개
- 자바가 기본으로 제공하는 라이브러리 (클래스 모음) 중 가장 기본인 되는 것
- lang 은 language 의 줄임 말이다.
- 모든 java 프로젝트 에서 기본 제공 되기 때문에 자동 import 된다.
java.lang 패키지의 대표 클래스
- Object : 모든 자바 객체의 부모 클래스
- String : 문자열
- Integer, Long, Double : 래퍼타입 → 기본형 데이터 타입을 객체로 만든 것
- Class : 클래스 메타 정보
- System : 시스템과 관련된 기본 기능들 제공
Object 클래스
- 자바에서 모든 클래스의 최상위 부모 클래스는 항상 Object 클래스 이다.
package lang.object;
// 부모가 없으면 묵시적으로 Object 클래스를 상속 받는다.
public class Parent {
public void parentMethod() {
System.out.println("Parent.parentMethod");
}
}
package lang.object;
// Parent 를 명시적으로 상속 받늗다.
public class Child extends Parent{
public void childMethod() {
System.out.println("Child.childMethod");
}
}
⇒ 다음과 같은 상속 구조를 갖게 된다.
⇒ 모든 자바의 최종 부모는 Object 가 되게 된다.
package lang.object;
public class ObjectMain {
public static void main(String[] args) {
Child child = new Child();
child.childMethod();
child.parentMethod();
// toString 은 Object 클래스의 메서드 => Object 로 부터 상속 받아 쓰게 된다.
String string = child.toString();
System.out.println(string);
}
}
⇒ Parent 는 Objcet 를 묵시적으로 상속 받았기 때문에 child 클래스 내에서도 Object 의 기능인 toString 을 사용 할 수 있는것 이다.
자바에서 Object 클래스가 최상위 부모 클래스인 이유??
- 공통 기능 구현
- 모든 객체에서 필요한 공통 기본 기능을 개발자가 직접 메서드를 만드는 것은 상당히 번거롭고 개발자 마다 메서드의 기능, 명 이 일관 되지 않기 때문에 공통 기능 구현 및 통일성을 위해 최상위 클래스로 사용되게 된다. → 프로그래밍의 단순화, 일관성의 목적
- Object 제공하는 기능의 예
- 객체 정보 제공 → toString()
- 객체의 같음 을 비교 → equals() 등등의 기능이 있다.
- 다형성의 기본 구현
- Object 는 모든 class 들의 부모 class 타입 이다. → 따라서 어떤 타입으로 값을 받아와도 Object 타입으로 받아 올 수 있다.
Object 다형성
- Object 는 모든 클래스의 부모 클래스 이므로 → 모든 객체를 참조 할 수 있다 .
Object dog = new Dog();
Object car = new Car();
⇒ Object 는 모든 객체의 부모 타입이므로 어떤 객체든 담을 수 있다.
- Object 타입의 Car class
package lang.object.poly;
public class Car {
public void move() {
System.out.println("자동차 이동");
}
}
- Object 타입의 Dog class
package lang.object.poly;
public class Dog {
public void sound() {
System.out.println("멍멍");
}
}
- Car 타입과 Dog 타입 class 를 사용 하는 클래스에서 Object 타입의 메서드 사용
package lang.object.poly;
public class ObjectPolyExample1 {
public static void main(String[] args) {
Dog dog = new Dog();
Car car = new Car();
action(dog);
action(car);
}
private static void action(Object obj) {
// obj.sound(); // 컴파일 오류 Object 는 sound() 기능이 없다.
// obj.move(); // 컴파일 오류 , Object sms move() 가 없다.
// 객체에 맞는 다운캐스팅 으로 호출 가능
if (obj instanceof Dog dog) {
dog.sound();
} else if (obj instanceof Car car) {
car.move();
}
}
}
⇒ 결론 Object 는 자식을 모두 담을 수 있지만 자식 내에 무었이 들어 있는지 자세히 알 순 없다.
⇒ 그래서 다운 캐스팅을 사용해 준다.
Object 배열
- Object 는 모든 타입의 객체를 담을수 있고 Object 타입의 배열을 만들면 세상의 모든 객체를 담을 수 있는 배열이 된다.
Object - toString() 메서드
- toString 메서드는 객체에 저장된 정보를 문자열 형태로 반환 해주는 기능을 말한다. → 디버깅과 로깅때 유용하게 사용 된다.
toString 오버라이딩
- 기본적으로 toString 메서드를 사용해 나온 객체 값은 사용하기 쉽지 않아 오버라이딩 하여 사용한다.
메서드 오버라이딩하여 toString을 사용할 수 있다 Dog class 만 오버라이딩 하여 사용해보면
package lang.object.tostring;
public class Dog {
private String dogName;
private int age;
public Dog(String dogName, int age) {
this.dogName = dogName;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"dogName='" + dogName + '\\'' +
", age=" + age +
'}';
}
}
⇒ Dog class
package lang.object.tostring;
public class Car {
private String carName;
public Car(String carName) {
this.carName = carName;
}
}
⇒ Car class
package lang.object.tostring;
public class ToStringManin2 {
public static void main(String[] args) {
Car car = new Car("Model Y");
Dog dog1 = new Dog("멍멍이1", 2);
Dog dog2 = new Dog("멍멍이2", 5);
System.out.println("1. 단순 toString 호출");
System.out.println(car.toString());
System.out.println(dog1.toString());
System.out.println(dog2.toString());
System.out.println("2. println 내부에서 toString 호출");
System.out.println(car);
System.out.println(dog1);
System.out.println(dog2);
}
}
⇒ Dog 와 Car 를 사용하면
1. 단순 toString 호출
lang.object.tostring.Car@7a81197d
Dog{dogName='멍멍이1', age=2}
Dog{dogName='멍멍이2', age=5}
2. println 내부에서 toString 호출
lang.object.tostring.Car@7a81197d
Dog{dogName='멍멍이1', age=2}
Dog{dogName='멍멍이2', age=5}
⇒ 메서드 오버라이딩 한것은 한것대로 결과가 나오고 println에서도 오버라이딩 한것을 호출 한다.
- 정리
- Car 인스턴스는 오버라이딩 하지 않아서 기본 메서드 사용
- Dog 객체는 오버라이딩을 한 덕분에 객체상태를 명확하게 제공
오버라이딩한 객체의 참조값을 찾고 싶다면??
String refValue = Integer.toHexString(System.identityHashCode(dog1));
System.out.println("refValue = " + refValue);
⇒ 다음과 같이 사용하면
refValue = 8efb846
⇒ 우리가 일반적으로보는 16진수의 참조값을 볼 수 있다.
Object와 OCP
public class ObjectPrinter {
public static void print(Object obj) {
String string = "객체 정보 출력: " + obj.toString();
System.out.println(string);
}
}
⇒ ObjectPrinter 라는 class 는 Object class에 의존 한다고 표현 하는데 Object class 는 구체적인 Dog나 Car 같은 우리가 생성한 구체적 class 를 의존하는것이 아니기 때문에 추상적인것을 의존한다 라고 표현한다.
ObjectPrinter class의 특징 살펴보기
- 다형적 참조 - print(Object obj) 타입의 매개변수를 사용하여 다형적 참조를 가능하게 한다 → Dog, Car 객체등 모든 객체 받을 수 있게
- 메서드 오버라이딩 - Object 클래스는 모든 객체의 부모 이기때문에 Object가 갖고 있는 모든 메서드 (toString()) 과 같은 것을 모든 클래스에서 메서드 오버라이딩 할 수 있다.
OCP 원칙
- Open : 새로운 클래스를 추가, toString() 을 오버라이딩해 기능 확장 가능
- Closed : 새로운 클래스가 추가되도 ObjectPrinter는 변경하지 않고 그대로 사용 가능하다.
정리
- 지금까지 배운 내용은 System.out.println() 의 기능을 살펴본 것이다.
- 자바 언어가 기본 제공하는 다양한 메서드들은 개발자가 필요에 따라 오버라이딩 해서 사용할 수 있도록 설계되어 있다.
의존관계?
- 정적 의존관계 : 주로 class 간의 관계를 의미하고, class 관계 그림이 정적 의존 관계이다, 프로그램을 실행시키지 않고 class 내에 사용하는 타입들만 보고 쉽게 의존관계를 파악할 수 있다.
- 동적 의존관계 : 프로그램을 실행하는 런타임 에서 확인할 수 있는 관계, Object 타입으로 모든 것을 받는 경우 프로그램을 실행 시켜 Car 타입인지 Dog 타입인지 알 수 있는 관계를 말한다.
⇒ 단순히 의존관계 또는 어디에 의존한다고 하면 주로 정적 의존 관계를 말한다.
equals() - 1. 동일성과 동등성
- 동등성 : Object 에서 제공하는 동등성 비교를 위한 equals() 메서드 이다. → 두 객체가 논리적으로 동등한지 확인
- 동일성 : == 연산자를 사용하여 두 객체의 참조가 동일한 객체를 가리키는지 확인 → 완전히 같은지 확인
- equals 실행 순서 예시
user1.equals(user2)
return (user1 == user2) // Object.equals 메서드 안
return (x001 == x002) // Object.equals 메서드 안
return false
false
⇒ equals 메서드는 위와 같이 작동한다. 그러므로 특정한 값의 동등성 비교를 사용하고 싶으면 equals 메서드를 재정의 해야 한다
equals() - 2. 구현
package lang.object.equals;
public class UserV2 {
private String id;
public UserV2(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
// 인자로 넘어온 id 를 변수에 담기 Object 에는 id가 없어서 다운 캐스팅
UserV2 user = (UserV2) obj;
// 내 id와 넘어온 id 같은지 비교 하기
return id.equals(user.id);
}
}
⇒ equals 메서드를 오버라이딩 하여 비교할 변수 를 지정해 변수끼리 비교 하게 만들기
package lang.object.equals;
public class EqualsMainV2 {
public static void main(String[] args) {
UserV2 user1 = new UserV2("id-100");
UserV2 user2 = new UserV2("id-100");
System.out.println("identity = " + (user1 == user2));
System.out.println("equality = " + user1.equals(user2));
}
}
⇒ 직접 사용하는 코드에 객체를 넣어 비교 해보면
identity = false
equality = true
⇒ 동등성 비교에서 true를 리턴 하게 된다.
- 객체의 참조가 달라 동일성이 다르다
- user1 의 id와 user2 의 id 의 값은 동등하다.
⇒ 해당기능은 최소한의 버전이고 정확한 equals 를 만드려면 복잡하다.
인텔리 제이에서 제공하는 기능으로 만들어 줄 수 있다.
eqauls (동등성)오버라이딩 코드 만들기
- 1. equals and hashCode 를 클릭해주고
- 2. next 버튼 클릭
- 3. 비교할 변수1 클릭 후 next
- 4. 비교할 변수2 클릭 후 next
- 5. 결과보기
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
UserV2 userV2 = (UserV2) object;
return Objects.equals(id, userV2.id);
}
⇒ 그럼 동등성 비교 코드를 만들어 준다.
정리
- 무조건 동일성 비교를 만들필요 없이 필요한 경우에만 재정의 하면 된다.
- equals 와 hashcode는 함깨 사용되는데 컬렉션 프레임 워크 사용시 자세하게 알아보자
Object 정리
Object 의 나머지 메서드
- clone( ) → 객체를 복사할때 사용, 잘 사용하지 않음
- hashCode( ) → equals 와 종종 사용되고 컬렉션 프레임 워크 에서 자세히 다룰 예정
- getClass( ) → 추후 class 강의에서 다룰 예정
- notify( ), notifyAll( ), wait( ) → 멀티 쓰레드용 메서드 , 멀티쓰레드에서 자세하게 다룰 예정