230720
객체지향 프로그래밍 (2) - 객체
JVM 메모리 구조
JVM 메모리 구조
- Java 언어는 메모리 관리를 개발자가 하지 않음
- GC (Garbage Collection) 가 메모리 관리
Garbage Collection
- Heap 영역 (class 영역 포함) 에 생성된 메모리 관리 담당
- 더이상 사용되지 않는 객체들을 점검하여 제거
- 자동적 실행/CPU가 한가 or 메모리 부족
- JVM에 의해서 실행
System.gc()
를 통해 호출 (시스템 영향을 줘서 하지 않기…)
객체 생성과 메모리 할당
Person p1 = new Person();
p1.name = "Yang";
p1.age = 45;
p1.hobby = "유튜브";
클래스 영역 = 메소드 영역: 클래스 안에 있는 메소드가 들어가기 때문에 메소드 영역이라고도 함
static 특징
대체 미리 쓸 수 있다는 게 무슨 말임?????? static으로 선언하면 설계도에 같이 넣어서 이전에~~ non-static은 그때그때 선언할 때마다 할당된다.
- 로딩 시점
- static: 클래스 로딩 시…
- non-static: 객체 생성 시
- 메모리 상의 차이
- static: 클래스당 하나의 메모리 공간만 할당 → 미리 class를 선언하기 때문에 class 안에 인스턴스들을 할당해서 메모리 공간 차지가 적음
- non-static: 인스턴스 당 메모리가 별도로 할당 → 인스턴스 하나마다 메모리 각각 할당
- 문법적 특징
- static: 클래스 이름으로 접근
non-static: 객체 생성 후 접근
public class Person { static int pCount; String name; int age; String hobby; }
public class PersonTest { public static void main(String[] args) { Person p new Person(); p.name = "Kim"; Person.pCount ++; p.pCount++; //오류는 나지 않지만 경고... 무슨 말임?? }
왜 인스턴스가 아니라 클래스 이름으로 접근하는 것을 권장할까? static → 인스턴스 생성 없이 접근할 수 있는 공유 메모리여서? 여러개의 인스턴스가 생성되어 있을 때는 어떻게 할까? 인스턴스로 접근해도 노란 줄 없음~~
static 영역에서는 non-static 영역을 직접 접근이 불가능
public class Main { String str = "문장"; public static void main(String[] args) { System.out.println(str); } }
static: 미리 메모리에 올라가 있어서 인스턴스 생성 여부 관계 X
non-static: 인스턴스가 만들어져야 쓸 수 있는 것, 만들어지기 전까지 메모리에 올라가지 않기 때문에 static에서는 접근할 수 없음 (당연한 말..)
non-static 영역에서는 static 영역에 대한 접근이 가능
public class Main { static String str = "문장"; public void print() { System.out.println(str); } }
non-static을 실행할 때 static 영역에 해당하는 것들은 이미 올라가 있기 때문에 접근할 수 있음
접근 제한자
패키지
패키지
- PC의 많은 파일을 관리하기 위해서 폴더를 이용한다
- 프로그램의 많은 클래스를 관리하기 위해서 패키지를 이용한다
- 패키지는 클래스와 관련 있는 인터페이스들을 모아두기 위한 이름 공간
- 패키지의 구분은 .(dot) 연산자를 이용한다
pkg1.pkg2.pkg3
: pkg1 안에 pkg2 안에 pkg3pkg1 에서 main을 실행하더라도
import pkg1.pkg2.Person;
해서 pkg1의 Person을 사용하는 것이 아닌 pkg2의 Person을 사용할 수 있다 만약 둘 다 쓰고 싶다면?import pkg1.pkg2.Person; import pkg1.Person;
내부적으로 같은 이름의 클래스이지만 다른 친구를 사용할 수는 없을까? → 풀패키지명으로 자료형을 적어주면 된다.
pkg1.Person p1 = new pkg.Person; pkg1.pkg2.Person p2 = new pkg1.pkg2.Person(); pkg1.pkg2.pkg3.Person p1 = new pkg1.pkg2.pkg3.Person();
하지만 이렇게 하기 너무 불편하기 때문에…
**같은 이름을 쓰는 것을 지양합시다~!**
- 패키지의 이름은 시중에 나와 있는 패키지들과 구분되게 지어야 한다
- 일반적으로 소속이나 회사의 도메인을 사용한다.
com.name.project_이름.module_이름
임포트
임포트
- 다른 패키지에 있는 클래스를 사용하기 위해서는 import 과정이 필요하다
package com.name.project.service; import com.name.project.dto.Person; public class PersonService { Person p; }
PersonService.java
에서 Person 클래스를 사용하기 위해서는 import 해야 한다.- import를 선언할 때는 import 키워드 뒤에 package 이름과 클래스 이름을 모두 입력하거나, 해당 패키지의 모든 클래스를 포함할 때는 ‘*’를 사용하기도 한다.
import package_name.class_name; import package_name.*; // *: 모두 가져오라는 뜻
★ 하위 패키지에 있는 것들은 다른 공간의 친구들이라 가져올 수 없어! 하위 패키지에 접근하고 가져와야 함
캡슐화 (Encapsulation)
public class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println("음식을 먹는다.");
}
}
Person p = new Person ("김싸피", 28);
이런 일이 가능한 이유는 무엇일까?
캡슐화
- 객체의 속성(data fields)과 행위(메서드, methods)를 하나로 묶고
- 실제 구현 내용 일부를 외부에 감추어 은닉한다
접근 제한자 (access modifier)
- 클래스, 멤버 변수, 멤버 메서드 등의 선언부에서 접근 허용 범위를 지정하는 역할의 키워드
- 접근 제한자의 종류
- public: 모든 위치에서 접근 가능
- protected: 별로 사용할 일이 없을 것이에요 → 같은 패키지 - 접근 가능 → 다른 패키지 - 불가능 → 단, 다른 패키지의 클래스와 상속관계가 있을 경우 접근 가능
- (default) → 같은 패키지 - 접근 허용 → 접근제한자가 선언이 안 되었을 경우 기본 적용
- private → 자신 클래스에서만 접근 허용 클래스(외부) 사용 가능: public, default 내부 클래스, 멤버변수, 메소드 사용가능: 4가지 모두 가능
- 그 외 제한자
- static: 클래스 레벨의 요소 설정
- final: 요소를 더 이상 수정할 수 없게 함
- abstract: 추상 메서드 및 추상 클래스 작성
- …
수식어 | 클래스 내부 | 동일 패키지 | (다른 패키지 내의) | |
---|---|---|---|---|
하위 클래스 | 다른 패키지 | |||
private | O | |||
(default) | O | O | ||
protected | O | O | O | |
public | O | O | O | O |
접근자(getter) / 설정자(setter)
클래스에서 선언된 변수 중 접근제한에 의해 접근할 수 없는 변수의 경우 다른 클래스에서 접근할 수 없기 때문에 접근하기 위한 메서드(설정자와 접근자)를 public으로 선언하여 사용
public class Person { private String name; private int age; //접근자 public String getName() { return name; } //설정자 public void setName(String name) { this.name = name; } //접근자, boolean 타입의 getter는 is를 쓰는 것이 국룰~ isHungry~ public int getAge() { return age; } //설정자 public void setAge(int age) { this.age = age; }
객체 배열 관리
싱글턴 패턴 (Singleton Pattern)
객체가 딱 하나만 필요할 때!!
소프트웨어 디자인 패턴에서 싱글턴 패턴(Singleton pattern)을 따르는 클래스는 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴
public class Manager { //외부에서 생성하지 못하게 막아버림!11 생성자에 private을 걸어버령 //기본 생성자를 작성하고 접근 제한자를 private으로 만들어 private static Manager manager = new Manager(); //가지고 있고 싶을 때 private Person () {}; private Person instance = new Person(); //이렇게 선언하는 것도 private String name = "Yang"; //이런 식으로 선언하는 거랑 같음 //외부에서 나의 instance에 접근해서 사용할 수 있게 하는 메소드 public Person getInstance() { //미리 선언하지 않고 이런 식으로 조건문을 활용해서, instance가 존재하지 않을 경우 -> 만들어서 return // if (instance == null) // instance = new Person() return instance; } private Manager() {} public static Manager getManager() { return manager; } }
//static으로 미리 올려 놓는다면? –> public static … -> instance 변수를 가져올 수 없기 때문에 에러 남 →
private static Person
로 instance도 static으로 미리 선언해야 됨main Person p1 = Person.getInstance(); Person p2 = Person.getInstance();
여기서 p1과 p2는 같은가?
**YES**
같은 인스턴스 값을 가져오기 때문에! (singleton의 경우에만 해당되는 듯)
객체 배열 관리
객체 배열 관리란?
- 정보 관리 시스템 ex) 학사 관리 시스템
- 캡슐화를 이용하여 클래스 작성
- DB 대신 배열을 사용해 객체의 정보를 저장
- 객체의 조회, 추가, 수정, 삭제(CRUD)를 구현
- 싱글턴 패턴을 사용하여 정보 관리 일원화