자바의 정석 - 객체지향 프로그래밍1

jhstudio·2022년 10월 24일
0

자바의정석

목록 보기
6/10
post-thumbnail

객체지향언어

실제 세계는 사물로 이루어져 있으며 발생하는 모든 사건들은 상호작용이다.

객체지향언어의 역사

  • 1960년대 중반시뮬라라는 최초의 객체지향 프로그래밍언어 등장
  • 1980년대 중반C++라는 객체지향언어가 관심을 끔
  • 1995년자바 발표
  • 1990년말에 인터넷이 발전하면서 객체지향이 자리잡음

객체지향언어

기존의 언어에서 몇가지를 추가한것이다.

  1. 코드 재사용이 높다.
    • 기존의 코드사용
  2. 코드 관리 용이
    • 적은 노력으로 코드를 변경
  3. 신뢰성이높다
    • 제어자, 메서드를 이용
    • 코드중복 제거

클래스와 객체

클래스와 객체의 정의와 용도

  • 클래스는 객체를 정의한 것 or 객체의 설계도
  • 클래스가 제품설계도라면 객체는 제품

객체와 인스턴스

클래스 -> 인스턴스화 -> 인스턴스
클래스로 부터 만들어진 객체인스턴스라 한다.

객체의 구성요소 - 속성과 기능

클래스란 객체를 정의한 것
객체는 속성과 기능의 집합
속성 - 멤버변수, 특성, 필드, 상태 (다같은말)
기능 - 텍스트, 메서드, 행위, 함수 (다같은말)

인스턴스의 생성과 사용

Tv t; // 메모리 공간 생성
t = new Tv(); // 힙메모리에 객체저장(힙에 변수들이 저장됨)

t.channel = 7; // 멤버변수 접근

// t -> Tv인스턴스에 접근한다.
// t변수를 통해서 Tv인스턴스를 조작할수 있다.
Tv t2 = new Tv();

// t2가 참조한 Tv인스턴스는 GC에 의해 삭제
// t, t2가 서로 같은 메모리를 바라본다.
t2 = t;

t2.channel = 10; // t, t2의 객체가 변한다.


class Tv {
	String color;
	boolean power;
	int channel;
	
    // 호출하면 스택에 쌓임
	void power() {power=!power;}
	void channelUp() {++channel;}
	void channelDown() {--channel;}
}
  • 인스턴스는 참조변수(t)를 통해서만 조작가능
  • 참조변수(t)는 인스턴스타입(Tv)과 같아야함
  • 클래스가 같아도 참조변수가 다르면 서로 다른 값이됨

참고 : https://www.baeldung.com/java-stack-heap

클래스의 또 다른 정의

데이터 처리의 발전과정

변수 -> 배열 -> 구조체 -> 클래스

변수와 메서드

변수 종류 : 클래스 변수, 인스턴스변수, 지역변수

class Test {
	int iv; // 인스턴스 변수
    static int cv; // 클래스변수(스태틱변수, 공유변수)
    void method() {
    	int lv = 0; // 지역변수
    }
}

Test test; // 클래스 변수 생성
test = new Test(); // 인스턴스 변수생성
test.method(); // 지역변수 생성

생성시기

클래스변수 : 클래스가 메모리에 올라갈때

Test test = new Test();
Test test2 = new Test();
test.cv=123;
System.out.println(test2.cv); // 123출력
  • 클래스의 공용변수
  • 프로그램 종료때까지 값이 유지된다.

인스턴스 변수 : 인스턴스가 생성될때
지역 변수 : 변수 선언문이 수행될때

  • 메서드가 종료되면 소멸

메서드

  1. 하나의 메서드는 한가지 기능만 수행
  2. 반복적인 기능은 하나의 메서드로 정의
  3. 관련된 여러 문장을 하나의 메서드로 만들기
  • 1번내용은 클린코드에서도 나온다.

메서드는 크게 선언부, 구현부가 있다.
1. 매개변수는 0개 또는 여러개
2. 매개변수는 지역변수로 구분 (메서드 종료시 소멸)
3. 메서드 return은 선언된 타입과 같아야한다.

return 문

메서드는 return or }를 만나면 종료한다.

int max(int a, int b) {
	if(a > b)
		return a;
	else
    	return b;
}
int max(int a, int b) {
    int result = 0;
	if(a > b)
		result = a;
	else 
    	result = b;
    return result;
}

2번째 코드처럼 return 값을 저장했다가 마지막에 쓰는게 좋다.

void add(int a, int b, int[] result) {
	result[0] = a + b;
}

주소값을 이용해 add하는 로직인데 좋은방법인지는 모르겠다.

메서드의 호출

static메서드 : 참조변수없이 클래스.메서드로 호출가능

  • 인스턴스 변수 호출불가
  • static 변수 호출 가능

JVM의 메모리구조

참조 : https://velog.io/@peanut_/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D-JVM%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0

메서드 영역

  • JVM 시작될 때 생성
  • 논리적으로는 Heap의 일부
  • 상수풀, 필드및 데이터, 클래스 및 인스턴스, 생성자의 클래스별 구조를 저장
  • 가득차면 OutOfMemoryError

콜 스택

  • 메서드가 호출될 때 메모리 할당
  • 메서드 중간에 연산결과 등을 저장
  • 메서드가 끝나면 비워짐
  • 가득차면 StackOverflowError

순서

  1. 메서드가 호출되면 콜스택에 push
  2. 다른 메서드가 호출되면 콜스택에 push
  3. 다른 메서드가 끝나면 콜스택에서 pop
  4. 메서드가 끝나면 콜스택에서 pop

힙 영역

  • 인스턴스가 생성되는 공간
  • 프로그램이 시작될때 인스턴스는 여기에 생성됨
  • 가득차면 OutOfMemoryError: heap space

각 영역은 서로 구분된다.

https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html

기본형 매개변수와 참조형 매개변수

기본형 매개변수 : 읽기만가능
참조형 매개변수 : 읽기 & 쓰기 가능

class Data {int x;}

class P {
	void change(int x) {
    	x = 10;// 기본형 매개변수
    } 
    void change2(Data d) {
    	d.x = 100; // 클래스를 이용한 참조형 매개변수
	}
    void change3(int[] x) {
    	x[0] = 1000; // 배열을 이용한 참조형 매개변수
	}
}

재귀호출

자기자신을 계속 호출하는 메서드

클래스메서드와 인스턴스 메서드

클래스(static) 메서드

  • static이 붙어있음
  • 클래스이름.매서드이름으로 호출
  • static변수하고만 작업가능

인스턴스 메서드

  • 인스턴스 변수하고만 작업가능
  • 객체를 생성해야 생성됨

멤버 변수 : static변수, 인스턴스변수

사용법

  1. 인스턴스 전체에 쓰일변수에만 static을 쓴다.
  2. static변수는 인스턴스 생성없이 사용가능
  3. 클래스 메서드는 인스턴스 변수사용못함
    • 인스턴스 생성없이 사용가능하기때문이다.
    • static은 클래스가 메모리에 올라가면 선언된다.
  4. 메서드에 static을 붙히는것을 고려하자
    • 일반메서드보다 빠르다.
    • 인스턴스 메서드는 메서드 찾는과정이 있음

MathClass를 보면서 공부하면 좋을듯하다.

클래스멤버와 인스턴스 멤버간의 참조와 호출

같은클래스인 경우 인스턴스멤버 없이도 호출가능

  • 이미 인스턴스가 생성되있다.

멤버 : 메서드, 변수 합친것

인스턴스 멤버 -> 클래스 멤버 호출가능
클래스 멤버 -> 인스턴스멤버 호출할땐 인스턴스가 생성되있어야 한다.


int sum = new Math().sum(1,2);

식으로 사용가능하다.

메서드 오버로딩

하나의 이름으로 여러개 메서드를 정의하는 것

오버로딩 조건

  1. 메서드 이름이 같아야한다.
  2. 매개변수, 타입이 달라야한다.
  3. 리턴타입은 오버로딩 조건이 아니다.

오버로딩 예

println() 메서드가 대표적인 예다.

오버로딩 장점

  • 메서드 이름짓기가 쉽다.
  • 매개변수가 다르지만 같은 기능을 한다는 것을 예측 가능

생성자

인스턴스 초기화 메서드
1. 생성자는 클래스 이름과 같아야한다.
2. 생성자는 리턴값이 없다.
3. 매개변수를 설정할 수 있다.
4. new 연산자가 인스턴스를 생성한다. (생성자가 인스턴스를 생성하지 않는다.)

Card c = new Card();
1. 연산자 new에 의해서 heap메모리에 Card클래스의 인스턴스 생성
2. 생성자 Card()실행
3. 연산자 new결과로 생성된 Card 인스턴스의 주소가 c에 저장

기본 생성자

  1. 클래스1개이상 생성자가 있어야한다.
  2. 코드에 생성자가 없을때컴파일러가 자동생성한다.
class Test {
	public Test(int a) {}
}

위 코드는 Test t = new Test(1); 형식으로만 호출가능하다.

매개변수가 있는 생성자

매개변수를 넣으면 코드가 짧아진다.

생성자에서 다른 생성자 호출

this로 생성자에서 다른 생성자를 호출가능하다.

  • this는 자신의 인스턴스다.
  • 모든 인스턴스 메서드에는 this가 붙어있다.
  • 생성자에서 클래스이름 대신 this를 쓴다.
  • 생성자 첫줄에서만 사용가능
class Test {
	int a=10;
	int b=20;
	int c=30;
	
	Test(int a, int b, int c) {
		this.a = a; // this를 사용하면 지역변수, 없으면 매개변수
		b = b; // 둘다 매개변수
		c = this.c; // 이렇게도 가능하다.
	}
	
	Test() {
		this(1,2,3); // 생성자 호출
	}	
}

197p 맨 밑문단
사실 생성자를 포함한 모든 인스턴스 메서드에는 자신이 관련된 인스턴스를 가리키는 참조 변수 this가 지역변수로 숨겨진채로 존재한다.

void sum(int a, int b) {return a + b;}
void getNumber() {return number;} // 지역변수 number

sum(int a, int b)에는 해당되지 않고 getNumber()같이 지역변수 number를 가져오면 앞에 자동으로 this가 붙어서 this.number로 호출되는 말같다.

  • static메서드에서는 this를 못쓴다. 왜냐하면 인스턴스 없이도 참조되기때문
  • this : 자신의 인스턴스를 가르키는 참조변수
  • this() : 다른 생성자를 호출할때 사용

생성자를 이용한 인스턴스 복사

인스턴스를 복사하는 기법이다.

class Car {
	...
	Car(Car c) {
		color = c.color;
		gearType = c.gearType;
		door = c.door;
	}
}
~~

Car c1 = new Car();
Car c2 = new Car(c1); // 복사한다.

변수의 초기화

method안에 지역변수는 자동초기화가 안되서 반드시 초기화후 사용한다.
멤버변수(class안에 변수)는 선택이다.

멤버변수의 초기화

명시적 초기화

int x = 1

초기화 블럭

class Test {
	static int staticVar = 0; // # 2번
	int var = 0; // #4번
	
    // static 변수를 로직으로 초기화하는데 사용한다.
    // 클래스가 처음 메모리에 올라갈때 수행
	static { // # 3번 (static블록이 우선순위가 높다)
		for (int i = 1; i <= 10;i++) {
			staticVar += i;
			var += i; // 안된다
		}
	}
	
    // 인스턴스 변수를 로직으로 초기화하는데 사용한다.
    // 인스턴스 생성마다 수행
	{ // # 5번, #7번
		for (int i = 1; i <= 10;i++) {
			staticVar += i; // 인스턴스를 만들수록 값이 누적증가한다.
			var += i;
		}
	}
}

Test t = new Test(); // #1번
Test t2 = new Test(); // #6번

실행순서는 #n번으로 작성
인스턴스 초기화블럭대신 생성자를 자주쓴다.
모든 생성자에 공통적이면 인스턴스 초기화 블럭을 쓴다.

멤버변수의 초기화 시기와 순서

클래수 변수 : 클래스의 최초로딩
인스턴스 변수 : 인스턴스가 생성될때마다

클래스변수의 초기화 순서 : 기본값 -> 명시적초기화 -> 클래스초기화블럭
인스턴스변수의 초기화 순서 : 기본값 -> 명시적초기화 -> 인스턴스초기화블럭 -> 생성자

  • JVM마다 로직이다름
    • 클래스 멤버 호출, 인스턴스를 생성등 클래스 호출할때 메모리에 로딩

      • 디버깅을 해보니 내가쓰는건 여기에 해당된다. (window jdk11)
    • 프로그램이 시작될때 메모리에 로딩

요약
메서드에 static을 붙히면 일반메서드보다 빠르다.
코드에 생성자가 없으면 컴파일러가 생성해준다.
static변수는 클래스(인스턴스가 아니다)가 메모리에 올라갈때 생성되서 프로그램 종료에 소멸된다.
static은 instance가 없어도 돌아간다.

profile
잡부

0개의 댓글