두 객체가 같으면 반드시 같은 hashcode를 가져야 한다.
두 객체가 같으면 equals()메서드를 호출했을 때 true를 반환해야 한다. 즉, 객체 a, b가 같다면 a.equals(b)와 b.equals(a) 둘 다 true이어야 한다.
두 객체의 hashcode가 같다고 해서 두 객체가 반드시 같은 객체는 아니다. 하지만, 두 객체가 같으면 반드시 hashcode가 같아야 한다.
4.equals()메서드를 override하면 반드시 hashCode()메서드도 override해야 한다.
hashCode()는 기본적으로 Heap에 있는 각 객체에 대한 메모리 주소 매핑정보를 기반으로 한 정수 값을 반환한다. int값 반환!!!!
그러므로, 클래스에서 hashCode()메서드를 override하지 않으면 절대로 두 객체가 같은 것으로 간주 될 수 없다.
hashCode()메서드에서 사용하는 '해시 알고리즘'에서 서로 다른 객체에 대하여 같은 hashcode값을 만들어 낼 수 있다. 그래서 객체가 같지 않더라도 hashCode가 같을 수 있다.
모리기반으로 되어있기 때문에 적절하게 재정의할 필요성이 있다. 
	public static void main(String[] args) {
		//3개의 Person 객체
		Person p1 = new Person(1,"홍길동"); 
		Person p2 = new Person(1,"홍길동"); 
		Person p3 = new Person(1,"이순신");
		
		System.out.println("p1.equals(p2) :"+p1.equals(p2)); 
	        // hashcode() equals() 오버라이드 자동완성 켰을때 true , 껐을때 false
	        System.out.println("p1.equals(p1) :"+p1.equals(p1)); //true
		System.out.println("p1==p2 :"+(p1==p2)); //true
		
		//Person을 담을 HashSet
		Set<Person> set = new HashSet<>();
		//순서가 없고 중복 허용X
		
		set.add(p1);
		set.add(p2);
		
		System.out.println("p1,p2 등록 후 데이터");
		for(Person p:set) {
			System.out.println(p.getId()+":"+p.getName());
			//p1만 등록 p2는 중복체크에 걸려서 추가X => 1:홍길동 
		}
		System.out.println("add(p3) 성공 여부 :"+set.add(p3));//true
		
		System.out.println("p3 등록 후 데이터");
		for(Person p:set) {
			System.out.println(p.getId()+":"+p.getName());
			//1:홍길동 1:이순신
		}
		
		System.out.println("remove(p2) 성공 여부: "+set.remove(p2));//true
		
		System.out.println("remove(p2) 후 데이터");
		for(Person p:set) {
			System.out.println(p.getId()+":"+p.getName()); 
            // p2와 p1과 같은 데이터로 생각 =>1:이순신
		}
	}
}
class Person{
	private int id;
	private String name;
	
	public Person(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	//자동완성
	@Override
	public int hashCode() {
		final int prime = 31;//prime : 소수
		int result = 1;
		result = prime * result + id; // 31+1 = 32
		result = prime * result + ((name == null) ? 0 : name.hashCode()); // 삼항연산자 
		return result;
	}
	@Override
	public boolean equals(Object obj) {// obj:p2
		if (this == obj)//(p1==p1)
			return true;
		if (obj == null)//(p2==null)
			return false;
		if (getClass() != obj.getClass())
        		return false;
               //p1에 대한 getClass p2 Person에 대한 getclass       
		Person other = (Person) obj;//(Person)으로 캐스팅
		if (id != other.id)//내가 갖고 있는 id와 p1의 id와 다를때
			return false;
		if (name == null) { //p1이 null이고
			if (other.name != null) //p2는 null이 아니다
				return false;
		} else if (!name.equals(other.name))//p1의 네임이 p2의 네임과 같지 않으면
			return false;
		return true;
	}
}