KDT - java 기본 타입과 참조타입
기본 타입(primitive type) vs 참조 타입(reference type)
- 기본 타입이란 정수, 실수, 문자, 논리 값을 저장하는 데이터 타입입니다.
- 참조 타입이란 객체의 주소를 참조하는 타입으로 배열, 클래스, 인터페이스 타입을 말합니다.
- 기본 타입으로 선언된 변수는 실제 값(value)을 변수 안에 저장하지만, 참조 타입으로 선언된 변수는 메모리의 주소값을 변수 안에 저장합니다.
- 참조 타입으로 선언된 변수는 스택(stack)영역에 주소값을 저장하고 내부의 실제 값은 힙(heap)영역에 저장합니다.
- 깊은 복사 vs 얕은 복사
- 참조 타입 String과 객체 동등 비교 메서드 equals()
- 자바는 문자열이 동일하다면 String 객체를 공유하도록 되어있습니다. 그래서 단순히 문자열을 String 변수에 할당한다면 같은 주소값을 갖게 됩니다.
- => 주소값으로 비교
ex) String str1 = "Hello"; String str2 = "Hello"; --> str1 == str2 -> true
- 그러나 new키워드를 사용해서 String객체를 직접 heap영역에 생성한다면 문자열의 내용이 같더라도 다른 주소값을 가지게 되므로 동등, 비동등 연산자(==, !=)의 결과가 false로 나오게 됩니다.
ex) String str3 = new String("Hello"); String str4 = new String("Hello"); --> str3 == str4 -> false
- 그래서 동일 String객체이든 다른 String 객체이든 상관없이 문자열의 내용 값 그자체를 비교할 때는 equals() 메서드를 사용해야 합니다.
실습
ArrayEqualsTest.java
package equals.array;
import java.util.Arrays;
public class ArrayEqualsTest {
public static void main(String[] args) {
//배열은 참조형 변수이기 때문에 단순 대입 시 문제 발생
int[] intArray1 = {1,2,3,4,5};
System.out.println("배열 1의 주소 : " + intArray1);
//배열도 참조형 변수이므로 주소가 아닌 실제 자료 조회하려면
//Arrays.toString(배열자료) 형식으로 호출해야 합니다.
System.out.println(Arrays.toString(intArray1));
System.out.println("------------------------");
}
}
이어서, .clone 사용 전 복사 실행 // 스택에서 일어나는 복사
//새로 생성하지 않고, intArray1을 대입받는 intArray2
//힙에 저장된 자료를 새로 똑같이 할당하는 복사 = 깊은 복사
// 변수 뒤에 .clone()을 써서 수행함
int[] intArray2 = intArray1;
intArray1[0] = 100;
System.out.println(Arrays.toString(intArray1));
System.out.println(Arrays.toString(intArray2));
System.out.println("배열 2의 주소 : " + intArray2);
.clone(깊은 복사) 사용 후 // 힙에서 일어나는 복사
배열의 주소와 값이 상이함
---------------------------------------------------------------------------------------------------------------------------
user.java // 스캐너용
package equals.str;
public class User {
String id;
String pw;
public User(String upw) {
pw = upw;
}
}
usermain.java
package equals.str;
public class UserMain {
public static void main(String[] args) {
// 같은 클래스 안에서 동일한 문자열을 직접 대입하는 형식으로
// String 객체를 생서할 시 같은 주소값을 공유함
String s1 = "룰루";
String s2 = "룰루";
System.out.println(s1 == s2);
}
}
- update
package equals.str;
public class UserMain {
public static void main(String[] args) {
// 같은 클래스 안에서 동일한 문자열을 직접 대입하는 형식으로
// String 객체를 생서할 시 같은 주소값을 공유함
String s1 = "룰루";
String s2 = "룰루";
System.out.println(s1 == s2);
String s3 = new String("룰루");
//s1,s2,s3 모두가 룰루라는 문자열을 갖고 있음
System.out.println(s1 + s2 + s3);
System.out.println(s1 == s3);
}
}
결과 화면
s1 룰루와 s3 룰루의 같은 문자임에도 다른 주소임으로 false 처리됨 -> 주소비교
이어서,
//문자열도 참조형 변수이므로 단순비교는 주소값 비교만 함
// 따라서 주소가 아닌 자료의 동등성을 따질 때는 .equals()를 사용함
System.out.println(s1.equals(s3));
해당 상황에서는 주소값이 아닌 자료의 동등성을 따졌으므로 true처리 되는 것을 알 수 있음
-----------------------------------------------------------------------------------------------------------------------------
접근 제한자와 상속
객체 지향 프로그래밍 기술
- OOP 기술에는 은닉(캡슐화:Encapsulation), 상속(Inheritance), 다형성(Polymorphism)이 있습니다.
상속(Inheritance)
- OOP에서 상속은 기존의 클래스를 확장하여 새로운 클래스를 이끌어내는 것을 의미합니다.
- 상속 관계는 is a 관계를 만족하는 관계입니다. ex) 돌고래 is a 포유류 --> 돌고래는 포유류의 속성을 가지고 있다.
- 상속은 기존의 코드를 재사용함으로써 불필요한 코드를 재작성하는 번거로움을 없앨 수 있고, 새로운 클래스를 만드는 시간과 노력을 줄일 수 있습니다.
- 자바에서는 C++에서 사용했던 다중상속의 문제점때문에 단일상속만을 지원합니다.
- 어떤 클래스가 다른 클래스로부터 상속을 받아 만들어지면 새롭게 만들어진 클래스를 자식(child or sub)클래스라고 부르며, 멤버변수와 메서드를 물려준 클래스는 부모(parent or super)클래스라고 부릅니다.
- 상속을 하면 부모클래스의 멤버변수와 메서드가 자식클래스에 상속이 됩니다. 그러나 부모클래스의 생성자는 상속이 되지 않습니다.
- 상속을 사용하는 키워드는 extends 입니다.
public class 자식클래스 extends 부모클래스 {
//정의사항 기술
}
- 상속을 하더라도 부모 클래스에서 private 접근제한을 갖는 멤버변수와 메서드는 상속대상에서 제외됩니다.
- 자바의 모든 클래스는 Object 클래스를 상속받고 있습니다. Object클래스는 자바의 최상위 클래스입니다.
상속 실습
package inheritance;
public class Human {
public String name;
public int age;
}
package inheritance;
public class Student extends Human {
//human의 특성인 name, age는 적지 않아도 자동으로 설정됩니다.
public String major;
}
package inheritance;
public class Salaryman extends Human{
public int salary;
}
package inheritance;
public class InheritanceExample {
public static void main(String[] args) {
Student st1 = new Student();
st1.name = "김학생";
st1.age = 20;
st1.major = "공학";
Salaryman sm1 = new Salaryman();
sm1.name = "나직장";
sm1.age = 40;
sm1.salary = 8000;
}
}
메서드 재정의(Overriding)
- 메서드 재정의란 부모클래스로부터 상속받은 메서드를 자식클래스에서 행위를 바꾸거나 보완하기 위해 다시 정의해서 사용하는 것을 말합니다.
- 이는 부모클래스에서 특별한 용도로 사용하던 메서드를 자식클래스에서 다른 용도로 사용할 때 필요합니다.
- 부모클래스의 모든 메서드가 자식클래스에 맞게 설계되어 있다면 가장 이상적인 상속이지만, 특정 메서드는 자식 클래스가 사용하기에 적합하지 않을 수도 있습니다.
- 이 경우 상속된 일부 메서드는 자식클래스에서 재정의하여 사용해야 합니다.
- 메서드가 자식클래스에서 재정의되었다면 자식객체를 통해 메서드를 호출했을 때 새롭게 재정의된 메서드가 호출됩니다.
- 메서드 재정의 규칙
- 반드시 상속을 전제로 해야합니다.
- 반드시 반환 유형이 같아야 합니다.
- 메서드 이름이 같아야 합니다.
- 매개 변수 선언이 정확히 일치해야 합니다.
- 접근제한자는 같거나 더 제한이 없어야 합니다.(more public)
+ 오버로딩 vs 오버라이딩
오버로딩 :
과적재 라는 영단어 뜻에 걸맞게 같은 이름의 함수를 여럿 정의하는 것
다만, 요구 파라미터의 자료형이나, 개수는 달라야 함.
오버라이딩 :
상속시 부모가 물려준 함수가 마음에 들지 않는다면
같은 이름과 같은 파라미터, 그리고 같은 리턴자료형을 재정의하는 것