인스턴스(instance)
- 클래스는 객체의 속성을 정의하고 기능을 구현하여 만들어 놓은 코드 상태
- 실제 클래스 기반으로 생성된 객체(인스턴스)는 각각 다른 멤버 변수 값을 가지게 됨
- 예를 들어 학생의 클래스에서 생성된 각각의 인스턴스는 각각 다른 이름, 학번, 학년 등의 값을 가지게 됨
- new 키워드를 사용하여 인스턴스 생성
힙메모리
- 생성된 인스턴스는 동적메모리(heap memory)에 할당됨
- 자바에서 Gabage Collector가 주기적으로 사용하지 않는 메모리를 수거함
- 하나의 클래스로 부터 여러 개의 인스턴스가 생성되고 각각 다른 메모리 주소를 가지게 됨
객체 지향 프로그램은 어떻게 구현하는가?
객체를 정의하고, 각 객체 제공하는 기능들을 구현하고, 각 객체가 제공하는 기능들 간의 소통(메시지 전달)을 통하여 객체간의 협력을 구현함
함수란(function)
- 하나의 기능을 수행하는 일련의 코드
- 구현된 함수는 호출하여 사용하고 호출된 함수는 기능이 끝나면 제어가 반환됨
- 함수로 구현된 하나의 기능은 여러 곳에서 동일한 방식으로 호출되어 사용될 수 있음
함수 정의하기
- 함수는 이름, 매개변수, 반환값, 함수 몸체로 구성됨
- 함수호출과 스택 메모리
- 스택 : 함수가 호출될 때 지역변수들이 사용하는 메모리
함수의 수행이 끝나면 자동으로 반환되는 메모리
메소드
- 객체의 기능을 구현하기 위해 클래스 내부에 구현되는 함수(멤버함수 라고도 함)
- 메소드를 구현함으로써 객체의 기능이 구현됨
용어 정리
- 객체 : 객체 지향 프로그램의 대상, 생성된 인스턴스
- 클래스 : 객체를 프로그래밍 하기 위해 코드로 정의해 놓은 상태
- 인스턴스 : new 키워드를 사용하여 클래스를 메모리에 생성한 상태
- 멤버변수 : 클래스의 속성, 특성
- 메소드 : 멤버변수를 이용하여 클래스의 기능을 구현한 함수
- 참조변수 : 메모리에 생성된 인스턴스를 가리키는 변수
- 참조값 : 생성된 인스턴스의 메모리 주소값
생성자
- 객체를 생성할 때 new 키워드와 함께 사용 - new Student();
- 생성자는 일반함수처럼 기능을 호출하는 것이 아니고 객체를 생성하기 위해 new와 함께 호출됨
- 객체가 생성될 때 변수나 상수를 초기화 하거나 다른 초기화 기능을 수행하는 메소드를 호출함
- 생성자는 반환값이 없고 클래스의 이름과 동일
- 대부분의 생성자는 외부에서 접근 가능하지만, 필요에 의해 private으로 선언되는 경우도 있음
기본 생성자(default constructor)
- 클래스에는 반드시 적어도 하나 이상의 생성자 존재
- 클래스에 생성자를 구현하지 않아도 new로 생성자 호출할 수 있음
- 클래스에 생성자가 하나도 없으면 컴파일러가 생성자 코드를 넣어줌
- 매개변수가 없음, 구현부가 없음
생성자 만들기
컴파일러가 제공해주는 기본 생성자 외에 필요에 의해 생성자를 직접 구현할 수 있음
생성자 정의하기
- 생성자를 구현해서 사용할 수 있음
- 클래스에 생성자를 따로 구현하면 기본 생성자는 제공되지 않음
- 생성자를 호출하는 코드에서 여러 생성자 중 필요에 따라 호출해서 사용할 수 있음
package bclass.step1;
public class A {
int i; // 인스턴스 변수(전역변수) i 선언
public A() { // 기본 생성자
System.out.println("A()호출");
i = 10; // i 변수를 10으로 초기화
}
public A(int i) { // 매개변수를 가지는 생성자
// 생성자 내용 없음
// this예약어로 디폴트 생성자 호출 가능
// this();
}
void methodA() { // 매개변수가 없는 메서드
// 현재는 아무 작업도 하지 않음
}
// 만약 외부에서 유지되기를 원하면 전변으로 치환하든가, 리턴타입을 활용
void methodA(int i) { // 매개변수가 있는 메서드
// 메소드 오버로딩 - 파라미터 투입 - 스택메모리에 있는 지변이다
// 인스턴스화를 할 때마다 새로운 객체 생성 - 주소번지가 달라짐
A a = new A();
a.i = 20;
System.out.println(a.i); // 20
}
public static void main(String[] args) {
// A 클래스의 새 객체 a를 생성
// 매개변수를 0으로 전달하여 생성자 호출
A a = new A(0);
// a 객체의 i 변수 값을 출력
// 10 출력, 생성자에서 초기화
System.out.println(a.i);
}
}
<자유게시판 구현에 대한 클래스 설계>
package bclass.board;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
// BoardView -> BoardController -> BoardDao
public class BoardView extends JFrame implements ActionListener {
// BoardController 객체를 저장할 참조 변수 선언
// 나는 내 타입도 몰라요. 왜냐면 초기화를 null로 했으니까
BoardController boardController = null;
// "조회" 레이블을 가진 JButton 선언
JButton jbtn_sel = new JButton("조회");
public BoardView() {
// 생성자에서 initDisplay 메서드 호출하여 화면 초기화
initDisplay();
}
public void initDisplay() {
jbtn_sel.addActionListener(null);//this는 현재 메모리에 로딩(활성화)되어 있는 자신 - BoardView - actionPerformed - 메소드 오버라이딩 - 추상메소드 - 인터페이스 - ActionListener - 정의가 안되어있다 - 미정이다. - 단말기가 결정되지 않음
this.add("North", jbtn_sel);
this.setSize(500, 400);
this.setVisible(true);
}
//현재 상태에서 단위테스트 가능한가요?
//힌트 - actionPerformed는 콜백메소드야 - 내가 호출하지 못해
//파라미터 자리에 클래스(참조형) 타입도 올 수 있다.
//콜백메소드의 파라미터자리는 개발자가 아닌 JVM에서 주입받는다.
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("actionPerformed");
Object obj = e.getSource();//절대로 NullPointerException이 발생하지 않음
//너 조회버튼 누른거야? 네
if(obj == jbtn_sel) {
boardController = new BoardController();
boardController.getBoardList();
}
}
public static void main(String[] args) {
BoardView bview = null;
bview = new BoardView();
}
}
package bclass.board;
public class BoardVO {
private int fb_no =0;//글번호
private String fb_title ="";// 글제목
private String fb_writer ="";//작성자
private String fb_content ="";//글내용
private int fb_hit =0;//조회수
private int fb_group =0;//글그룹번호
private int fb_step =0;//글순번
private String fb_date ="";//작성일자
//1이면 입력|수정|삭제 성공, 0이면 입력|수정|삭제
private int result = -1;
public int getResult() {
return result;
}
public void setResult(int result) {//1 또는 0
boolean isValid = false;
//public으로 변수를 선언하여 직접 사용할 때 보다 메소드를 통해서 값을 사용하므로
//입력값에 대한 유효성 체크를 할 수 있다는 장점이 있다.
if(result == 0 | result == 1) {//입력값에 대한 유효성 체크를 동반할 수도 있다.
isValid = true;
}
else {
isValid = false;
}
this.result = result;
}
public int getFb_no() {
return fb_no;
}
public void setFb_no(int fb_no) {
this.fb_no = fb_no;
}
public String getFb_title() {
return fb_title;
}
public void setFb_title(String fb_title) {
this.fb_title = fb_title;
}
public String getFb_writer() {
return fb_writer;
}
public void setFb_writer(String fb_writer) {
this.fb_writer = fb_writer;
}
public String getFb_content() {
return fb_content;
}
public void setFb_content(String fb_content) {
this.fb_content = fb_content;
}
public int getFb_hit() {
return fb_hit;
}
public void setFb_hit(int fb_hit) {
this.fb_hit = fb_hit;
}
public int getFb_group() {
return fb_group;
}
public void setFb_group(int fb_group) {
this.fb_group = fb_group;
}
public int getFb_step() {
return fb_step;
}
public void setFb_step(int fb_step) {
this.fb_step = fb_step;
}
public String getFb_date() {
return fb_date;
}
public void setFb_date(String fb_date) {
this.fb_date = fb_date;
}
}
package bclass.board;
import java.util.List;
import java.util.Map;
//화면과 로직(모델계층-데이터계층과 업무 프로세스 처리)을 분리하자
//화면과 로직을 연결해주는 클래스 설계함
//로직(입력, 수정, 삭제, 전체조회 상세조회 업무내용 - 메소드 5개 설계함)
//입력인 경우 - 성공이면 1을 반환하고 실패이면 0을 반환 - 누가반환하지 - 오라클 서버
//5가지의 메소드의 리턴타입과 파라미터 타입을 결정해야 함
//공통점 찾아내서 하나의 메소드로 합칠 수 있는 것인지 아니면 메소드를 모두 다 분리해야 하는지 결정
public class BoardController {
BoardDao bDao = new BoardDao(this);//전역변수
public List<Map<String,Object>> getBoardList(){
System.out.println("getBoardList호출 성공");
return null;
}
}
package bclass.board;
//DAO(Data Access Object) - 영속성을 제공하는 오라클 서버와 연계하는 역할만 전담
//클래스 사이의 결합도를 낮춰야 한다. - 재사용성을 높여야 한다. - 칼퇴
public class BoardDao {
BoardController boardController = null;//주소번지 안찍힘 - 타입이 결정되지 않음 - 모른다
public BoardDao(BoardController boardController) {
this.boardController = boardController;
}
}
package bclass.step1;
class C1{
int i;
}
class C2{
}
public class CMain {
//c1은 C1타입이고 아직 생성되지 않았다. 선언만 함. 아직 인스턴스화 안함
C1 c1 = null;//타입이 결정된것도 아니었다 - 경험치
public static void main(String[] args) {
CMain cm = new CMain();
cm.c1 = new C1();//생성
System.out.println(cm.c1);//null
System.out.println(cm.c1 instanceof C1);
System.out.println(cm.c1.i);//NullPointerException발동됨
System.out.println(cm.c1.i+2);//2
System.out.println("main");
}
}/////// end of CMain
package bclass.step1;
class D1{
//DMain에서 선언된 변수를 굳이 methodA에서 사용하고 싶다.
//어떡하지? - 파라미터를 이용하면 된다(call by value, call by reference)
int methodA(int i, int j) {
System.out.println(i+", "+j);
return i+j;
}
}
public class DMain {
public static void main(String[] args) {
D1 d1 = new D1();
int i = 1;
int j = 2;
int hap = d1.methodA(i, j);
System.out.println(hap);
}
}
package bclass.step1;
import javax.swing.JButton;
public class EMain extends Object {
@Override
public String toString() {
return "null";
}
public static void main(String[] args) {
EMain em = new EMain();
JButton jbtn = new JButton("조회");
System.out.println(em);
System.out.println(em.toString());
System.out.println(jbtn);
}
}
package bclass.step1;
//샘플데이터 - 0054307 | 나신입 | 3
public class Student {
private int s_no;//학번이다. - 0
private String s_name;//학생이름 - null
private int grade;//학년 - 0
public Student() {}
public Student(int s_no) {}
public Student(int s_no, String s_name) {};
public Student(int s_no, String s_name, int grade) {
this.s_no = s_no;
this.s_name = s_name;
this.grade = grade;
}
public int getS_no() {
return s_no;
}
public void setS_no(int s_no) {
this.s_no = s_no;
}
public String getS_name() {
return s_name;
}
public void setS_name(String s_name) {
this.s_name = s_name;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
};
}
package bclass.step1;
public class StudentTest {
public static void main(String[] args) {
Student me = new Student();
System.out.println("학번 : "+me.getS_no());
System.out.println("학생이름 : "+me.getS_name());
System.out.println("학년 : "+me.getGrade());
me = new Student(9563409, "나신입", 3);
System.out.println("학번 : "+me.getS_no());
System.out.println("학생이름 : "+me.getS_name());
System.out.println("학년 : "+me.getGrade());
}
}
package bclass.step1;
//메소드를 선언할 수 있다는 건 리턴타입과 파라미터를 결정할 수 있어야 한다.
import java.util.ArrayList;
import java.util.List;
import bclass.board.BoardVO;
//입력 수정 삭제 조회 상세보기
//입력,수정,삭제 - return int로 한다. 파라미터는 BoardVO로 한다
//전체 조회 - List<BoardVO>, List<Map>
//반복되는 코드를 줄이기 위한 방법으로 공통분모 생각해 본다.
//반복되는 코드를 모두 모아서 한 눈에 보이게 펼치고 리턴타입과 파라미터에 대한 선택- 첫번째 시도로
//추출한 데이터를 가지고 연산처리를 할 경우 타입체크가 필수 이므로 이런 경우는 VO제네릭 으로 한다.
//Map<String, Object> Object-> int Object -> double ClassCastingException
// 설계단계 - 화면정의서, 요구사항 정의서, 클래스 다이어그램(클래스설계:클래스관계), 유스케이스 다이어그램(업무담당자의 요구사항을 그림- 절차)
//BoardDao.java설계하여 처리하시오.
//왜 오라클서버 연동하는 클래스를 추가로 설계하였나?
//JDBC API(반복되는 코드가 늘어남-업무에대한 규칙이 바뀌면 코드를 수정해야 함) ->
//반복되는 코드를 줄여주는 그러나 쿼리문은 남아있는 myBatis(라이브러리-main가 없는 클래스)사용하여 처리함
//전체적인 클래스 설계가 변한다(야근)|변하지 않는다.(5일)
//클래스를 독립적으로 나누어 관리한다.
//클래스가 분리가 되면 인스턴스화를 잘 해야 한다. - 생성자의 파라미터를 잘 선택한다.
public class FMain {
//입력 처리
/*************************************************************
* INSERT INTO 테이블명(컬럼명1, 컬럼명2,...) VALUES(?,?,?,?,?,?,?,?)
* 쿼리문을 자바코드에 왜 적었나? - 파라미터 자리를 결정할 수 있다. 갯수, 타입, 컬럼명, 컬럼타입
* @param BoardVO
*************************************************************/
//public int boardInsert(Map<String,Object> pmap) {
public int boardInsert(BoardVO bVO) {
int result = -1;
//커밋해야 된다면서요???? - 디폴트값이 autocommit으로 설정됨
//con.setAutocommit(false);
//con.commit();
return result;
}
//수정 처리 - 있는 걸 바꾼다 - PK는 수정할 수 없다. - 7개만 수정이 가능하다.
/*************************************************************
* update dept set dname =:dname, loc =:loc where deptno=:deptno;
* 쿼리문을 자바코드에 왜 적었나? - 파라미터 자리를 결정할 수 있다. 갯수, 타입, 컬럼명, 컬럼타입
* @param BoardVO
*************************************************************/
public int boardUpdate(BoardVO bVO) {
int result = -1;
return result;
}
//삭제 처리
/*************************************************************
* DELETE FROM freebard where fb_no=?;
* 쿼리문을 자바코드에 왜 적었나? - 파라미터 자리를 결정할 수 있다. 갯수, 타입, 컬럼명, 컬럼타입
* @param BoardVO
*************************************************************/
public int boardDelete(int fb_no) {
int result = -1;
return result;
}
//전체 조회 처리
/*************************************************************
* SELECT fb_no, fb_title, fb_writer, fb_hit, fb_group, fb_step, fb_date FROM freeboard
* WHERE fb_title LIKE ?||'%'
* AND (OR) fb_date LIKE ?
* AND (OR) fb_writer LIkE ?
* 쿼리문을 자바코드에 왜 적었나? - 파라미터 자리를 결정할 수 있다. 갯수, 타입, 컬럼명, 컬럼타입
* @param BoardVO
*************************************************************/
//public List<BoardVO> boardList(Map<String,Object> pmap) {
public List<BoardVO> boardList(BoardVO pbVO) {
List<BoardVO> bList = new ArrayList<>();
return bList;
}
//상세보기 처리
public BoardVO boardDetail() {
//public Map<String,Object> boardDetail() {
BoardVO rbVO = null;
return rbVO;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
/*
* 클래스
* 1) 기능처리 위한 클래스
* 2) 데이터셋을 위한 클래스 - 복습 - 단단히 할것
* 3) 서블릿<- JSP학습 - Web기반 서비스 - URL이용 - 네트워크 프로그래밍(소켓) - main메소드는 없다.
* 3-1) 모바일(앱) -> 3+3-1 -> 하이브리드 앱개발 - 함수형프로그래밍 언어(람다식, 화살표함수)
*
*/
package bclass.step1;
class G{
int i = 1;
static int j = 10;
G(){
j++;
i = j;
}
}
public class GMain {
//여러개의 인스턴스가 하나의 전변을 공유하고 싶다면 static한다
public static void main(String[] args) {
G g = new G();
System.out.println(g);
System.out.println(g.i);
System.out.println(G.j+1);
g = new G();
System.out.println(g);
System.out.println(g.i);
System.out.println(G.j+1);
g = new G();
System.out.println(g);
System.out.println(g.i);
System.out.println(G.j+1);
}
}
package bclass.step1;
public class Car {
private int carNum;
public Car() {//디폴트 생성자 - 리턴타입이 없고 , 구현없음, 생략가능, 생략했을 경우 컴파일 될때 JVM주입해줌
int x = CarFactory.serialNum++;
System.out.println("x: "+x);
carNum = CarFactory.serialNum;
}
public int getCarNum() {
return carNum;
}
public void setCarNum(int carNum) {
this.carNum = carNum;
}
}
package bclass.step1;
public class CarFactory {
public static int serialNum = 1000;
public static Car getInstance() {
Car myCar = null;
if(myCar == null) {//myCar 변수를 null체크하여 null인 경우에만 인스턴스화함
myCar = new Car();
}
return myCar;
}///////////end of getInstance
}
package bclass.step1;
public class CarTest {
public static void main(String[] args) {
Car yourCar = CarFactory.getInstance();
//Car himCar = CarFactory.getInstance();
//Car herCar = CarFactory.getInstance();
//insert here
System.out.println(yourCar.getCarNum());
//System.out.println(himCar.getCarNum());
//System.out.println(herCar.getCarNum());
}
}
package bclass.step1;
class H{
int i;
private static H h = new H();//이른 인스턴스화
private H(){
System.out.println("H()");
}
static H getInstance() {
return h;
}
}
public class HMain {
public static void main(String[] args) {
H h = H.getInstance();
H h2 = H.getInstance();
System.out.println(h+", "+h2);
}
}