1) 객체지향 프로그래밍
1-1. 객체지향 프로그래밍의 특징
① 캡슐화
- 객체의 데이터(필드), 동작(메서드)을 하나로 묶고 실제 구현 내용을 외부에 감추는 것.
- 외부 객체는 객체 내부의 구조를 알지 못하며 객체가 노출해서 제공하는 필드와 메서드만 이용할 수 있다.
- 자바 언어는 캡슐화된 멤버를 노출시킬 것인지 숨길 것인지 결정하기 위해 접근 제한자를 사용한다.
② 상속
- 객체지향 프로그래밍에서는 부모 역할의 상위 객체와 자식 역할의 하위 객체가 있다. 부모 객체는 자기가 가지고 있는 필드와 메서드를 자식 객체에게 물려주어 자식 객체가 사용할 수 있도록 한다.
- 코드의 재사용성을 높여 준다 : 잘 개발된 부모 객체의 필드와 메서드를 자식이 그대로 사용할 수 있어 자식 객체에서 중복 코딩을 하지 않아도 된다.
- 유지 보수 시간을 최소화시켜 준다 : 부모 객체의 필드와 메서드를 수정하면 모든 자식 객체들은 수정된 필드와 메서드를 사용할 수 있다.
③ 다형성
- 사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질.
- 자동차의 부품을 교환하면 성능이 다르게 나오듯이, 프로그램을 구성하는 객체(부품)를 바꾸면 프로그램의 실행 성능이 다르게 나올 수 있다.
- 다형성을 구현하기 위해서는 자동 타입 변환과 재정의 기술이 필요하다.
1-2. 추상화
- 추상화는 클래스들의 공통적인 요소를 뽑아서 상위 클래스를 만들어내는 것이다.
- 반드시 상위 클래스일 필요는 없어서, 공통적인 속성과 기능을 정의한 하위 클래스를 생성할 수도 있다.
- 한 마디로 추상화는 공통적인 속성과 기능을 정의함으로써 코드의 중복을 줄이고, 클래스 간 관계를 효과적으로 설정하고, 유지/보수를 용이하게 하는 것이다.
- 자바에서는 추상 클래스와 인터페이스라는 문법 요소를 통해 추상화를 구현한다.
1-3. 클래스의 구성 멤버
- 클래스 선언에는 객체 초기화 역할을 담당하는 생성자와 객체에 포함될 필드와 메서드를 선언하는 코드가 포함된다. 그래서 생성자, 필드, 메서드를 클래스 구성 멤버라고 한다.
public class ClassName{
int fieldName; //필드 : 객체의 데이터가 저장되는 곳
ClassName(){...} //생성자 : 객체 생성 시 초기화 역할 담당
int methodName(){...} //메서드 : 객체의 동작으로 호출 시 실행하는 블록
}
① 필드 : 객체의 데이터를 저장하는 역할을 한다. 선언 형태는 변수 선언과 비슷하지만 쓰임새는 다르다
② 생성자 : new 연산자로 객체를 생성할 때 객체의 초기화 역할을 담당한다. 선언 형태는 메서드와 비슷하지만, 리턴 타입이 없고 이름은 클래스 이름과 동일하다.
③ 메서드 : 객체가 수행할 동작이다. 다른 프로그램 언어에서는 함수라고 하기도 하는데, 객체 내부의 함수는 메서드라고 부른다. 메서드는 객체와 객체간의 상호작용을 위해 호출된다.
1-4. 클래스 변수
- 클래스로부터 객체를 생성하려면 객체 생성 연산자인 new가 필요하다.
- new 연산자 뒤에는 생성자 호출 코드가 오는데, 클래스() 형태를 가진다.
- new 연산자는 객체를 생성시킨 후 객체의 주소를 리턴하기 때문에 클래스 변수에 다음과 같이 대입할 수 있다.
클래스 변수 = new 클래스();
ReferenceEdu rf = new ReferenceEdu();
rf.referenceSample();
1-5. 필드 선언과 사용
- 필드는 객체의 데이터를 저장하는 역할을 한다. 객체의 데이터에는 고유, 현재 상태, 부품 데이터가 있다.
ⓛ 필드 선언
- 필드 선언은 클래스 블록에서 선언되어야 한다.
타입 필드명 [ = 초기값 ];
- 타입은 필드에 저장할 데이터의 종류를 결정한다. 기본 타입(byte, short, int, long, float, double, boolean)과 참조 타입(배열, 클래스, 인터페이스)이 가능하다.
- 초기값을 제공하지 않을 경우 필드는 객체 생성 시 자동으로 기본값으로 초기화된다.
*필드 타입별 기본값
| 분류 | 데이터 타입 | 기본값 | |
| 기본타입 | 정수 타입 | byte char short int long |
0 \u0000(빈 공백) 0 0 0L |
| 실수 타입 | float double |
0.0F 0.0 |
|
| 논리 타입 | boolean | false | |
| 참조 타입 | 배열 클래스(String 포함) 인터페이스 |
null null null |
|
public class Car{
String model; //null
int speed; //0
boolean start; //false
Tire tire; //null
}
- 필드와 로컬 변수(전역변수/지역변수) : 로컬변수는 생성자와 메서드 블록에서 선언되며 생성자와 메서드 호출 시에만 생성되고 사용된다. 필드는 클래스 블록에서 선언되며 객체 내부에서 존재하고 객체 내, 외부에서 사용 가능하다.
* 필드와 (로컬)변수의 차이점
| 구분 | 필드 | (로컬)변수 |
| 선언 위치 | 클래스 선언 블록 | 생성자, 메서드 선언 블록 |
| 존재 위치 | 객체 내부에 존재 | 생성자, 메서드 호출 시에만 존재 |
| 사용 위치 | 객체 내, 외부 어디든 사용 | 생성자, 메서드 블록 내부에서만 사용 |
② 필드 사용
- 필드값을 읽고 변경하는 것
- 클래스에서 필드를 선언했다고 바로 사용할 수 있는 것은 아니다. 필드는 객체의 데이터이므로 객체가 존재하지 않으면 필드도 존재하지 않는다.
- 클래스로부터 객체가 생성된 후에 필드를 사용할 수 있다. 필드는 객체 내부의 생성자와 메서드 내부에서 사용할 수 있고, 객체 외부에서도 접근해서 사용할 수 있다.
//외부객체
void method(){
//Car 객체 생성
Car myCar = new Car();
//외부에서 필드 사용
myCar.speed = 60;
}
//객체 내부
//필드
int speed;
//생성자에서 사용
Car(){
speed = 60; //값 변경
}
//메서드에서 사용
void method(...){
speed = 60; //값 변경
}
//생성자와 메서드는 객체가 생성된 후 호출되므로 내부에서 필드를 사용할 수 있다.
- 객체 내부에서는 필드명으로 읽고 변경할 수 있지만, 외부 객체에서는 참조 변수와 도트(.) 연산자를 이용해서 필드를 읽고 변경해야 한다. 도트(.)는 객체 접근 연산자로, 객체가 가지고 있는 필드나 메서드에 접근하고자 할 때 참조 변수 뒤에 붙인다.
public class ClassEdu {
public String model = "소나타";
public int speed = 300;
public static void carEdu() {
String model2= "그랜져";
int speed2 = 200;
System.out.println(model2);
System.out.println(speed2);
}
public void carEdu2() {
System.out.println(model);
System.out.println(speed);
}
}
//공통적인 요소가 아니라면 static 사용은 지양
//new 연산자를 통해 새로운 객체를 생성 및 필드에 접근하여 데이터를 수정하는 것이 올바른 방법
//기능1 시작
ClassEdu ce = new ClassEdu();
System.out.println(ce.model = "그랜져");
System.out.println(ce.speed = 200);
ce.carEdu2();
//기능1 끝
//기능2 시작
ClassEdu ce2 = new ClassEdu();
System.out.println(ce2.model);
System.out.println(ce2.speed);
ce2.carEdu2();
//기능2 끝

1-6. 생성자 선언과 호출
① 기본 생성자
- 모든 클래스는 생성자가 존재하며, 하나 이상을 가질 수 있다. 클래스에 생성자 선언이 없으면 컴파일러는 다음과 같은 기본 생성자를 바이트코드 파일에 자동으로 추가시킨다.
[public] 클래스() {}
- 클래스가 public class로 선언되면 기본 생성자도 public이 붙지만, 클래스가 public 없이 class로만 선언되면 기본 생성자에도 public이 붙지 않는다.
//소스파일(Car.java)
public class Car{}
-> 컴파일 후 바이트코드 파일
//바이트코드 파일(Car.class)
public class Car{
public Car(){} //자동추가
}
-> new 연산자 뒤에 기본 생성자 호출 가능
Car myCar = new Car();
② 생성자 선언
클래스(매개변수, ...){생성자 블록}
- 생성자는 메서드와 비슷한 모양을 가지고 있으나, 리턴 타입이 없고 클래스 이름과 동일하다. 매개변수는 new 연산자로 생성자를 호출할 때 매개값을 생성자 블록 내부로 전달하는 역할을 한다.
//Car 생성자를 호출할 때 3개의 매개값을 블록 내부로 전달한다고 가정
Car myCar = new Car("그랜저", "검정", 300);
//매개변수의 타입은 매개값의 종류에 맞게 작성
//3개의 매개값을 순서대로 매개변수로 대입받기 위해서는 다음과 같이 생성자가 선언되어야 한다.
public class Car{
//생성자 선언
Car(String model, String color, int maxSpeed){...}
}
③ 필드 초기화
- 객체마다 동일한 값을 갖고 있다면 필드 선언 시 초기값을 대입하는 것이 좋고, 객체마다 다른 값을 가져야 한다면 생성자에서 필드를 초기화하는 것이 좋다.
public class korean{
//필드 선언
String nation = "대한민국";
String name;
String ssn;
//생성자 선언
public Korean(String name, String ssn){
//name, ssn 초기화
this.name = n;
this.ssn = s;
}
}
④ 생성자 오버로딩
- 매개값으로 객체의 필드를 다양하게 초기화하려면 생성자 오버로딩이 필요하다.
- 매개변수를 달리하는 생성자를 여러 개 선언하는 것
public class ClassEdu {
public String model = "현대";
public String color;
public int maxSpeed;
public ClassEdu(String color, int maxSpeed) {
System.out.println("객체 생성 완료");
this.color = color;
this.maxSpeed = maxSpeed;
}
public static void carEdu() {
String model2= "그랜져";
int speed2 = 200;
System.out.println(model2);
System.out.println(speed2);
}
public void carEdu2() {
System.out.println(model);
System.out.println(color);
System.out.println(maxSpeed);
}
}
//기능1 시작
ClassEdu ce = new ClassEdu("검정", 200);
ce.carEdu2();
//기능1 끝
//기능2 시작
ClassEdu ce2 = new ClassEdu("빨강", 500);
ce2.carEdu2();
//기능2 끝

1-7. 가변길이 매개변수
- 메서드가 가변길이 매개변수를 가지고 있다면 매개변수의 개수와 상관없이 매개값을 줄 수 있다.
int sum(int...values){}
public void carEdu3(int...num) {
System.out.println(num);
for(int numArr : num) {
System.out.println(numArr);
}
}
ClassEdu ce = new ClassEdu();
ce.carEdu3(50000, 12345, 56789);

1-8. getter/setter/toString
private String name;
private String ssn;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setSsn(String ssn) {
this.ssn = ssn;
}
public String getSsn() {
return ssn;
}
@Override
public String toString() {
return "ClassEdu [name=" + name + ", ssn=" + ssn + "]";
}
ClassEdu ce = new ClassEdu();
ce.setName("김보쌈");
System.out.println(ce.getName());
ce.setSsn("200730");
System.out.println(ce.getSsn());
System.out.println(ce.toString());

2) DTO / VO
2-1. DTO(Data Transfer Object)
- 계층 간 데이터 교환을 위한 객체
- 로직을 가지지 않고 getter/setter 메서드만 가진 순수한 데이터 객체 클래스(Java Beans)로 DB에서 데이터를 얻어 Service나 Controller 등으로 보낼 때 사용
2-2. VO(Value Object)
- 도메인에서 1개 또는 그 이상의 속성들을 묶어서 특정 값을 나타내는 객체.
- 도메인 객체의 일종이고 보통 PK로 식별값을 가지는 엔티티(Entity) 와 구분해서 사용한다.
- 변경 불가능하며 오직 읽기만 가능
* DTO/VO 차이점
- DTO는 setter를 가지고 있어 값을 변경할 수 있지만, VO는 getter만을 가지기 때문에 읽기만 가능하고 수정은 불가능
- DTO는 인스턴스 개념이고, VO는 리터럴 값(변하지 않는 데이터) 개념
- DTO는 단지 데이터를 담아 전달하는 역할만 하지만, VO는 값들에 대해 읽기만 가능한 Read-Only 속성을 가져 객체로서 데이터 그 자체에 의미를 갖는다.
출처: https://hstory0208.tistory.com/entry/Spring-DAO-DTO-VO란-각각의-개념에-대해-알아보자
3) 스프링 프레임워크 = 개발하기 편리한 도구 + mvc 패턴의 개발방법을 지향하는 도구
mvc패턴 : model, view, controller
controller : 단순히 url 요청에 따라서 어떤 메서드를 실행시킬지 결정하는 클래스
view(데이터 전달) > controller(메서드 요청 및 데이터 받고(dto 세팅) > impl(실질적인 기능 구현)
--Action.java
package common;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/registerUser")
public class Action extends HttpServlet {
public void service(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("hi");
System.out.println(req.getParameter("name"));
System.out.println(req.getParameter("ssn"));
System.out.println(req.getParameter("nation"));
ActionDTO acDto = new ActionDTO();
acDto.setName(req.getParameter("name"));
acDto.setSsn(req.getParameter("ssn"));
acDto.setNation(req.getParameter("nation"));
System.out.println(acDto.toString());
ActionServiceImpl serviceImpl = new ActionServiceImpl();
String result = serviceImpl.registerUser(acDto);
System.out.println(result);
}
}
--ActionDTO.java
package common;
public class ActionDTO {
private String name;
private String ssn;
private String nation;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setSsn(String ssn) {
this.ssn = ssn;
}
public String getSsn() {
return ssn;
}
public void setNation(String nation) {
this.nation = nation;
}
public String getNation() {
return nation;
}
@Override
public String toString() {
return "ActionDTO [name=" + name + ", ssn=" + ssn + ", nation=" + nation + "]";
}
}
--ActionServiceImpl.java
package common;
public class ActionServiceImpl {
public String registerUser(ActionDTO acDto) {
System.out.println("---impl 파일 위치---");
System.out.println(acDto.toString());
//회원가입에 관련된 기능이 들어가야 하고, java 문법을 이용해서 아이디 중복체크, pw데이터 이상 없는지 등..
//jdbc 연결하는 구문도 들어가야 한다.
return "회원가입을 축하합니다";
}
}
--index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
회원가입 폼
<form method="post" action="/registerUser">
<input name="name"/>
<input name="ssn"/>
<input name="nation"/>
<button type="submit">전송</button>
</form>
</body>
</html>

'JAVA, JSP' 카테고리의 다른 글
| java - 7장 상속 (0) | 2024.08.08 |
|---|---|
| java - 클래스(리턴데이터타입, 오버로딩, 정적, final, gatter, setter), import문 자동 추가 단축키 (0) | 2024.08.08 |
| java 5장 - 참조타입, 배열, 다차원배열, 열거 (0) | 2024.07.31 |
| java - 반복문 (0) | 2024.07.25 |
| java - 논리연산자, 대입연산자, 삼항연산자 (0) | 2024.07.18 |