1. Java최상위 클래스
1.1 Object클래스
- Object 클래스는 자바의 최상위 클래스이다.
- 모든 클래스는 Object 클래스와 "링크"된다.
1.2 instanceof 연산자
- instaceof연산자는 레퍼런스가 가리키는 인스턴스가 지정한 클래스의 인스턴스이거나 super 클래스의 인스턴스 있지 확인하는 연산자이다.
package com.eomcs.basic.ex01;
//클래스를 정의할 때 수퍼 클래스를 지정하지 않으면
//컴파일러는 자동으로 Object를 상속 받는다.
public class Exam0110 /*extends Object*/ {
static class My /*extends Object*/ {
}
public static void main(String[] args) {
// instanceof 연산자
// => 레퍼런스가 가리키는 인스턴스가 지정한 클래스를 인스턴스 이거나 또는 조상으로 갖는지 검사한다.
Object obj = new My();
// Object의 레퍼런스에 My 인스턴스 주소를 저장할 수 있다는 것은
// My 클래스가 Object 크래스의 서브 클래스임을 증명하는 것이다.
System.out.println(obj instanceof My); //true
System.out.println(obj instanceof String); //false
System.out.println(obj instanceof Object); //true
}
}
// Object 클래스의 주요 메서드
// 1) toString()
// => 클래스이름과 해시코드를 리턴한다.
// 2) equals()
// => 같은 인스턴스인지 검사한다.
// 3) hashCode()
// => 인스턴스를 식별하는 값을 리턴한다.
// 4) getClass()
// => 인스턴스의 클래스 정보를 리턴한다.
// 5) clone()
// => 인스턴스를 복제한 후 그 복제 인스턴스를 리턴한다.
// 6) finalize()
// => 가비지 컬렉터에 의해 메모리에서 해제되기 직전에 호출된다.
//
2. Object class의 주요 메서드
2.1 toString() 메서드
- toString()메서드는 클래스 정보 반환한다.
- 형식은 "패키지명.클래스@16진수해시값" 이다.
package com.eomcs.basic.ex01;
public class Exam0120 {
static class My {
}
public static void main(String[] args) {
My obj = new My();
System.out.println(obj.toString());
//com.eomcs.basic.ex01.Exam0120$My@7ad041f3
//.toString을 생략가능
System.out.println(obj);
//com.eomcs.basic.ex01.Exam0120$My@7ad041f3
My obj2 = new My();
My obj3 = new My();
System.out.println(obj2 == obj3); //false
System.out.println(obj2.toString());
//com.eomcs.basic.ex01.Exam0120$My@251a69d7
System.out.println(obj3.toString());
//com.eomcs.basic.ex01.Exam0120$My@7344699f
}
}
2.1 toString() 메서드 응용(@override활용)
package com.eomcs.basic.ex01;
public class Exam0121 {
static class My {
String name;
int age;
// 개발을 하다 보면 인스턴스의 현재 값을 간단히 확인하고 싶을 경우가 있다.
// 그럴 경우 toString()을 오버라이딩 하라!
//override를 한다고 컴파일러에게 알려주면 오타로 인한 버그를 줄일수 있다.
@Override
public String toString() {
return "My [name=" + name + ", age=" + age + "]";
}
}
public static void main(String[] args) {
My obj1 = new My();
obj1.name = "홍길동";
obj1.age = 20;
System.out.println(obj1.toString());
//My [name=홍길동, age=20]
System.out.println(obj1);
//My [name=홍길동, age=20]
}
}
2.2 equals() 메서드
public class Exam0130 {
static class My {
String name;
int age;
}
public static void main(String[] args) {
My obj1 = new My();
obj1.name = "홍길동";
obj1.age = 20;
My obj2 = new My();
obj2.name = "홍길동";
obj2.age = 20;
}
}
- 기본형
- 기본적으로 equals() 메서드로 두 인스턴스를 비교하면 false가 리턴된다.
System.out.println(obj1 == obj2); //false
System.out.println(obj1.equals(obj2)); //false
- Override 활용하기
- 두 인스턴스를 비교하기 위해 기존equals를 override를 한다.
- 같은 클래스를 확인하기 위해 getClass()메서드를 사용한다.
- 대표적으로 String.equals()가 Override를 활용한 경우이다.
static class My {
String name;
int age;
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
My other = (My) obj;
//파라미터가 type이 Object type이기 때문에 형변환을 적용한다.
return age == other.age && Objects.equals(name, other.name);
}
}
System.out.println(obj1 == obj2); //false
System.out.println(obj1.equals(obj2)); //true
2.3 hashCode() 메서드
- hashCode는 데이터를 구분하기위한 고유번호값이다.
- 데이터 동일성 검증에 사용된다.
- 기본형
package com.eomcs.basic.ex01;
public class Exam0140 {
static class My {
String name;
int age;
}
public static void main(String[] args) {
My obj1 = new My();
obj1.name = "홍길동";
obj1.age = 20;
My obj2 = new My();
obj2.name = "홍길동";
obj2.age = 20;
System.out.println(Integer.toHexString(obj1.hashCode())); //7ad041f3
System.out.println(Integer.toHexString(obj2.hashCode())); //251a69d7
}
}
- Override 활용하기
static class My {
String name;
int age;
@Override
public int hashCode() {
// String 클래스의 hashCode() 메서드는
// 같은 문자열에 대해 같은 해시값을 리턴한다.
String str = String.format("%s,%d", this.name, this.age);
return str.hashCode();
}
}
- 같은 String에 대해서는 동일한 해쉬값을 리턴한다.
System.out.println(Integer.toHexString(obj1.hashCode())); //994aa0fc
System.out.println(Integer.toHexString(obj2.hashCode())); //994aa0fc
3. hashCode() 와 equals()활용
3.1 HashSet
static class Student {
String name;
int age;
boolean working;
public Student(String name, int age, boolean working) {
this.name = name;
this.age = age;
this.working = working;
}
}
public static void main(String[] args) {
Student s1 = new Student("홍길동", 20, false);
Student s2 = new Student("홍길동", 20, false);
Student s3 = new Student("임꺽정", 21, true);
Student s4 = new Student("유관순", 22, true);
}
- 다음과 같이 Student 클래스와 s1 - s4까지 학생 정보가 정의 되어있다.
- HashSet은 중복값을 제거한 하나의 집합을 나타낸다.
HashSet<Student> set = new HashSet<Student>();
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
// 해시셋에 보관된 객체를 꺼낸다.
Object[] list = set.toArray();
for (Object obj : list) {
Student student = (Student) obj;
System.out.printf("%s, %d, %s\n",
student.name, student.age, student.working ? "재직중" : "실업중");
/* 결과값
홍길동, 20, 실업중
임꺽정, 21, 재직중
홍길동, 20, 실업중
유관순, 22, 재직중
*/
- 결과 값이 홍길동이 중복되면 안되지만 중복값을 출력한다.
- HashSet()은 중복을 검사할때, equals()와 hashCode()가 모두 true일때 중복으로 간주한다.
- Override()를 통해 equals()와 hashCode()를 수정한다.
static class Student {
// 기본구조는 동일
@Override
public int hashCode() {
return Objects.hash(age, name, working);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
return age == other.age && Objects.equals(name, other.name) && working == other.working;
}
}
HashSet<Student> set = new HashSet<Student>();
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
// 해시셋에 보관된 객체를 꺼낸다.
Object[] list = set.toArray();
for (Object obj : list) {
Student student = (Student) obj;
System.out.printf("%s, %d, %s\n",
student.name, student.age, student.working ? "재직중" : "실업중");
/* 결과값
홍길동, 20, 실업중
임꺽정, 21, 재직중
유관순, 22, 재직중
*/
3.2 HashMap
package com.eomcs.basic.ex01;
import java.util.HashMap;
public class Exam0152 {
static class MyKey {
String contents;
public MyKey(String contents) {
this.contents = contents;
}
@Override
public String toString() {
return "MyKey [contents=" + contents + "]";
}
}
public static void main(String[] args) {
HashMap<MyKey,Student> map = new HashMap<>();
MyKey k1 = new MyKey("ok");
MyKey k2 = new MyKey("no");
MyKey k3 = new MyKey("haha");
MyKey k4 = new MyKey("ohora");
MyKey k5 = new MyKey("hul");
map.put(k1, new Student("홍길동", 20, false));
map.put(k2, new Student("임꺽정", 30, true));
map.put(k3, new Student("유관순", 17, true));
map.put(k4, new Student("안중근", 24, true));
map.put(k5, new Student("윤봉길", 22, false));
// HashMap
// => 값을 저장할 때 key 객체의 해시코드를 이용하여 저장할 위치(인덱스)를 계산한다.
// => 따라서 해시코드가 같다면 같은 key로 간주한다.
//
// 값을 저장할 때 사용한 key 객체로 값을 찾아 꺼낸다.
System.out.println(map.get(k3));
// key를 사용하여 값을 꺼내보자.
MyKey k6 = new MyKey("haha");
System.out.println(map.get(k6)); // 엥? 값을 꺼낼 수가 없다.
System.out.println(k3 == k6); // 인스턴스는 다르다.
System.out.printf("k3(%s), k6(%s)\n", k3, k6);
System.out.println(k3.hashCode()); // hash code는 다르다.
System.out.println(k6.hashCode()); // hash code는 다르다.
System.out.println(k3.equals(k6)); // equals()의 비교 결과도 다르다.
}
}
- 두 키 객체 k3와 k6가 내용물이 같다 하더라도, (둘다 "haha"이다.)
- hashCode()의 리턴 값이 다르고, equals() 비교 결과도 false 라면 HashMap 클래스에서는 서로 다른 key로 간주한다.
- Override()를 통해 equals()와 hashCode()를 수정한다.
@Override
public int hashCode() {
return Objects.hash(contents);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyKey2 other = (MyKey2) obj;
return Objects.equals(contents, other.contents);
4. getClass()메서드 활용
4.1 getClass()
package com.eomcs.basic.ex01;
public class Exam0160 {
static class My {
}
public static void main(String[] args) {
My obj1 = new My();
// 레퍼런스를 통해서 인스턴스의 클래스 정보를 알아낼 수 있다.
Class classInfo = obj1.getClass();
// 클래스 정보로부터 다양한 값을 꺼낼 수 있다.
System.out.println(classInfo.getName()); // 패키지명 + 바깥 클래스명 + 클래스명
System.out.println(classInfo.getSimpleName()); // 클래스명
//com.eomcs.basic.ex01.Exam0160$My
//My
}
4.2 getClass() : Primitive type과 String 타입의 클래스 정보
public class Exam0161 {
public static void main(String[] args) {
// Primitive Type은 Object의 서브 클래스가 아니기 때문에 getClass()를 호출할 수 없다.
// 대신 static 변수인 class 를 사용하여 Class 정보를 리턴 받을 수 있다.
//
Class classInfo = byte.class;
System.out.println(classInfo.getName()); //byte
System.out.println(short.class.getName()); //short
System.out.println(char.class.getName()); //char
System.out.println(int.class.getName());//int
System.out.println(long.class.getName()); //long
System.out.println(float.class.getName()); //float
System.out.println(double.class.getName()); //double
System.out.println(boolean.class.getName()); //boolean
System.out.println(String.class.getName());// java.lang.String
}
}
4.3 getClass() : Primitive[] type과 String[] 배열 타입의 클래스 정보
// Object 클래스 - getClass() 와 배열
package com.eomcs.basic.ex01;
public class Exam0162 {
public static void main(String[] args) {
// 배열의 클래스 정보
String[] obj2 = new String[10];
Class classInfo = obj2.getClass();
System.out.println(classInfo.getName()); //[Ljava.lang.String;
System.out.println(new byte[10].getClass().getName()); //[B
System.out.println(new short[10].getClass().getName()); //[S
System.out.println(new char[10].getClass().getName()); //[C
System.out.println(new int[10].getClass().getName()); //[I
System.out.println(new long[10].getClass().getName()); //[J
System.out.println(new float[10].getClass().getName()); //[F
System.out.println(new double[10].getClass().getName()); //[D
System.out.println(new boolean[10].getClass().getName()); //[Z
}
}
4.3 getComponentType()
- 배열 안의 원소에 대한 type을 확인하기 위해서는 getComponentType()를 활용한다.
public class Exam0163 {
public static void main(String[] args) {
// 배열의 클래스 정보
String[] obj2 = new String[10];
Class classInfo = obj2.getClass();
System.out.println(classInfo.getName()); //[Ljava.lang.String;
// 배열 항목의 타입 정보를 가져온다.
Class compTypeInfo = classInfo.getComponentType();
System.out.println(compTypeInfo.getName()); //java.lang.String
// 배열안의 원소에 대한 타입 정보는 getComponetType()을 통해 얻는다.
System.out.println(obj2.getClass().getComponentType().getName()); //java.lang.String
// [Ljava.lang.String -> java.lang.String -> java.lang.String
System.out.println(new int[10].getClass().getComponentType().getName()); //int
// [I -> int -> int
}
}
5. clone()메서드 활용
5.1 protectd의 기능
- protected 는 subclass에서 접근가능하지만, 자신의 멤버에 속한 경우에 가능하다.
public class Exam0170 {
static class Score {
String name;
int kor;
int eng;
int math;
int sum;
float aver;
public Score() {}
public Score(String name, int kor, int eng, int math) {
this.name = name;
this.kor = kor;
this.eng = eng;
this.math = math;
this.sum = this.kor + this.eng + this.math;
this.aver = this.sum / 3f;
}
@Override
public String toString() {
return "Score [name=" + name + ", kor=" + kor + ", eng=" + eng + ", math=" + math + ", sum="
+ sum + ", aver=" + aver + "]";
}
}
public static void main(String[] args) {
Score s1 = new Score("홍길동", 100, 100, 100);
Score s3 = s1.clone(); // 컴파일 오류!
//
// Object에서 상속 받은 clone()은 protected 이다.
// 따라서 같은 패키지에 소속된 클래스이거나 상속 받은 서브 클래스가 아니면 호출할 수 없다.
// 비록 Object의 서브 클래스라 할지라도 남의 인스턴스로 protected 멤버를 사용할 수 없다.
// 자신이 상속 받은 protected 멤버인 경우에만 접근할 수 있다.
// 해결책:
// => Object에서 상속 받은 clone()을 오버라이딩 하라!
// => Exam0171.java 를 살펴보라!
}
}
5.2 clone() 오버라이딩
static class Score implements Cloneable {
String name;
int kor;
int eng;
int math;
int sum;
float aver;
public Score() {}
public Score(String name, int kor, int eng, int math) {
this.name = name;
this.kor = kor;
this.eng = eng;
this.math = math;
this.sum = this.kor + this.eng + this.math;
this.aver = this.sum / 3f;
}
@Override
public String toString() {
return "Score [name=" + name + ", kor=" + kor + ", eng=" + eng + ", math=" + math + ", sum="
+ sum + ", aver=" + aver + "]";
}
@Override
public Score clone() throws CloneNotSupportedException {
// 복제를 위한 코드를 따로 작성할 필요가 없다.
// JVM이 알아서 해준다.
// 그냥 상속 받은 메서드를 오버라이딩하고, 접근 권한을 public 으로 확대한다.
// 원래의 clone() 메서드를 실행한 다음에
// 리턴 타입을 해당 클래스로 형변환 한다.
return (Score) super.clone();
}
}
5.3 clone() : deep copy
@Override
public Car clone() throws CloneNotSupportedException {
// deep copy
// => 포함하고 있는 객체에 대한 복제를 수행하려면 다음과 같이
// 개발자가 직접 포함하는 객체를 복제하는 코드를 작성해야 한다.
//
Car copy = (Car) super.clone();
copy.engine = this.engine.clone();
return copy;
}
'개발자 꿈나무의 하루 > 01_Boot Camp' 카테고리의 다른 글
(네이버클라우드 부트캠프) 23일차 - 실습프로젝트(인터페이스) (0) | 2024.06.26 |
---|---|
(네이버클라우드 부트캠프) 22일차 - Java프로그래밍 기초(String, Wrapper),실습프로젝트(LinkedList) (0) | 2024.06.25 |
(네이버클라우드 부트캠프) 19일차 - 실습프로젝트(Static필드, High Cohesion) (0) | 2024.06.20 |
(네이버클라우드 부트캠프) 18일차 - 실습프로젝트(게시판CRUD) (0) | 2024.06.19 |
(네이버클라우드 부트캠프) 17일차 - 실습프로젝트(CRUD구현하기) (0) | 2024.06.18 |