오늘은 Object 클래스와 Generic에 대해 알아보겠습니다.
타입 상관없이 수용 할 때 사용하는 두가지 입니다만,
비슷한 것 같으면서 다른게 영 헷갈립니다.
그래서 두가지의 공통점과 차이점을 알아보고자 합니다.
Java에서 Object 클래스는 모든 클래스의 최상위 클래스입니다.
Java의 모든 클래스는 Object 클래스로부터 상속받으며,
이로 인해 Object 클래스에 정의된 메서드들은 모든 Java 객체에서 사용할 수 있습니다.
Object 클래스는 Java의 클래스 계층구조에서 근본적인 역할을 하며, Java에서 모든 객체의 공통적인 동작을 정의합니다.
주요 메서드
Object 클래스에는 여러 중요한 메서드들이 포함되어 있으며, 이들 중 몇 가지를 아래에 간략히 설명합니다:
이 메서드들은 객체의 동등성 비교(equals
), 해시 코드 생성(hashCode
), 문자열 표현(toString
) 등 객체를 다룰 때 자주 사용합니다.
equals(Object obj)
equals
메서드는 객체 자신과 다른 객체가 동등한지 비교하여 boolean
값을 반환합니다. 두 객체가 논리적으로 동등한 경우 true
를, 그렇지 않은 경우 false
를 반환합니다. 기본적으로 Object
클래스의 equals
메서드는 객체의 참조를 비교합니다(즉, 두 객체가 메모리상에서 같은 위치를 가리키는지 확인합니다).
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && name.equals(person.name);
}
}
public class Main {
public static void main(String[] args) {
Person person1 = new Person("John", 30);
Person person2 = new Person("John", 30);
System.out.println(person1.equals(person2)); // true
}
}
hashCode()
hashCode
메서드는 객체의 메모리 주소를 기반으로 한 정수 값을 반환합니다. 이 값은 해시 테이블과 같은 자료 구조에서 객체를 효율적으로 관리하기 위해 사용됩니다. equals
메서드를 오버라이드하는 경우, hashCode
메서드도 함께 오버라이드해야 합니다. 이는 equals
메서드가 true
를 반환하는 두 객체는 반드시 동일한 해시 코드를 반환해야 한다는 규약 때문입니다.
@Override
public int hashCode() {
return Objects.hash(name, age);
}
toString()
toString
메서드는 객체의 정보를 문자열로 반환합니다. 기본적으로 Object
클래스의 toString
메서드는 객체의 클래스 이름과 해시 코드의 무부호 16진수 표현을 반환합니다. 하지만, 객체의 상태를 더 읽기 쉽게 표현하기 위해 toString
메서드를 오버라이드하는 것이 일반적입니다.
@Override
public String toString() {
return "Person{name='" + name + '\'' + ", age=" + age + '}';
}
public static void main(String[] args) {
Person person = new Person("John", 30);
System.out.println(person); // Person{name='John', age=30}
}
이 예시들은 equals
, hashCode
, toString
메서드를 어떻게 오버라이드하여 사용하는지 보여줍니다. 이러한 메서드들은 Java에서 객체의 기본 동작을 정의하고, 객체 간 비교 및 자료 구조에서의 객체 관리, 객체의 문자열 표현 등을 위해 중요합니다.
제네릭에서 사용하는 타입(Type)은 클래스나 인터페이스를 의미합니다.
제네릭을 사용하면, 클래스나 메서드를 정의할 때 구체적인 클래스 타입 대신에 타입 파라미터(보통 대문자 한 글자로 표현되는, 예: T, E, K, V 등)를 사용하여, 후에 실제 클래스 타입으로 대체될 수 있는 "타입 변수"를 선언할 수 있습니다.
이 타입 변수는 후에 해당 제네릭 클래스나 메서드를 사용할 때 구체적인 타입(클래스나 인터페이스)으로 지정됩니다.
따라서, 제네릭의 타입은 "변수"라기보다는 "클래스나 인터페이스의 플레이스홀더(Placeholder)"로 보는 것이 더 정확합니다.
Java의 제네릭은 타입 안전성을 높이고 코드의 재사용성을 개선하는 데 도움을 줍니다. 제네릭 메서드, 클래스, 그리고 와일드카드 타입을 사용하여 다양한 타입에 대해 유연하게 작업할 수 있습니다. 아래에 각각에 대한 설명과 예제를 제공합니다.
제네릭 메서드는 메서드를 선언할 때 메서드의 리턴 타입, 파라미터, 로컬 변수 등에 타입 파라미터(제네릭 타입)를 사용할 수 있게 합니다. 제네릭 메서드는 다양한 타입에 대해 동일한 작업을 수행할 수 있도록 합니다.
public class GenericMethodTest {
// 제네릭 메서드
public static <T> void printArray(T[] inputArray) {
for (T element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
public static void main(String args[]) {
// Integer, Double, Character 배열 생성
Integer[] intArray = {1, 2, 3, 4, 5};
Double[] doubleArray = {1.1, 2.2, 3.3, 4.4};
Character[] charArray = {'H', 'E', 'L', 'L', 'O'};
System.out.println("Array integerArray contains:");
printArray(intArray); // Integer 배열 전달
System.out.println("\nArray doubleArray contains:");
printArray(doubleArray); // Double 배열 전달
System.out.println("\nArray characterArray contains:");
printArray(charArray); // Character 배열 전달
}
}
제네릭 클래스는 클래스를 정의할 때 타입 파라미터를 사용하여 클래스의 인스턴스 변수, 메서드 등에 다양한 타입을 사용할 수 있게 합니다. 이는 클래스를 보다 범용적으로 사용할 수 있게 해줍니다.
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<>();
Box<String> stringBox = new Box<>();
integerBox.set(new Integer(10));
stringBox.set(new String("Hello World"));
System.out.printf("Integer Value :%d\n", integerBox.get());
System.out.printf("String Value :%s\n", stringBox.get());
}
}
와일드카드 타입은 제네릭 타입의 인자로 사용되며, 타입 파라미터의 범위를 제한할 때 사용됩니다. ?
기호를 사용하며, ? extends T
는 T 타입의 상위 범위를, ? super T
는 T 타입의 하위 범위를 의미합니다.
public class WildcardTest {
public static void printList(List<?> list) {
for (Object elem : list)
System.out.println(elem + " ");
System.out.println();
}
public static void main(String[] args) {
List<Integer> intList = Arrays.asList(1, 2, 3);
List<String> stringList = Arrays.asList("One", "Two", "Three");
printList(intList);
printList(stringList);
}
}
이 예에서 printList
메서드는 타입 파라미터의 구체적인 타입에 관계없이 모든 타입의 List
를 처리할 수 있습니다. 와일드카드 타입은 제네릭 메서드나 클래스가 다양한 타입의 객체를 유연하게 처리할 수 있도록 도와줍니다.
PECS는 "Producer-Extends, Consumer-Super"의 약자로, 제네릭 와일드카드 타입을 사용할 때 지켜야 하는 지침입니다. 이 원칙은 제네릭 타입의 데이터를 생산하는 경우와 소비하는 경우에 적절한 와일드카드 타입을 사용하도록 도와줍니다.
Producer-Extends: 데이터를 생산(읽기)만 하는 경우, extends
를 사용합니다. 즉, 메서드가 컬렉션으로부터 데이터를 읽기만 하고, 그 데이터 타입이 특정 타입의 하위 타입이 될 수 있다면, ? extends T
를 사용합니다. 이렇게 하면, T 타입 또는 그 하위 타입의 객체를 반환할 수 있습니다.
Consumer-Super: 데이터를 소비(쓰기)하는 경우, super
를 사용합니다. 메서드가 컬렉션에 데이터를 쓰는 작업을 할 때, 그 데이터 타입이 특정 타입의 상위 타입이 될 수 있다면, ? super T
를 사용합니다. 이는 T 타입 또는 그 상위 타입의 객체를 컬렉션에 추가할 수 있게 합니다.
public class WildcardExample {
// Producer-Extends 예제
public static void printList(List<? extends Number> list) {
for (Number elem : list) {
System.out.println(elem);
}
}
// Consumer-Super 예제
public static void addNumbers(List<? super Integer> list) {
list.add(10); // Integer는 Number의 하위 클래스입니다.
}
public static void main(String[] args) {
List<Integer> intList = Arrays.asList(1, 2, 3);
List<Number> numList = new ArrayList<>();
printList(intList); // Producer-Extends
addNumbers(numList); // Consumer-Super
System.out.println(numList); // 출력: [10]
}
}
PECS 원칙은 제네릭을 사용할 때 타입 안전성을 유지하면서도, 코드의 유연성을 최대화하는 데 도움을 줍니다.
Java에서 Object 클래스와 제네릭은 다형성을 활용하는 두 가지 핵심적인 방법이지만, 이 두가지는 근본적으로 다른 접근 방식을 하고있습니다.
Object 클래스는 Java의 모든 객체에 대한 기본적인 동작을 정의하며, 모든 타입을 수용할 수 있는 가장 일반적인 형태로 다형성을 제공합니다.
반면, 제네릭은 타입 파라미터를 통해 컴파일 시점에 타입 안전성을 강화하고 코드의 재사용성을 높이는 타입 시스템의 확장입니다.
결론적으로, Object와 제네릭은 그들이 생성된 근본적인 목적과 사용 방법이 서로 다르기 때문에, 상황에 맞게 적절하게 사용하는 것이 중요합니다.
출처 : https://inpa.tistory.com/entry/JAVA-%E2%98%95-Object-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EC%83%81%EC%9C%84-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%9E%AC%EC%A0%95%EC%9D%98-%ED%99%9C%EC%9A%A9-%EC%B4%9D%EC%A0%95%EB%A6%AC
https://kephilab.tistory.com/92
https://www.nextree.io/generic-ihaehagi/
https://mangkyu.tistory.com/241