D+33-equals,hashCode,toString,Wrapper클래스,Map

Bku·2024년 2월 13일

학원 일기

목록 보기
31/67
post-thumbnail

equals함수

문자열은 비교할 경우 비교연산자를 사용할 수 없다. 비교연산자는 스택방의 값을 비교하는 것인데 문자열의 경우 인스턴스라 힙영역의 주솟값을 가지기 때문이다.

equals의 재정의

String의 경우 재정의가 이미 되어있어 String에 대한 equals를 사용할 경우 재정의가 필요하지 않았다. 그런데 우리가 정의한 클래스의 인스턴스는 equals가 재정의 되어있지 않기 때문에 재정의가 따로 필요하다.

비교 연산자 사용

public class MemberApplication {
    public static void main(String[] args) {
        Member member = new Member("blue");
        Member member2 = new Member("blue");

//        객체 비교시 equals를 사용해야한다.

        if (member2 == member) {// 이렇게 하면 참조값이 비교된다.
            System.out.println("같음");
        }else {
            System.out.println("다름");
        }
    }

같은 클래스에서 나온 인스턴스이지만 참조값이 다르기에 다름이 나온다.

equals 재정의

    @Override
    public boolean equals(Object o) {
        if (this == o) return true; // 아예 비교하는 객체가 같을 때
        if (o == null || getClass() != o.getClass()) return false; // 비교하는 객체가 문제가 있을 때
        // 위 두 개의 상황이면 아래 코드가 발동되지 않아도 되므로 메모리를 아끼기위해 만든 코드이고
        // 실질적으로는 아래 코드가 목적이다.
        Member member = (Member) o; // 나머지
        return Objects.equals(id, member.id);
    }

1) 자바에서 모든 클래스의 조상 클래스가 Object이다. 그래서 Object의 함수인 equals, toString, hashCode를 가진다.
2) 비교하는 객체가 완전히 같아서 참조값이 같으면 true를 반환하고 탈출한다.
3) o의 타입이 완전히 다르거나(getClass를 통해 알 수 있다.) o가 null이면 false를 반환하고 탈출한다.
4) 두 참조값이 다르고 타입이 같은 경우에는, o를 Member로 다운캐스팅하고 id값을 비교하여 boolean값을 반환한다.

    @Override
    public boolean equals(Object obj) {
//        코딩 : int) 매개변수 obj의 속성 == this.속성 => 같다
//            String) 매개변수 obj의 속성.equals(this.속성) => 같다

//      TODO: 복원 : Object -> Member 끄집어내기 : 강제 형변환
        if(obj instanceof Member) {
            Member member = (Member) obj;

            if(this.id.equals(member.id)) {
                return true;             // 같으면 true 내보내기
            }
        }

        return false;                // 틀리면 false 내보내기
    }

다른 방법으로 다음과 같이 재정의할 수도 있다.

equals 함수 사용
Member객체 equals함수를 재정의 해주고 equals함수를 이용해 두 객체를 비교해보자 (참고 : 두 객체가 같다는 정의는 생성자 값이 같다면 같다라고 생각할 수 있다.)

public class MemberApplication {
    public static void main(String[] args) {
        Member member = new Member("blue");
        Member member2 = new Member("blue");

//        객체 비교시 equals를 사용해야한다.
        if (member2.equals(member)) {
            System.out.println("같음");
        }else {
            System.out.println("다름");
        }
    }
}


이제야 같음이 나오는 것을 확인 할 수 있다.

hashCode

Hash code란 객체를 식별하는 유일한 정수값을 의미한다. 힙 영역의 주소를 주로 사용한다.
hashCode함수는 참조값을 생성해주는 함수이다.

hashCode 재정의 대상

HashMap, HashSet 자료구조 사용시 재정의 하지 않으면 객체를 식별 할 수 없으므로 이 때는 재 정의를 해주어야한다.

hashCode 재정의

@Override
    public int hashCode() {
//        코딩 : 대상 :
//             1) 이 객체를 생성하는 모든 변수는 해쉬코드를 같게 코딩
//             2) 속성의 해쉬코드 또는 값을 내보내기하면 됨
//                 -String 일 경우 : 속성의 hashCode 값 내보내기
//                 - 일반 자료형 : 값만 내보내기
//             3) 해쉬코드 함수를 사용하는 자료구조 때문에 재정의가 필요함
     return id.hashCode();
    }

코딩 : 대상 :
1) 이 객체를 생성하는 모든 변수는 해쉬코드를 같게 코딩
2) 속성의 해쉬코드 또는 값을 내보내기하면 됨

  • 2-1String 일 경우 : 속성의 hashCode 값 내보내기
  • 2-2일반 자료형 : 값만 내보내기

3) 해쉬코드 함수를 사용하는 자료구조 때문에 재정의가 필요함

toString

객체의 정보를 출력하는 함수로, 객체를 문자열로 변환해서 출력해주는 함수이다. 위 두 함수와 마찬가지로 Object클래스가 가지는 함수여서 모든 클래스가 다 가진다.

public class SmartApplication {
    public static void main(String[] args) {
        SmartPhone smartPhone = new SmartPhone("삼성", "안드로이드");

//      객체 출력 : toString함수는 Object클래스가 가지는 함수로 모든 클래스가 가진다.
        System.out.println(smartPhone.toString());
    }
}


하지만 역시 재정의를 해주지 않으면 우리가 알고싶은 속성의 값을 반환하는 것이 아니라 그냥 참조값을 반환할 뿐이다.

toSting 재정의

@Override
    public String toString() {
        return "SmartPhone{" +
                "company='" + company + '\'' +
                ", os='" + os + '\'' +
                '}';
    }

다음과 같이 속성의 값을 문자형태로 반환해주는 함수를 재정의 해주어야한다.


재정의 후 속성 값이 잘 출력된다. toString은 생략해도 자동으로 실행된다.

Wrapper클래스

기본 자료형을 객체형태로 변환해서 사용할 경우가 생긴다.

예를들어 제네릭 함숭에는 기본자료형의 객체형태를 <>안에 넣는다.

자바에서는 미리 기본자료형의 객체 자료형인 Wrapper 클래스를 미리 만들어 놓았다. 전역객체이므로 인스턴스를 따로 만들 필요가 없다.

Wrapper클래스들

  • int = Integer
  • long = Long
  • char = Character
  • double = Double
  • boolean = Boolean
    다음과 같이 나타내면 된다.

Boxing

기본 자료형을 객체 자료형에 넣는 것을 박싱이라한다.

 Integer obj = 100;

UnBoxing

기본 자료형에 객체 자료형을 넣는 것을 언박싱이라고한다.

int value = obj;

모델(model)클래스

프로그램을 만들때 보통 3가지 클래스를 만든다.

model Class

프로젝트에서 속성과 기능함수들이 있는 곳이다. 가장 중요한 클래스라고 할 수 있다.

main class

말그대로 메인 클래스이다.

출력함수 클래스

출력

set

인터페이스로 부모역할을 한다. 자식클래스로 HashSet, LinkedHashSet, TreeSet등이 있다.
여기서 가장 많이 사용하는 것이 HashSet이다.

집합을 구현한 자료구조이고 순서가 유지되지 않아 저장할때와 값을 찾을때 순서가 다를 수 있다. 중복이 허용되지 않는다.

HashSet

ArrayList와 마찬가지로 추가 삭제 조회 등이 있다.

중복 제한

HashSet은 동일한 객체는 중복 저장하지 않는다. 여기서 동일한 객체란 다른 객체라도 hashCode함수의 리턴값이 같고 equals함수가 true이면 동일객체라고 한다.

Set의 함수들

값 추가

ArrayList와 마찬가지로 add를 이용한다.

public class HashSetApplication {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();

        set.add("Java");
        set.add("JDBC");
        set.add("JSP");

        System.out.println(set);

    }
}

출력

set은 배열과 다르게 순서가 없기때문에 일반 for문을 사용해서 출력을 할 수 없다. 그래서 향상된 for문으로만 출력이 가능 하다.

public class HashSetApplication {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();

        set.add("Java");
        set.add("JDBC");
        set.add("JSP");

        System.out.println(set);

        for (String s : set) {
            System.out.println(s + " ");
        }
    }
}

크기 나타내기

ArrayList와 마찬가지로 size를 이용한다.

public class HashSetApplication {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();

        set.add("Java");
        set.add("JDBC");
        set.add("JSP");

        System.out.println(set);

        for (String s : set) {
            System.out.println(s + " ");
        }

        System.out.println(set.size());
    }
}

값 삭제하기

ArrayList와 마찬가지로 remove를 사용하면 되지만 인덱스번호가 없어서 값으로 삭제를 해야한다.

public class HashSetApplication {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();

        set.add("Java");
        set.add("JDBC");
        set.add("JSP");

        System.out.println(set);

        for (String s : set) {
            System.out.println(s + " ");
        }

        System.out.println(set.size());

        set.remove("JDBC");

        System.out.println(set);
    }
}

활용

중복된 데이터를 제거하기위해서 사용할 수 있다.

  1. List에 데이터를 넣고
  2. Set으로 변환하여 중복을 제거하고
  3. 다시 이걸 List로 만들어주면 List에서 중복된 데이터가 없는 List타입의 자료가 될 수 있다.

집합에 객체 넣기

집합에 값 말고도 객체를 바로 넣을 수 있다.

멤버 객체

public class Member {
    public String name;

    public int age;

    public Member(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Member{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

toString 함수만 재정의 해주었다.

main 클래스

public class MemberApplication {
    public static void main(String[] args) {
        Set<Member> set = new HashSet<>();
        
        set.add(new Member("홍길동", 30));
        set.add(new Member("홍길동", 30));

        System.out.println(set.size());
    }
}	


속성이 같은데도 중복 허용되는 거처럼 크기가 2가 나온다. 이 이유는 equals와 hashCode를 재정의 해주지 않았기 때문이다.

재정의 후의 결과

  @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Member member = (Member) o;
        return age == member.age && Objects.equals(name, member.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }


재 정의를 해주니 1로 변한 것을 볼 수 있다.

Map

키와 값을 한 쌍으로 가지는 자료구조이다. 키는 중복된 데이터가 없어야하고, 값은 중복이 가능하다. 기존에 저장된 키와 동일한 키로 값을 저장하면 기존의 값은 없어지고 새로운 값으로 대치된다.

이 인터페이스이고, 자식클래스로 HashMap, HashTable, LinkedHashMap, Properties, TreeMap등이 있다.

사용법

지금까지 사용하던 객체 호출과는 좀 다르다.

public class HashMapApplication {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
    }
}

위와 같이 <>안에 자료형을 넣어주면 되지만, 만약 자료형이 특정되지 않을 경우 다음과 같이 할 수도 있다.

public class HashMapApplication {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
    }
}

HashMap의 함수들

값 넣기

public class HashMapApplication {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
		// 값 넣기
        map.put("no",1);
        map.put("name", "홍길동");
        System.out.println(map);
    }
}

put을 이용하여 괄호안에 앞에는 키, 뒤에는 값을 입력해주면 된다.

크기 확인하기

size를 이용해 크기를 확인 할 수 있다.

public class HashMapApplication {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
		// 값 넣기
        map.put("no",1);
        map.put("name", "홍길동");
        System.out.println(map);

		// 크기 확인하기
        System.out.println(map.size());
    }
}

키로 값 확인하기

get으로 값을 가져올 수 있는데, key를 이용해 해당 키의 값을 가져올 수 있다.

public class HashMapApplication {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
p<>();
		// 값 넣기
        map.put("no",1);
        map.put("name", "홍길동");
        System.out.println(map);

		// 크기 확인하기
        System.out.println(map.size());
        
		// 키로 값 확인하기		
        System.out.println(map.get("name"));
    }   
}

name에 해당하는 값인 홍길동을 가져온다.

키로 값 수정하기

동일한 키에 값을 또 넣으면 원래 있던 값은 사라지고 새로 입력된 값이 들어가게 된다.

public class HashMapApplication {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
p<>();
		// 값 넣기
        map.put("no",1);
        map.put("name", "홍길동");
        System.out.println(map);

		// 크기 확인하기
        System.out.println(map.size());
        
		// 키로 값 확인하기		
        System.out.println(map.get("name"));
        
        // 키로 값 수정하기
         map.put("no", 2);
        System.out.println(map.get("no"));
    }   
}


no의 값이 바뀐것을 확인할 수 있다.

키로 값 삭제

public class HashMapApplication {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
p<>();
		// 값 넣기
        map.put("no",1);
        map.put("name", "홍길동");
        System.out.println(map);

		// 크기 확인하기
        System.out.println(map.size());
        
		// 키로 값 확인하기		
        System.out.println(map.get("name"));
        
        // 키로 값 수정하기
         map.put("no", 2);
        System.out.println(map.get("no"));
        
        //키로 값 삭제
        map.remove("no");
        System.out.println(map);
    }   
}


no키가 삭제되었다.

Map에 객체 넣기

model 클래스

public class Student {
    public int sno;
    public String name;

    public Student(int sno, String name) {
        this.sno = sno;
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return sno == student.sno && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(sno, name);
    }

    @Override
    public String toString() {
        return "Student{" +
                "sno=" + sno +
                ", name='" + name + '\'' +
                '}';
    }
}

hash클래스를 사용할 것이므로 hash오버라이딩 필수

main클래스

public class StudentApplication {
    public static void main(String[] args) {
        Map<String, Student> map = new HashMap();
        map.put("홍길동", new Student(1, "홍길동"));
        map.put("장길산", new Student(2, "장길산"));
        System.out.println(map);
    }
}

키를 String으로 값을 Student로 각각 타입을 지정해주고 put으로 값을 넣어 주었다.

HashTable

멀티스레드 환경에서 사용하는 자료구조이고 함수는 HashMap과 같다.

profile
기억보단 기록

0개의 댓글