IT 면접족보/자바 면접족보

자바 수업 정리 - clone method, shallow & deep copy, Wrapper class(methods) (18일 차 )

낙산암 2020. 12. 19. 19:53

자바 면접 족보(18일 차 )

1. String 클래스 에서 문자열 비교시 equals를 쓰는 이유는?

String class도 당연히 Object class를 상속한다. 그리고 이미 문자열의 내용비교를 하도록 Object class의 equals() 함수를 오버라이딩 하고 있다.

여기에서 문자열 비교시에 equals를 사용한 이유new로 객체 생성을 했기 때문이다. 이렇게 객체를 생성했을 때 참조 주소값 비교가 아닌 문자열의 내용 비교를 위해서는 일반적인 객체에서 비교하는 방법과 마찬가지의 방법으로 equals를 사용해서 비교를 해야 한다. String class에는 equals함수가 이미 오버라이딩 되어있다.

String str1 = new String("So Simple");
String str2 = new String("So Simple");

String str3 = "So Simple"; 
String str4 = "So Simple";
//이렇게 str3, str4 String 객체를 만들면 == 을 해도 같은 문자열임을 확인할 수 있다.(참조 주소값도 문자열도 같음)
...
if(str1 == str2)      // 참조 주소 비교
if(str1.equals(str2)) // 참조하는 객체의 값 비교 = 문자열 내용 비교

clone 메소드 호출 방법

  • 사용법: implements Cloneable +  Override 부분
  • 클래스 정의시, clone 메소드의 호출을 허용 하려면 Cloneable 인터페이스를 구현해야 한다. (Marker Interface인 Cloneable: 클론 메소드 호출을 허용하겠다는 의미)
  • 참고! Overriding 사용은 기능을 바꾸는 것 뿐 아니라 접근 수준을 넓히는 것도 가능 하다. 예제 에서 오버라이딩을 한 이유는 오브젝트 클래스는 java.lang 패키지에 들어 있고, 호출하는 클래스는 다른 패키지에 들어있다. 기본적으로 clone 메소드 자체가 protected로 선언되어 있기 때문에 다른 패키지에서는 사용할 수 없으므로, 접근 수준을 넓혀서 사용할 수 있게 만들기 위해서 오버라이딩으로 접근 수준을 public으로 변경하였다. (기능 자체를 새로 만들지는 않았던 예시)
  • 예제: clone 메소드 호출의 예 , @Override

2. shallow copy, deep copy 의 차이는?

shallow copy

복사 하려는 클래스 안에 참조형 데이터 멤버가 있을 때 clone 함수로 카피를 하는 경우 객체 자체만 복사 하기 때문에 참조 변수가 가진 주소값만 참조 변수가 참조하는 객체 까지는 복사해서 가져오지 못하게 되는 경우를 말한다. 그래서 참조형 데이터 멤버가 가리키는 객체는 원본 과 복사본이 동일한 주소를 가지고 있기 때문에 같은 객체를 가리키고 있는 상황이 된다

참조형이 아닌 변수와 함수만 존재한다면 얕은 복사에서 문제가 발생하지 않는다. 그러나 클론의 대상이 참조형 변수가 참조하는 생성된 객체 까지가 아니고 자기가 가진 데이터 멤버, 함수만 클론의 대상이 되기 때문에, 한 단계만 복사하고 그 객체의 멤버, 함수만 가져오는 것으로 그 객체의 데이터 멤버가 참조형 인지는 신경 쓰지 않는데, 바로 이 경우 문제가 된다.

 

@Override
public Object clone() throws CloneNotSupportedException {
	Rectangle copy = (Rectangle)super.clone();

	copy.upperLeft= (Point)upperLeft.clone();
	copy.lowerRight= (Point)lowerRight.clone();
  //clone아니고 new라도 해서 복사를 해줘야 한다.

	return copy;
}

3. 금일 배운 Rectangle의 shall copy 와 deep copy 일 때의 그림을 그리시오.

4. 다음 main()이 실행되면 아래 예시와 같이 출력되도록 MyPoint 클래스를 작성하라.

public static void main(String [] args) {
	MyPoint p = new MyPoint(3, 50);
	MyPoint q = new MyPoint(4, 50);

	System.out.println(p);

	if(p.equals(q)) System.out.println("같은 점");
	else System.out.println("다른 점");			
}

/*
Point(3,50)
다른점
*/
class Circle {
	int x;
	int y;
	int radius;
	
	public Circle(int x, int y, int radius) {
		this.x = x;
		this.y = y;
		this.radius = radius;
	}
	
	public String toString() {
		return "Circle(" + x + ", " + y + ") 반지름 "+ radius;
	}	
	
	@Override
	public boolean equals(Object obj) {
		if((this.x == ((Circle)obj).x) && (this.y == ((Circle)obj).y))
			return true;
		else
			return false;
	}
}

public class CircleMain {

	public static void main(String[] args) {
		Circle a = new Circle(2, 3, 5); // 중심 (2, 3)에 반지름 5인 원
		Circle b = new Circle(2, 3, 30); // 중심 (2, 3)에 반지름 30인 원

		System.out.println("원 a : " + a);
		System.out.println("원 b : " + b);

		if(a.equals(b))
			System.out.println("같은 원");
		else
			System.out.println("서로 다른 원");
	}
}

6. 문자열을 입력 받아 한 글자씩 회전시켜 모두 출력하는 프로그램을 작성하라.

문자열을 입력하세요. 빈칸이나 있어도 되고 영어 한글 모두 됩니다.

I Love you
Love youI
Love youI
ove youI L
ve youI Lo
e youI Lov
youI Love
youI Love
ouI Love y
uI Love yo
I Love you
```
public class Test02 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		System.out.println("문자열을 입력하세요. 빈칸이나 있어도 되고 영어 한글 모두 됩니다.");
		String input = sc.nextLine();
		
		for(int i = 0; i <= input.length(); i++) {
			System.out.print(input.substring(i));
			System.out.println(input.substring(0, i));
		}
		sc.close();
	}	
}

7. 래퍼 클래스(Wrapper class)란 무엇인가?

자바는 대표적인 객체 지향 언어이다.

파이썬과 같은 최신 언어들은 기본 자료형(primitive data type)이 따로 존재하지 않는다. 하지만 자바는 객체 지향 언어임에도 불구하고 언어가 만들어질 당시 C언어 등 주류 언어의 영향을 받지 않을 수 없었기 때문에 int a; 와 double b; 같은 기본 자료형(primitive data type)이 존재한다.

하지만 자바 언어에서도 기본 자료형(primitive data type)을 객체로 표현해야 하는 경우가 있기 때문에 모든 기본 자료형(primitive data type)은 객체를 생성할 수 있게 만들었다.

Wrapper class: 기본 자료형의 값을 감싸는 클래스

기본 자료형(primitive data type)을 객체로 만들기 위해(객체화) 사용 되는 클래스를 래퍼 클래스(wrapper class)라고 한다. 감싸는 클래스라는 뜻의 wrapper class로 이름 붙여진 것은 기본 데이터 타입의 값을 클래스가 소유하고 있는(감싸는) 형태로 만들어지기 때문이다. 이렇게 모든 기본 자료형(primitive data type) 8개는 객체로 만들 수 있다.

 

class UseWrapperClass{ //오브젝트 받아서 오브젝트 뿌림
	public static void showData(Object obj) {
	System.out.println(obj);
}

/*
인스턴스를 요구하는 메소드
이 메소드를 통해서 정수나 실수를 출력하려면 해당 값을 인스턴스화 해야한다.	
*/

	public static void main(String[] args) {
		Integer iInst= new Integer(3);
		showData(iInst);
		showData(new Double(7.15));
	}
}

//int, double은 기본형인데 new ! → 객체이다.

래퍼 클래스의 종류와 생성자 (8개)

Boolean    public Boolean(boolean value)
Character  public Character(char value)
Byte       public Byte(byte value)
Short      public Short(short value)
Integer    public Integer(int value)
Long       public Long(long value)
Float      public Float(float value), 
					 public Float(double value)
Double     public Double(double value)

박싱 & 언박싱

  • 박싱: 객체화 시켜 클래스로 감쌌다고 박싱 이라 함. 기본형 → 객체형

    객체 생성을 통해 이루어짐
  • 언박싱: 값을 꺼내는 작업을 하는 것을 언박싱 이라고 표현한다. 객체형 → 기본형

    메소드 호출을 통해 이루어짐
Integer iObj = new Integer(10);    // 박싱 
Double dObj = new Double(3.14);    // 박싱

int num1 = iObj.intValue();           // 언박싱
double num2 = dObj.doubleValue();     // 언박싱

연산

기본 자료형의 특징은 사칙 연산이 가능하다는 것. 래퍼 클래스의 인스턴스는 immutable instance이다. (String 클래스의 인스턴스도 immutable 인스턴스!) 그래서 값을 못 바꾼다. 그래서 연산 결과를 저장할 객체를 계속 생성할 수 밖에 없다. → 비효율적 이지만 최소한의 연산 가능하다.

// 래퍼인스턴스값의증가방법
	iObj = new Integer(iObj.intValue() + 10); //20
	dObj = new Double(dObj.doubleValue() + 1.2); //3.34

언박싱 메소드의 이름

Boolean   public boolean booleanValue()
Character public char charValue()
Integer   public int intValue()
Long      public long longValue()
Double    public double doubleValue()

8. auto unboxing 이란?

auto boxing :

  • 자동으로 boxing이 이루어짐 → 인스턴스에 값이 자동으로 들어감
  • new를 통한 객체 생성을 하지 않고 바로 값을 넣음 (컴파일러가 자동으로 호출해서 객체 생성해 줌)
  • 참조형 객체 = 기본형 값 → 이렇게 대입하는 경우

auto unboxing:

  • 자동으로 unboxing이 이루어짐 → 자동으로 값이 꺼내짐
  • 기본 자료형 타입 변수에 바로 객체의 값이 반환됨
  • 기본형 변수 = 참조형 객체 값 → 이렇게 대입하는 경우
//오토 박싱 & 오토 언박싱: 문법적으로 허용

Integer iObj = 10;     // 오토박싱진행
Double dObj = 3.14;     // 오토박싱진행
		
int num1 = iObj;     // 오토언박싱진행
double num2 = dObj;     // 오토언박싱진행

Integer num = 10; //오토박싱 적용
	num++;          //->오토박싱과오토언박싱동시에진행!
// new Integer(num.intValue() + 1); (객체 새로 생성)

num += 3;      //->오토박싱과오토언박싱동시에진행!
// new Integer(num.intValue() + 3); (객체를 또 새로 생성)- 메모리에 계속 쌓이는 것

int r = num + 5;   // 오토언박싱진행
Integer rObj= num -5;   // 오토언박싱진행 //자료형 일치해야 함 

//연산은 기본형에서 쓰는 연산을 그대로 가져와서 쓸 수 있다.
//하지만 안에서 계속 객체를 생성한다.

Number 클래스 (프리미티브 타입 8개의 조상)

java.lang.Number  //모든래퍼클래스가상속하는클래스
//java.lang.Number에정의된추상메소드들

public abstract int intValue()
public abstract long longValue()
public abstract double doubleValue()
//→ 즉래퍼인스턴스에저장된값을원하는형의기본자료형값으로반환할수있다. 

// 8개는 무조건 저위의 추상 클래스를 구현하고 있어야한다.// 넘버를 상속한다.

9. 다음 조건을 만족하는 클래스 Person을 구현하여 테스트하는 프로그램을 작성하시오.(필수) ⭐️

- 클래스 Person은 이름을 저장하는 필드 구성
- 클래스 Person은 상위 클래스 Object의 메소드 equals()를 오버라이딩하여 이름이 같으면 true를 반환하는 메소드 구현
- 다음과 같은 소스로 클래스 Person을 점검

Person p1 = new Person("홍길동");
System.out.println(p1.equals(new Person("홍길동")));
System.out.println(p1.equals(new Person("최명태")));
class Person {
	String name;

	public Person(String name) {
		this.name = name;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(this.name ==((Person)obj).name)
			return true;
		else
			return false;
	}
}

public class PesonEquals {
	public static void main(String[] args) {
		Person p1 = new Person("홍길동");
		System.out.println(p1.equals(new Person("홍길동")));
		System.out.println(p1.equals(new Person("최명태")));
	}
}

10. 다음 조건을 만족하는 클래스 String의 객체 이용 프로그램을 작성하여 메소드 equals()와 연산자 == 의 차이를 비교 설명하시오.(필수) ⭐️

- 메소드 equals()와 비교 연산자 ==의 차이를 다음 소스로 점검

String s1 = new String("java");
String s2 = new String("java");
String s3 = s2;

System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
System.out.println(s2 == s3);
System.out.println(s2.equals(s3));

public class StringEquals {
	
	public static void main(String[] args) {
		String s1 = new String("java");
		String s2 = new String("java");
		String s3 = s2;

		System.out.println(s1 == s2);
		System.out.println(s1.equals(s2));
		System.out.println(s2 == s3);
		System.out.println(s2.equals(s3));
		
		if(s1 == s2)
			System.out.println("s1, s2 참조 대상 같다.");
		else
			System.out.println("s1, s2 참조 대상 다르다. ");
		
		if(s2 == s3)
			System.out.println("s2, s3 참조 대상 같다.");
		else
			System.out.println("s2, s3 참조 대상 다르다. ");
	
		if(s1.equals(s2))
			System.out.println("s1, s2 내용 동일하다.");
		else
			System.out.println("s1, s2 내용 다르다.");
		
		if(s2.equals(s3))
			System.out.println("s2, s3 내용 동일하다.");
		else
			System.out.println("s2, s3 내용 다르다.");

	}
}

/*
false
true
true
true
s1, s2 참조 대상 다르다. 
s2, s3 참조 대상 같다.
s1, s2 내용 동일하다.
s2, s3 내용 동일하다.
*/

String class도 당연히 Object class를 상속, 문자열의 내용비교를 하도록 Object class의 equals() 함수를 오버라이딩 하고 있음

new로 객체 생성을 했기 때문에 기본적으로 참조 주소가 저장된다. 그래서 == 연산시에 주소값을 비교하게 된다.

참조 주소가 아닌 문자열의 내용 비교를 위해서는 일반적인 객체에서 비교하는 방법과 마찬가지의 방법으로 equals를 오버라이드 해서 사용해야 하지만 이미 String클래스에 equals가 오버라이딩 되어있으므로 그냥 사용하면 된다.