재_패캠Java/Spring - 3주차

하파타카·2023년 7월 28일
0

패캠JAVA, Spring과정

목록 보기
14/20

메서드와 변수의 관계

자바 => 객체지향언어
객체 => 메서드(함수)

변수와 배열의 관계에 유의하며, Java에서는 배열이 객체임을 생각하자.

메서드(Method)란?

  • 객체가 가진 동작(기능)을 메서드(Method)라고 한다.
  • 객체지향 프로그램은 객첵 가지고 있는 메서드를 통해 데이터를 주고받으며 상호작용을 한다.
  • API에서 제공해주는 메서드와 사용자 정의 메서드로 분류할 수 있다.
  • 메서드는 정의 후 호출하여 사용해야 한다.

모든 메서드의 결과는 하나의 형태로 나온다.

메서드는 클래스 내에서 독립적으로 만들어야 한다.
→ 하나의 메서드는 하나의 단위작업을 처리하도록 한다.

자바제어자 반환타입 메서드명(입력매개변수){
	수행작업
}

public int add(int x, int y){
	int z = x + y;
    return z;
}

반환값이 없을 경우 반환타입은 void로 선언

메서드는 변수다

public int add(int x, int y){
	int z = x + y;
    return z;
}

int result = add(3, 4);	// add메서드 호출
System.out.println(result);	// 7

위 예제의 경우 add함수가 z라는 결과를 만들어 낸다.
함수 이름이 변수 역할을 하며 함수 이름으로 값을 전달한다.

변수는 일반 자료형을 담는다면 함수는 데이터를 처리한 결과를 담는다.

add(3, 4)에서 3. 4는 인수 혹은 매개변수라고 부름.

매개변수 전달기법(parameter passing)

매서드는 값이나 번지를 전달받는데, Java는 거의 번지를 전달한다.

1) Call By Value (값 전달)

public class CallByReference {
    public static void main(String[] args) {
        float a= 56.7f;
        float b = 78.9f;

        floatAdd(a, b);
        System.out.println("종료");
        // 결과: hap = 135.6\n종료
    }

    public static void floatAdd(float a, float b){
        float hap = a + b;
        System.out.println("hap = " + hap);
    }
}

2) Call By Reference (번지 전달)

public class CallByReferenceExam {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,5,6,7,8,9,10};
        int result =addArray(a);

        System.out.println("result = " + result);
        // 결과: result = 55
    }

    public static int addArray(int[] a){
        int sum = 0;

        for (int i=0; i<a.length; i++){
            sum+=a[i];
        }
        return sum;
    }
}

위 예제에서 a는 값이 아니라 배열 객체의 주소(번지)를 가지고 있다.
고로 매개변수로 주소값이 전달되는 것.

메서드 오버로딩(Overloading)

  • 하나의 클랙스 내에서 동일한 이름의 메서드를 여러 개 사용할 수 있는 객체지향 기법.
  • 동작이 유사한 메서드끼리 이름을 같게 만들면 원하는 메서드를 찾기 편리하다.
  • 조건: 서로 메서드 시그니처가 달라야 한다.
    메서드 시그니처란? 매개변수의 개수, 매개변수의 타입.
    둘 중 하나이상 달라야 한다.

패캠Java/Spring 4주차 - Override 오버라이딩

예제

public class OverloadingTest {
    public static void main(String[] args) {
        int a = 3;
        int b = 6;
        int result1 = addNum(a, b);
        System.out.println("result1 = " + result1);

        float x = 3.1f;
        float y = 6.2f;
        float result2 = addNum(x, y);
        System.out.println("result2 = " + result2);
    }

    // Q. 매개변수로 두 개의 정수값을 받아 총합을 리턴하는 메서드를 정의하시오.
    public static int addNum(int a, int b) {
        int sum = a + b;
        return sum;
    }

    // Q. 매개변수로 두 개의 실수값을 받아 총합을 리턴하는 메서드를 정의하시오.
    public static float addNum(float a, float b) {
        float sum = a + b;
        return sum;
    }
}

두 메서드의 이름은 addNum으로 동일하지만 매개변수의 타입이 다르므로 다른 메서드로 인식한다.

정적 바인딩

정적 바인딩이란 컴파일 시점에서 호출될 메서드가 결정되는 바인딩을 말한다.

개발자가 메서드 오버로딩을 통해 같은 이름의 메서드를 여러개 만들어도 실제로는 컴파일 시 컴퓨터 내부에서는 서로 다른이름의 메서드로 인식된다
=> 즉, 메서드 오버로딩을 한다고 메서드를 찾느라 속도저하가 발생하지는 않는다.

참고로 오버로딩과 반대로 추후 나올 개념인 오버라이드(override)의 경우 동적 바인딩을 사용하므로 속도저하의 원인이 될 수 있다.


-학습정리 & quiz-
1. 기능?? → 메서드(Method)
2. 메서드 오버로딩(Method Overloading)
3. 매개변수의 타입, 갯수
4. 컴파일 시점에서 사용될 메서드가 결정되는 바인딩
5. 값 전달 기법(Call By Value), 주소 전달 기법(Call By Reference)
6. 하나의 형태
7. return


객체지향 프로그래밍 #1

클래스로 객체 모델링하기

객체를 만들기 위해 모델링 도구인 class를 사용한다.

객체(Object) = 모델(Model) = 덩어리(Value Object) = 이동(Data Transfer Object=DTO)

해당 클래스가 모델임을 알리기 위해 클래스 이름 뒤에 VODTO를 붙이기도 한다. (안붙여도 무관함)

BookDTO b;
=> 책이라는 데이터를 변수에 저장하려면 책이라는 자료형이 필요하다. 이때 bookDTO라는 사용자정의 자료형을 지정한다.

클래스(class)

객체를 설계(모델링)하는 도구.
혹은 자료형 측면에서는 사용자 정의 자료형을 만드는 도구.

=> 자료형 측면: 원하는 자료형의 객체를 만들기 위해 사용하는 도구
=> 객체지향 측면: 객체의 멤버변수와 멤버메서드를 가져와 설계하는 도구

public class BookDTO {
	// 멤버 변수(필드)
    public String title;
    public int price;
    public String company;
    public String author;
    public int page;
    public String isbn;
 	
    // 멤버 메서드
    public void printTitle(){
        System.out.println("title = "+title);
    }
}

생성자(Constructor)

new Book();
객체를 메모리에 생성하는 역할.

  • new 연산 메서드에 의해 호출됨
  • 자신이 가진 멤버들을 메모리에 올려 객체를 생성하는 역할
  • 메서드 이름과 클래스 이름이 동일해야 함
  • 접근제한자가 public인 경우에만 사용가능
  • 모든 클래스는 기본생성자(default constructor)를 가지고 있음
  • 객체의 초기화를 위해 사용됨
  • 리턴타입이 없음 (모든 생성자는 리턴타입이 없으므로 void를 생략함)

예제

BookDTO.java파일은 위의 예제를 그대로 사용함.

public class BookTest {
    public static void main(String[] args) {
        BookDTO book = new BookDTO();

        book.title ="자바공부책";
        book.titlePrint();	// 결과: title = 자바공부책
    }
}

틀을 만들어두고 내용만 바꿔가며 객체를 찍어낼 수 있어 클래스와 객체는 흔히 붕어빵틀과 붕어빵에 비유되곤 한다.

this

자기 자신을 가리키는 객체변수(참조변수, 포인터 변수).


-학습정리 & quiz-
1. 사용자정의 자료형
2. 객체를 모델링하는 도구
3. 객체생성
4. 멤버변수(필드 Field), 멤버메서드
5. 생성자 메서드(Constructor)
6. this
7. 인스턴스(Instance)


클래스의 종류

모델(Model)

클래스를 역할에 따라 부르는 이름을 모델(Model)이라고 함.
역할에 따라 다양한 모델을 만들어 사용할 수 있다.

class - 프로그래밍적 명칭
model - 소프트웨어 공학적 명칭

종류
main 클래스 : 프로그램을 시작하는 클래스
DTO, VO Model : 데이터를 이동하기 위해 담는 모델
DAO Model : 데이터를 (DB와 연동하여)처리하는 모델
Utitliy Model : 도움을 주는 모델

DTO, VO

데이터를 이동하기 쉽게 한번에 담을 수 있는 바구니 역할을 하는 모델.

- CarVO.java -

public class CarVO {
    public int carSn;
    public String carName;
    public int carPrice;
    public String carOwner;
    public int carYear;
    public String carType;
}

- CarTest.java -

public class CarTest {
    public static void main(String[] args) {
        // Q. 자동차의 정보를 [키보드로 부터 입력]받아 [다른 메서드]로 이동해야 하는 경우를 생각해보자.
        Scanner scan = new Scanner(System.in);
        CarVO car1 = new CarVO();

        System.out.print("자동타 일련번호:");
        car1.carSn = scan.nextInt();
        scan.nextLine();

        System.out.print("자동타 이름:");
        car1.carName = scan.nextLine();

        System.out.print("자동타 가격:");
        car1.carPrice = scan.nextInt();

        System.out.print("자동타 소유자:");
        car1.carOwner = scan.nextLine();
        scan.nextLine();

        System.out.print("자동타 연식:");
        car1.carYear = scan.nextInt();
        scan.nextLine();

        System.out.print("자동타 타입:");    // G(휘발유), D(경유)
        car1.carType = scan.nextLine();

        carInfoPrint(car1);
    }
    // Q. 매개변수로 자동차의 정보를 받아서 출력하는 메서드르 정의하시오.
    public static void carInfoPrint(CarVO car){
        System.out.println(car.carSn+"\t"+car.carName+"\t"+car.carPrice+"\t"+car.carOwner+"\t"+car.carYear+"\t"+car.carType);
    }
}


위와 같은 예제를 CarDTO클래스 없이 만드려면 매개변수로 일일히 하나씩 값을 보내줘야 하지만, DTO클래스를 사용하면 하나의 객체만을 매개변수로 넘겨주면된다.

DB의 데이터를 가져와 사용할때에도 마찬가지.

DAO

Data Access Object
데이터베이스에 데이터를 검색, 삭제, 저장, 수정하기 위해 만들어진 클래스(모델)
= CURD동작을 가진 클래스 = 비즈니스 로직을 처리하는 클래스

예제
실제로 DB연결을 하지는 않고 어떤 역할을 하는지만 실습
- CarDAO.java -

public class CarDAO {
    // CRUD
    public void carInsert(CarVO car){
        // DB연결, insert SQL
        System.out.println("car정보가 DB에 저장되었습니다.");
    }
}

- CarInsertTest.java -

public class CarInsertTest {
    public static void main(String[] args) {
        // 자동차정보를 키보드로 입력받아 DB에 저장하시오.(JDBC)
        Scanner scan = new Scanner(System.in);
        CarVO car1 = new CarVO();

        System.out.print("자동타 일련번호:");
        car1.carSn = scan.nextInt();
        scan.nextLine();

		// ...생략...

        CarDAO dao = new CarDAO();
        dao.carInsert(car1);
    }
}

Utility

  • 반복적으로 사용해야할 기능을 별도의 클래스로 만들어 필요할때 사용하는 클래스
  • 필수는 아님
  • 자바의 java.util 패키지에 Utility클래스가 많으니 참고해볼것

예제
- CarUtilityTest.java -

public class CarUtilityTest {
    public static void main(String[] args) {
        // 자동차 정보를 출력하는 동작을 가진 Utility클래스를 설계하시오.
        int carSn = 11111;
        String carName = "BMW828i";
        int carPrice = 90000000;
        String carOwner ="홍길동";
        int carYear = 2015;
        String carType = "G";

        CarVO car = new CarVO();
        car.carSn=carSn;
        car.carName=carName;
        car.carPrice=carPrice;
        car.carOwner=carOwner;
        car.carYear=carYear;
        car.carType=carType;

        CarUtility carUtility = new CarUtility();
        carUtility.carPrint(car);
    }
}

- CarUtility.java -

public class CarUtility {
    public void carPrint(CarVO car) {
        System.out.println(car.carSn+"\t"+car.carName+"\t"+car.carPrice+"\t"+car.carOwner+"\t"+car.carYear+"\t"+car.carType);
    }
}

main메서드에서는 객체를 만들기만 하고 출력하는 기능은 CarUtility클래스로 옮겨서 기능을 분리함.


-학습정리 & quiz-
1. Model
2. DTO(VO), DAO, Utility
3. DTO, VO
4. DAO
5. Create, Read, Update, Delete


접근권한

접근제어

객체지향 프로그래밍에서는 보안을 위해 객체 상호간의 접근을 제어할 필요가 있음.

객체의 상태정보(멤버변수)는 중요하므로 일반적으로 접근을 막아야 한다.
반대로 행위정보(멤버메서드)는 상호작요이 필요하기 때문에 일반적으로 접근을 허용한다.

접근 제한을 위해서는 접근제한자를 이용한다.

접근제한자

public : 모든 클래스에서 접근가능 (모든 클래스는 public, 모든 멤버변수는 public)
private : 모든 패키지에서 접근불가 (자기자신만 접근가능, 모든 멤버변수는 private)
protected : 상속관계에서 하위클래스에서 상위클래스로 접근가능
default : 동일한 패키지에서만 접근가능 (생략가능)

멤버변수는 private로 선언 후 멤버변수에 접근하는 멤버메서드를 만들어 메서드를 통해 데이터를 다루는 방법을 사용한다.

패키지(Package)

  • 서로 기능이 비슷한 클래스끼리 모아서 관리하기 위해 사용한다. 폴더와 유사한 개념.
  • 패키지 외부에서부터의 클래스 접근을 막기 위한 보안적 측면을 위해 사용.(실제로 보안적 의미는 크지않다)
  • Java에서 제공해주는 API도 패키지의 형태로 배포됨.

패키지 이름을 알아야 해당 클래스를 import해서 사용하므로 어떤 패키지의 클래스를 쓰는지는 알아둬야 한다.


-학습정리 & quiz-
1. public, default, protected, private
2. pakage
3. java.lang
4. 풀네임, import
5. java.lang.String, java.util.Scanner
6. import


VO클래스(객체) 설계

클래스는 객체를 모델링하는 도구로, 모델링(설계)을 잘해야 좋은 프로그램을 만들 수 있다.

정보 은닉이란?

자신의 정보를 숨기고 자신의 동작, 기능, 연산만을 통해 접근을 허용하는 것.
클래스 외부에서 특정 정보로의 접근을 막는 것.

예제1

// 객체 모델링(설계)
public class PersonVO(){
	public String name;
    public int age;
}
// 객체 생성
PersonVO p = new Person();
// 객체 사용(접근)
p.name = "홍길동";
p.age = 1000;

=> 멤버변수(필드)를 public으로 선언 시 제한없이 접근이 가능하다.

예제2

// 객체 모델링(설계)
public class PersonVO(){
	private String name;
    private int age;
}
// 객체 생성
PersonVO p = new Person();
// 객체 사용(접근)
p.name = "홍길동";	// 접근불가
p.age = 1000;	// 접근불가

=> 멤버변수(필드)를 private으로 선언 시 접근이 불가능하다.

getter setter

외부에서 접근이 불가능한 멤버변수(필드)에 값을 넣거나 가져오기 위해 사용하는 메서드.

public class PersonVO {
    private String name;
    private int age;
    private String phone;

    // setter
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    // getter
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public String getPhone() {
        return phone;
    }
}
PersonVO p = new PersonVO();
p.setName("홍길동");

setter메서드에서 this는 자기자신을 가리키기 때문에 this.멤버변수명 = 매개변수;는 매개변수로 받아온 값을 자기 자신에게 넣는 것이 된다.

생성자를 통한 객체 초기화

초기화: 객체를 생성함과 동시에 생성된 메서드에서 데이터를 넣는 과정

생성자를 통하면 객체를 초기화할 수 있다.

public class PersonVO {
    private String name;
    private int age;
    private String phone;
    // 생성자메서드로 초기화
	public PersonVO(){
    	this.name = "홍길동";
    	this.age = 50;
    	this.phone = "010-1111-1111";
	}
}

단, 위의 예제에서의 생성자메서드를 사용하면 모든 객체가 똑같은 값을 가지게 된다.
이때 개발자가 원하는 값으로 객체를 생성하기 위해서는 생성자를 오버로딩(Overloading)하여 매개변수로 받아온 값으로 객체를 초기화하는 방법을 사용한다.

// 기본생성자
public PersonVO() {}
// 오버로딩한 생성자
public PersonVO(String name, int age, String phone){
    this.name = name;
    this.age = age;
    this.phone = phone;
}
// 기본생성자를 통한 생성
PersonVO p = new PersonVO();

// 오버로딩한 생성자를 통한 생성
PersonVO p1 = new PersonVO("홍길동", 50, "010-1111-1111");
PersonVO p2 = new PersonVO("김둘리", 100, "010-1000-1000");

일반적으로 기본생성자는 오버로딩하지 않는다.
또한 생성자를 오버로딩 했을 경우 컴파일러가 기본생성자를 자동생성하지 않으므로 직접 만들어주어야 함.

toString()

객체가 가진 값을 문자열 형태로 넘겨주는 메서드.

public class PersonVO {
    private String name;
    private int age;
    private String phone;
    // 생성자, setter getter 생략
    @Override
    public String toString() {
        return "PersonVO{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", phone='" + phone + '\'' +
                '}';
    }
}
PersonVO p1 = new PersonVO("홍길동", 50, "010-1111-1111");
System.out.println(p1.toString());
// 결과: PersonVO{name='홍길동', age=50, phone='010-1111-1111'}

toStringsetter getter 메서드처럼 이클립스나 인텔리제이에서 우클릭 → generate로 자동생성 가능.


-학습정리 & quiz-
1. 정보은닉
2. setter
3. getter
4. 생성자 메서드(Constructor)
5. toString()


배열과 클래스

기본배열

float[] arr = new Float[4];
arr[0] = 10.66f;
arr[1] = 30.1f;
arr[2] = 98.2f;
arr[3] = 67.5f;

객체배열

Student[] std = new Student[4];
std[0] = new Student("홍길동", "컴공", 22, "hong@gogle.com");
std[1] = new Student("박지성", "전기", 30, "park@gogle.com");
std[2] = new Student("홍길동", "건축", 26, "kim@gogle.com");
std[3] = new Student("홍길동", "통신", 21, "lee@gogle.com");

객체배열 선언 후 new생성자를 통해 메모리에 생성하는 과정이 필요함.

static과 JVM메모리 모델

main클래스의 실행방식

1) JVM이 실행할 클래스를 찾음
2) static키워드가 있는 멤버들을 정해진 메모리 위치(static zone)에 한번 자동으로 로딩함
=> main()메서드는 static이기때문에 메모리에 자동으로 로딩된다.
=> static키워드가 있는 멤버는 클래스를 사용하는 시점에 딱 한 번만 메모리에 로딩되는 점이 중요
3) JVM이 static zone에서 main()메서드를 호출
4) 호출된 메서드를 Stack Area에 push한 후 동작을 시작함
=> Stack Area의 program count를 보면 현재 실행중인 프로그램을 확인할 수 있다.

static

메모리에 static메서드끼리 올라가고 none static메서드끼리 올라감. 둘의 영역이 다르다.

static키워드가 있는 멤버는 클래스를 사용하는 시점에 딱 한 번만 메모리에 로딩된다.
즉, 자동으로 메모리오 로딩되므로 new를 통해 객체를 생성해줄 필요가 없다.

예제1
- StaticAccess.java -

public class StaticAccess {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int sum = MyUtil.hap(a,b);
        System.out.println("sum = " + sum);
        // 결과: sum = 30
    }
}

- MyUtil.java -

public class MyUtil {
    public static int hap(int a, int b){
        int hap = a+b;
        return hap;
    }
}

=> static메서드는 객체생성이 불필요함.
이때 불필요한 객체생성을 막기 위해 생성자를 private로 지정할 수 있다.

예시로 System.을 입력하면 나오는 모든 메서드는 static메서드이며 Math메서드는 생성자가 private로 지정되어 있다.
Math.max(10, 20); 처럼 객체생성없이 사용.

none-static의 접근

객체를 생성하여 메모리에 로딩시켜야 함.
=> new라는 연산자를 이용하면 heap메모리에 객체를 생성하고, static메서드에서 heap메모리의 번지를 참고하여 none-static메서드를 사용한다.

예제2

public class NoneStaticTest {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        NoneStaticTest st = new NoneStaticTest();
        int result = st.sum(a,b);
        System.out.println("result = " + result);
        // 결과: result = 30
    }
    public int sum(int a, int b){
        int hap = a + b;
        return hap;
    }
}

메모리의 영역 Method Area, Stack Area, Heap Area 세 개 모두 필요한 예제임. (그림은 ppt참고)

지역변수

변수는 선언한 메서드 내에서만 사용할 수 있으며, 이를 지역변수(local variable)이라고 한다.
다른 메서드에서 같은 이름의 지역변수를 선언하더라도 두 변수는 서로 다른 변수이다. (메모리에 생성되는 공간이 다름)

메서드를 call하면 휘하의 지역변수도 같이 메모리에 공간이 생성되고, 메서드가 종료되면 메서드와 같이 메모리에서 삭제되므로 메서드와 지역변수는 생명주기가 같다.

메모리 모델

  • Method Area : 메서드의 기계어 코드가 할당되는 영역.
    static-zone / none-static-zone 으로 나뉘어진다.
  • Hep Area Generation : 객체가 생성되는 메모리 공간.
    Garbage collector에 의해 메모리가 수집됨.
  • Stack Area / PC register Native Mehod Area : 메서드가 호출되면 메서드의 기계어 코드를 할당받고 메서드가 실행되는 메모리 영역(지역변수, 매개변수들이 만들어지는 공간).
    Program Counter에 의해 현재 실행중인 프로그램의 위치가 관리됨.
    LIFO 구조.
  • Runtime Constant Pool : 상수 값이 할당되는 메모리 영역.
    문자열 중 문자열 상수(Literal 리터럴)가 할당되는 메모리 영역.

Class, Object, Instance

셋 다 객체를 나타내는 용어이다.

Class : 객체를 모델링하는 도구

public class Person(){
	private String name;
    private int age;
}

Object : 클래스를 통해 선언되는 변수
Student st;
=> st: 변수가 구체적인 실체를 가리키지 않을때에는 객체변수라고 함

Instance : 객체생성에 의해 Heap메모리에 만들어진 객체
st = new Student();
=> st는 구체적인 실체를 가리키는 상태이므로 인스턴스 변수라고 함


-학습정리 & quiz-
1. static
2. Stack
3. 생성자를 private로 만듦
4. 인스턴스 Instance
5. ...모르겠다 (답: Method Area, Stack Area, Heap Area, Literal POOL



에러

패키지명을 java.part3로 변경하고 아래에 java파일을 생성한 후 실행하니
Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.part3 에러가 발생했다.

해결

자바가 기본으로 제공하는 패키지명이 java이기때문에 패키지명이 같으면 오류가 발생한다.
fcjava.part3로 패키지명을 변경하자 정상적으로 실행되었다.

예시 - java.util, java.io, java.lang 등

참고링크

profile
천 리 길도 가나다라부터

0개의 댓글