A.P.I.E
현실의 객체를 추상화해서 클래스 구성
하나의 객체를 여러가지 타입(형)으로 참조
부모 클래스이 자산을 물려받아 자식을 정의함으로 코드의 재사용이 가능
데이터를 외부에 직접 노출시키지 않고 메서드를 이용해 보호
장점
- 신뢰성 높은 프로그래밍 가능
- 추가 / 수정 / 삭제 용이
- 재 사용성이 높다
붕어빵 틀 => Type 규정
붕어빵 => 객체
추상화
다음과 같이 클래스를 만들고 테스트 코드를 만든다.
Person.java
public class Person {
String name;
int age;
boolean isHungry;
public void eat() {
isHungry = false;
}
public void work() {
isHungry = true;
}
}
PersonTest.java
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.age = "홍길동";
p1.isHungry = true;
System.out.println(p1.name+" : "+ p1.isHungry);
p1.eat();
System.out.println(p1.name+" : "+ p1.isHungry);
Person p2 = new Person();
p2.name = "임꺽정";
System.out.println(p2.name + " : " + p2.isHungry);
}
}
이 코드내의 멤버변수 / 멤버메서드 / 구체화를 구분하면 다음과 같다.
String name;
int age;
void eat();
void work();
Person p = new person;
p.name = "철수";
p.age = 20;
p.work();
a, b와 같은 변수는 힙 영역의 객체를 참조한다.
다른 스레드의 스택에서도 힙을 공유하므로 같은 주소를 참조할 수 있다.
Person형의 p1을 선언하면 metaspace에 클래스를 참조하여 heap에 객체가 생성되고 stack영역에 해당 주소를 참조하는 값이 저장된다.
멤버 변수
객체는 멤버변수인 name, age, isHungry가 있고, 각각의 타입의 기본형으로 초기화 되어있다. name은 String형으로 참조형 타입이므로 주소값이 저장되어 있는데 해당 주소로 가면 p1의 name을 확인할 수 있다.
멤버 메서드
클래스의 멤버메서드의 경우 호출되는 경우 stack에 생성되고 종료되면 stack에서 사라진다.
타입에 따른 분류
인스턴스 변수의 특징
public class Person{
static String scientificName = "Homo Sapiens"
String name;
}
- 객체가 만들어질 때 heap에 객체 별로 생성
- 타입 별로 default 초기화
- 사용하기 전 명시적 초기화 필요
- 객체 생성 후 (메모리에 올린 후) 객체 이름(소속)으로 접근
외부에서는 접근이 불가하므로 소속 불필요- 내부에서는 이름에 바로 접근
- 객체를 생성하고 객체 이름으로 접근도 가능하다 static에 부합한 표현은 아님
Person p = new Person();
p.scientifiName = "객체를 통한 변경"
Person.scientifiName = "클래스를 통한 변경"
- Garbage Collector에 의해 객체가 없어질 때(프로그래머가 명시적으로 소명시킬 수 없음)
- 선언된 영역인 { } 을 벗어날 때
메서드 선언 시 동일 타입의 인자가 몇개 들어올 지 예상할 수 없을 경우 (또는 가변적)
...
을 이용해 파라미터를 선언하면 호출 시 넘겨준 값의 개수에 따라 자동으로 배열 생성 및 초기화예시)
public PrintStream printf(String format Object ... args){
return format(format, args);
}
public void addAll(int... params){
int sum = 0;
for(int i: params){
sum += i;
}
System.out.println(sum);
}
값
을 복사해서 전달call by value
public class CallByTest {
int memberVar = 10;
static void change1(int var) {
var += 10;
System.out.printf("change1 : %d%n", var);
}
static void change2(CallByTest cbtl) {
cbtl.memberVar += 100;
System.out.printf("change2 : %d%n", cbtl.memberVar);
}
public static void main(String[] args) {
CallByTest cbt = new CallByTest();
cbt.memberVar = 5;
System.out.printf("change1 호출 전 memberVar: %d%n", cbt.memberVar);
change1(cbt.memberVar); //값 전달 15출력
System.out.printf("change1 호출 후 memberVar: %d%n", cbt.memberVar); // 값 복사 후 전달 => 원본은 그대로 5
change2(cbt); //주소값 전달 => memberVar값 그 자체가 증가 105출력
System.out.printf("change2 호출 후 memberVar: %d%n", cbt.memberVar); //105 출력
}
}
위 코드 동작시 메모리 변화는 다음과 같다
동일한 기능을 수행하는 메서드의 추가 작성
일반적으로 메서드 이름은 기능별로 의미 있게 작성
동일한 기능을 여러 형태로 정의해야 한다면?
eat vs eatUsingChopSticks, eatUsingFork, eatUsingSpoon
입으로 이동하는 부분까지만 다르고 그 이후의 동작은 ?
ex)
System.out.println(1);
System.out.println('C');
System.out.println("Hi");
장점
매서드 이름은 동일
파라미터의 개수 도는 순서, 타입이 달라야 할 것
파라미터가 같으면 중복 선언 오류
리턴 타입은 의미 없음
ex)
void walk(){
System.out.println("100cm 이동");
}
void walk(int distance){
System.out.println(distance + "cm 이동");
}