이글은 자바를 빠르게 끝내기 위해 내가 헷갈리는 부분만을 정리해논 글입니다. Do it! 자바 프로그래밍 입문을 정리하지만 내용을 많이 건너뜀
우리는 프로그래밍하면서 String, Integer와 같은 클래스들을 사용하엿다.
이런 클래스들은 어디에 있는 것인가?
java.lang 패키지 안에서 존재한다.
String은 원래 java.lang.String인 것이다.
Object 클래스는 모든 클래스의 최상위 클래스로 모든 클래스는 Object클래스에서 상속 받는다.
그렇기 때문에 모든 클래스는 Object 클래스의 메서드를 사용 가능하고 그 중 일부는 재정의하여 사용할 수 있다. 위치는 java.lang.Object 클래스이다.
기본동작 : 객체의 해시코드 출력
override 목적 : 객치의 정보를 문자열 형태로 표현하고자 할 때
package object;
public class Book {
private String title;
private String author;
public Book(String title, String author){
this.title = title;
this.author = author;
}
public static void main(String[] args) {
Book book = new Book("깊은 밤 부억에서", "모리스 샌닥");//object 클래스의 toString()메서드
System.out.println(book);
}
}
//결과
object.Book@119d7047
Process finished with exit code 0
toString()의 원형
getClass.getName()+'@'+Integer.toHexString(hashCode())
package object;
public class Book {
private String title;
private String author;
public Book(String title, String author){
this.title = title;
this.author = author;
}
@Override
public String toString(){
return title +", " + author;
}
public static void main(String[] args) {
String str = new String("Apple");//String 클래스의 toString()메서드
System.out.println(str);
Book book1 = new Book("정말 깊은 밤속", "신범철");//book클래스에서 toSting()메서드 직접 재정의
System.out.println(book1);
}
}
//결과
Apple
정말 깊은 밤속, 신범철
결국
override를 통해 객체의 정보를 문자열 형태로 표현할 수 있다.
기본 동작 : '==' 연산 결과 반환
override 목적 : 물리적으로 다른 메모리에 위치하는 객체여도 논리적으로 동일함을 구현하기 위해
물리적 동일함 : 객체가 메모리에서 같은 주소를 갖는 것
논리적 동일함 : 물리적으로 다른 위치에 있지만 같은 저장되어 있는 정보가 같다면 논리적 동일함
package object;
public class EqualsTest {
public static void main(String[] args) {
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1==str2);//false
System.out.println(str1.equals(str2));//true
}
}
str1==str2에서 ==는 주소값이 동일한지(물리적 동일함)을 묻는 것이고
두 인스턴스는 다른 주소에 있기 때문에 false를 반환
str1.equals(str2)는 인스턴스의 값(논리적 동일함)을 묻는 것이기때문에 true를 반환
package object;
import exam.Subject;
class Student{
int studentNum;
String studentName;
public Student(int studentNum, String studentName){
this.studentNum = studentNum;
this.studentName = studentName;
}
@Override
public boolean equals(Object obj){
if(obj instanceof Student){
Student std = (Student)obj;//Object클래스로 업캐스팅 된것을 다운캐스팅해준다.
return (this.studentNum == std.studentNum);
}
return false;
}
}
public class EqualsTest {
public static void main(String[] args) {
Student Lee = new Student(100,"이순신");
Student Lee2 = Lee;
Student shin = new Student(100,"이순신");
System.out.println(Lee ==Lee2);//true
System.out.println(Lee == shin);//false
System.out.println(Lee.equals(shin));//재정의전//false
System.out.println(Lee.equals(shin));//재정의후//true
}
}
기본 동작 : JVM이 부여한 코드값. 인스턴스가 저장된 가장 머신의 주소를 10진수로 반환
override목적 : 두 개의 서로 다른 메모리에 위치한 객체가 동일성을 갖기 위해
해시코드란 JVM이 인스턴스를 생성할 때 메모리 주소를 변환해서 부여하는 코드이다.
실제 메모리 주소값과는 별개의 값이며 실제 메모리 주소는 System 클래스의 identityHashCode()로 확인 가능
자바에서는 동일성은 equals()의 반환값이 true, hashCode() 반환값이 동일함을 의미한다.
그래서 일반적으로 equals()와 hashCode()는 함께 override 한다.
System.out.println(Lee);//object.Student@776ec8df
System.out.println(Lee.hashCode());//2003749087
System.out.println(shin.hashCode());//1324119927
기본 주소값이 16진수인 것과 다르게 hashCode()를 사용하면 10진수 주소를 반환해준다.
두개의 서로 다른 메모리의 위치한 인스턴스가 동일하다는 것은 equals()의 반환값이 true여서 '논리적 동일함'을 보여주고 또한 동일한 hashCode()값을 가져야한다.
위의 Lee와 shin은 equals()의 반환값은 true이지만 hashCode의 값은 다른 모습을 보여준다. 이유는 hashCode()는 재정의 하지 않았기 때문이다. 이러한 이유로 equals()를 재정의할 때 hashCode()를 같이 재정의 해주는 경우가 대부분이다.
참고로 hashCode가 같아지게 재정의 한다고 해서 실제 hashCode 주소값이 값다는 것은 아니다.
//book클래스
@Override
public boolean equals(Object obj){
if(obj instanceof Student){
Student std = (Student)obj;//Object클래스로 업캐스팅 된것을 다운캐스팅해준다.
return (this.studentNum == std.studentNum);
}
return false;
}
@Override
public int hashCode(){
return studentNum;
}
//main
System.out.println(Lee);//object.Student@64
System.out.println(Lee.hashCode());//100
System.out.println(shin.hashCode());//100
System.out.println(System.identityHashCode(Lee));//2003749087
System.out.println(System.identityHashCode(shin));//1324119927
hashCode를 재정의하여 Lee와 shin의 hashCode()를 같게 만드려고 할 때 return값은 equals를 재정의 할때 썼던 멤버 변수를 사용하는 것이 좋다.
그래서 return을 equals에서 기준이 되었던 studentNum을 사용하면 Lee와 shin의 hashCode()값이 100으로 같아지는 것을 확인할 수있다.
clone() 메서드는 객체의 복사본을 만드는 메서드로 기본틀(prototype)이 되는 객체로부터 같은 속성 값을 가진 복사본을 생성할 수 있는 메서드이다.
객체지향 프로그래밍의 정보은닉에 위배되는 가능성이 있으므로 복제할 객체는 cloneable 인터페이스를 명시하여야한다.
정수를 사용할 때 기본형인 int를 사용했다. 하지만 정수를 객체형으로 사용하는 경우가 있다.
public void setValue(Integer i){ ...}
public Integer returnValue() { ...}
이러한 경우에 자바에서는 기본 자료형 처럼 사용할 수 있는 클래스를 제공한다. 그것이 wrapper 클래스이다.
primitive type(기본 타입)
과 reference type(참조 타입)
으로 나누어진다.포장 객체
라 칭함)ArrayList<Integer> xx
처럼 컬렉션 형태의 변수를 선엉할 때, 제네릭 타입의 <Integer>
가 자바의 int형과 매핑되는 래퍼클래스이다.String str = "2";
int strToInt = Integer.parseInt(str);
public class Wrapper_Ex {
public static void main(String[] args) {
Integer num = new Integer(17); // 박싱
int n = num.intValue(); //언박싱
System.out.println(n);
}
}
Integer num = new Integer(17); // Boxing
int n = num.intValue(); // UnBoxing
Character ch = 'X'; // AutoBoxing : Character ch = new Character('X');
char c = ch; // AutoUnBoxing : char c = ch.charValue();
일급 컬랙션
이라고 한다. 다시 말해, Collection들을 한번 Wrapping 한 컬렉션이다.public class Car {
private int position;
public void move(MovingStrategy movingStrategy) {
if (movingStrategy.isMove()) {
position++;
}
}
public int getPosition() {
return position;
}
}
public Cars(List<Car> car)
Car aCar = new Car() // Car 인스턴스 1
Car bCar = new Car() // Car 인스턴스 2
Car cCar = new Car() // Car 인스턴스 3
public class Cars {
private List<Car> cars;
public Cars(List<Car> cars) {
this.cars = this.cars;
}
public List<Car> getCars() {
return cars;
}
}
자세한 내용은 추후에 정리하자ㅏㅏㅏㅏ
Class c1 = String.class;
String str = new String();
Class c2 = str.getClass();
Class c3 = Class.forName("java.lang.String");
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = String.class;
String str = new String();
Class c2 = str.getClass();
Class c3 = Class.forName("java.lang.String");//클래스 이름으로 가져오기
Constructor[] cons = c3.getConstructors();//모든 생성장 가져오기
for(Constructor con: cons) {
System.out.println(con);
}
System.out.println();
Method[] methods = c3.getMethods();//모든 메서드 가져오기
for(Method method : methods) {
System.out.println(method);
}
}
Constructor과 Method를 모를 때 위와 같은 방식으로 모든 생성자와 메서드를 출력할 수 잇따.
하지만 보통 .을 누르면 어떤 것들이 사용가능한지 알 수 있기 때문에 사용하는 일은 많이 없다.