프로그래밍/Java 정리

Java 12일차 -Object, Wrapper,Generic class

윤도ri 2021. 12. 2. 00:22

>Object 클래스

-모든 클래스들의 최상위 클래스

 

ToString() :객체 출력시 나올 문자열 정의(객체에 대해 설명하는 문자열)

 

시작하기전에 우리가 매일 쓰는 System.out.println(); 매소드를 아는가? 우리 선배님들이 이 메소드를 선언할 때는 

후에 어떤것을 이 메소드를 이용해서 출력할지 알 수 없었기 때문에 println 안에는 object타입의 매개변수가 

선언되도록 만들어주셨다. 그래서 이 뜻은 아무거나 객체 하나 넘겨라 라는 뜻이다.

 또한 println은 외부에서 어떤 객체를 선언하게 되면 내부에서 그 객체.toString()을 사용해서 출력한다.

 

:toString을 붙여서 출력하게 되면 tostring을 사용한 부분 통째로 문자열이므로 단순한 문자열 출력이다
부모클래스(object)에서 상속받아서 메소드 쓰는것

:객체가 오브젝트 매개변수로 넘어가고 업캐스팅되어서 오버라이딩 된 메소드를 사용할수 있다.

msg3는 String 타입이므로 object클래스에서 상속받아 equals로 재정의하여 문자값을 비교하는것이고 msg1 == msg2 는 object 매개변수로 들어가서 equals메소드 안에 this==obj 를 리턴하므로 주소값을 비교하여 false가 나오는것이다.

> ==   
-두 주소값이 같은지 확인하는 연산자 

>equals

-두 주소값이 같은지 확인하는 메소드

?1.msg1 == msg2 -->true

1)Hello라는 상수가 있는 필드가 있니? 라고 검사함. 

2)없으면 새로 만들고 그후 msg1 에 그 주소값을 넣어준다.

3)msg2 보면 Hello 값있는지 다시 한번 검사함 

4)있으니까 기존의 것을 사용해서 그 주소값을 넣어준다.

==그러므로 msg1 과 msg2 의 값은 같다.

 

2.msg2 == msg3 -->false

1)무조건 새로운 객체를 만드는것이기 때문에 새롭게 만들어짐(200번지)

2)msg2 에 200번지가 담길것이다

== 그러므로 false 값이 나온다.

 

결론: 문자값을 비교할땐 equals() 메소드를 쓰고 주소값 비교할땐 ==을 쓰자.

 

>동위객체를 동일객체로 보려고 하고 싶을때

Test obj1 = new Test(10, 11.11);

Test obj2 = new Test(10, 11.11);

-->동위객체라고 한다. 

 

>equals()

 Object 의 equals() 는 동위객체를 절대 동일 객체로 보지 않는다. 내부에서 주소값을 비교하기 때문이다.

개발을 하다보면 필요에 의해 동위 객체를 동일 객체로 볼 수 있어야 하기 때문에 우리가 만든 클래스에서 

재정의를 할 수 있어야 한다.

System.out.println(obj1 == obj2); //주소값비교하는것이므로 false 이다.

System.out.println(obj1.equals(obj2));

// 1.obj2가 Object 부모 클래스로 들어갔으므로 업캐스팅됨 

( Test(자식)에서 새로 구현한 메소드, 변수 다 잘려나감)

2.그러므로 내부의 필드들을 서로 비교하려면 잘려나간 필드를 다운캐스팅해서 붙어주어야 한다.

3.객체가 업캐스팅으로 되어있을 경우만 해야하므로 instanceof 타입비교부터 해준다.

 

 

obj1.equals("sdfsd") ---> 오류 생김 why? 문자열이므로 다운캐스팅 자체가 안되므로(그래서 instanceof 로 타입먼저 

                                                     비교가 필요하다)

 

 

>hashCode()

-해쉬값(주소값 관련된 고유한 int값) 을 리턴

위에서 우리가 재정의 했으므로 동일객체가 되었다고 생각했다. 그래서 obj.hashCode() ==obj2.hashCode()를 했더니 

false가 나왔다. 아.. 아직 동일객체가 아니네? 그러면 우리는 hashCode도 재정의 해야겠다!!

Test obj1 = new Test(10, 11.11);

Test obj2 = new Test(10, 11.11);

였으므로  이렇게 재정의 해주면 해쉬값까지 같게된다 .

 

결론: 

 우리가 만드는 클래스에서는 주소값이 아닌 다른 값으로 활용할 수 있도록 재정의할 수 있는 능력이 필요하다

또한 동일객체를 만드려면 equals와 hashCode 둘다 사용해야 완벽히 동일객체가 됨을 알 수 있다.

 

재정의 예제. 로그인

>Wrapper 클래스

-기본형 타입의 변수를 객체로 사용 가능하게 도와주는 클래스
-기본형 타입의 클래스 타입 
(기본형 타입의 값을 마치 객체로 감싸고 있다고 보여서 Wrapper클래스)

                     int    --> Integer 
                    char   --> Character
                             .  .  .

1.박싱
Wrapper 클래스명 객체명 = (Wrapper클래스명) 값; //신버전
Wrapper 클래스명 객체명 = new Wrapper생성자(값);//구버전

2.언박싱 
Wrapper객체.~~value();

jdk 1.5 버전부터는 오토를 지원한다.

3.오토박싱, 언박싱 
Wrapper 클래스명 객체명 = 일반자료형값; // 오토박싱
기본자료형 변수명 = Wrapper객체;  // 오토언박싱 

 

 

>>Wrapper 클래스를 사용하는 이유
1)기본형 타입을 객체로 다루어야 할 때
2)기본형 타입이 아닌 객체로 값을 저장해야 할 때
3)매개변수로 객체를 넘길 때(특히 Object 타입에) (가장 많이 쓰게 될것)
4)객체간에 비교가 필요할 때 

 

매개변수로 객체를 넘길때 
객체간의 비교가 필요할때 

 

 

>Generic(제네릭) <>

 int[] arData = {3,"yello",'y',222.2}; -->안됨. 아 여러가지 타입을 넣고 싶은데 자료형 저거 없으면 좀 선언가능하지 않나? 이 생각에서 generic이 탄생하게 되었다.

-자료형을 선언할 때 정하지 않고 사용할 떄 정해주는 기법 

 
<키워드>
E :element
:Number
T :Type
K :Key
V :Value 

 

 

1. 제네릭 클래스
-클래스 내부에서 사용될 자료형을 지정한다. 

-키워드는 클래스만 올 수 있다.
        Class 클래스명<키워드> {
       내부에서 키워드를 타입으로 사용 가능
            }

클래스는 도장, Winter는 인주라고 생각하면 된다. 똑같은 형태의 객체를 찍어내지만, 안에 있는 필드의 자료형을 못정할 때에는 객체를 찍어낼 때 어떤 색깔(타입)로 할지 정해주는 기법이 제네릭 기법이다.

2. 제네릭 메소드

-메소드 내부에서 사용될 자료형을 지정한다. 

:제네릭 메소드를 호출할때 자료형 타입 적어주지 않아도 된다( 값을 보면 컴퓨터가 암시적으로 안다.)

       <키워드>리턴 타입 메소드명(){
               내부에서 키워드를 타입으로 사용 가능
                      } 

 

3. 제네릭 인터페이스 

-인터페이스 내부에서 사용될 자료형을 지정한다.

        interface 인터페이스명<키워드>{
                내부에서 키워드를 타입으로 사용 가능 
                     }

1.키워드와 함께 인터페이스를 만든다 

 1) 안에 추상메소드를 만들어둔다

2. 인터페이스를 구현하는 방법은 두가지가 있다. 

 1) 익명클래스를 사용해 구현한다.

{ }; 가 익명클래스이며 이것 자체가 값이된다.&nbsp;&nbsp;

//호출

 (1)제네릭 인터페이스의 생성자 호출한다. 

 (2)키워드 이제 명시해준다. 

 (3)익명클래스에 인터페이스를 구현한다.

 (4)부모클래스(인터페이스) 타입인 obj1 에 객체를 넣는다(업캐스팅) 

 //출력

Syso(obj.add(50,30)); 

처음에는 나는 이게 메소드니까 출력문을 안써도 된다고 생각을 했는데 {} 안에 있는 것 자체가 다 값이라서 적어주어야 하는것 같다. (아마도..? 맞나요 아시는분 댓글좀..)

<> 이부분은 위에서 명시했기때문에 적어도 되고 안적어도 되는 부분인것 같다.

 

2) implements 를 사용하여 구현한다.

제네릭인터페이스를 구현했지만 클래스 자체는 일반클래스이므로 평소에 하던것처럼 호출하면 된다.

//호출

 (1)implements  인터페이스<자료형 타입> 적어준다

 *클래스가 제네릭이 아닌 상황에서 해버리면 메소드도 제네릭이 될 수 없다... 구현을 해야하는데 애매해지는 상황 

  그래서 이 경우에 인터페이스의 자료형은 선언해주고 클래스는 일반클래스로서 사용을 해야 할 수 있다. 

  그래서 이제 더이상은 제네릭이 아니라고 보면 된다. (이미 자료형을 선언해놓은 상태이기 때문이다) 

 (2)인터페이스를 구현한다.

//출력

 (3)다른클래스이므로 생성자 호출한다

  :위와 같이 시소를 이용해서 자료형 타입에 맞게 호출하면 된다.

 

>Math 클래스

-수학적인 메소드들과 계산에 필요한 상수를 가지고 있는 클래스

Math.ceil(), Math.floor(), Math.round(), Math.sqrt(), Math.pow() , Math.abs()