ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바스터디(1)
    언어/JAVA 2023. 10. 18. 01:00

    1. 절차지향 to 객체지향

     

    - 과거의 프로그래밍은 절차지향적이었다. 다른 말로 프로세스 지향적이었다. 

    - 데이터를 조작하는 코드를 별도로 분리(함수 혹은 프로시저)로 쪼개고 각 프로시저들이 데이터를 조작하는 방식이다.

    - 각 프로시저는 다른 프로시저를 사용할 수 있고, 각 프로시저는 같은 데이터를 사용할 수 있다.(프로시저간 데이터 공유)

     

    ex) 평균 계산 프로그램 : 각 과목 점수 데이터 읽어서 합+평균구하기(함수1) ->  화면출력(함수2) 

                                            이때 각 프로시저는 데이터를 공유하는 방식 -> 데이터 중심적 구현 

    - 프로세스를 한눈에 볼 수 있다는 장점이 있지만 명백한 한계점이 존재한다.

     

    1. 프로그램 규모가 커지면, 함수가 너무 많이 증가 

    2. 데이터 이름 의미 등등 변경이 생기면 함수를 하나씩 다 수정해줘야한다.

    3. 같은 데이터를 프로시저들이 다른 의미로 사용하는 경우가 발생한다.

        ex) 초기에 회원 서비스 만료일이 null일 경우 오류로 처리하는 프로시저를 만들어 두었다고 하자 

              -> 시간이 지난 후 서비스가 커지고 손님이 많아졌다

              -> 특정 회원은 서비스를 무한정으로 이용 할 수 있다는 의미를 부여하기 위해 만료일에 null값을 설정했다고하자 

              -> 두 함수는 같은 데이터를 다른 의미로 생각한다.

     

    절차 지향의 가장 큰 문제는 한 곳을 수정하면 다른 오류가 연쇄적으로 발생한다는 점이다.!

     

    그렇다면, 이러한 프로시저들을 어떻게 (어떤 기준으로 수납할 것인가?)

     

    1.데이터에 따라 함수를 분리

    public static void main(String[] args){
    	학생1.id =10;
        학생2.name = '장원';
        
        StudentFunction.studentId(학생1);
        
    }
    
    public class StudentFunction{
    
    	public static int studentId(Student st){
        	return st.id;
        }
    	
        public static String studentName(Student st){
        	return st.name;
        } 
    }
    
    public class Student{ //구조체
    	String name;
       	int id;
    }

     

     -> 만약 Student에 id 데이터명이 grade로 바뀌었다고 생각해보자.. 모든 함수들을 수정해줘야할 것이다.

     

    2. 기능(행위,책임)에 따른 분리 

    public static void main(String[] args){
    	
        Student 학생1 = new Student(); //객체
        학생1.studentId();
        학생1.studentName();
        
    }
    
    
    public class Student{ //클래스
    	String name;
       	int id;
        
        public int getId(){
        	return id;
        }
    	
        public String getName(){
        	return name;
        } 
    }

    - 기능에 따라 분리하면, 내부의 구조 변화의 따른 코드의 수정 범위가 제한

    - 데이터와 함수를 하나의 영역에 정의 할 수 있음 

    - 연관 데이터는 내부에 보관되고, 함수를 통해서만 접근할 수 있음 

    - 한마디로 캡슐화됨

     

    * 하나의 도구 혹은 대상에 불가했던 함수데이터와 묶여서 캡슐화되고 하나의 객체가 됨

      이는 하나의 데이터를 가지고 하나의 책임을 수행하게 된다는 의미 -> 주체적(의인화)으로 변화

       StudentFunction.studentId(학생)   -> 학생.getId()

      

      - 함수가 아닌 메서드, 데이터가 아닌 속성이라고 부르는 이유이다. (뇌피셜)

      - 전통적인 함수에 가까운 것은 static 메서드 (하나의 도구, 기능 제공) 

     

     

     

    2. 캡슐화와 의존 

     

    - 캡슐화의 핵심은 기능 구현을 감추는 것 -> 기능을 사용하는 코드는 영향 받지 않도록 하는 것 

     

    2.1 의존 (객체의 활용

     

    - 캡슐화 된 것은 좋다. 그럼 이를 어떻게 사용할까?

    - 객체를 중심으로 구현하다보면, 다른 객체가 제공하는 기능(책임)을 이용해서 나의 책임을 완성 

    - 한 객체가 다른 객체를 이용 -> 다른 객체의 메서드를 호출(메시지)

    - 이처럼 한 객체가 다른 객체를 생성, 메서드를 호출,파라미터로 전달 받는 것을 객체에 의존한다고 표현

     

    * 객체지향적 프로그래밍을 통해 구조 변경에 따른 오류 들은 막았지만, 의존관계로 인한 문제점은 있다.

       의존하는 타입 자체에 변경이 발생하면, 나도 변경될 가능성이 높다. 

       내가 변경되면, 나를 의존하는 타입에 영향을 준다. 

       

     

     

     

    - 캡슐화의 두가지 규칙

      1. Tell, Don'tAsk : 데이터를 물어보지말고 기능 실행에 메시지를 보내라 

    if(학생.getId() < 10)
      //불량학생으로 지정 
      
    if(학생.isMeanStudent()){
    
    }
    
    if(stack.length() == 0)
    if(stack.empry())

     

    2.데미테르의 법칙

         - 메서드에서 생성한 객체의 메서드만 호출

         - 파라미터로 받은 객체의 메서드만 호출

         - 필드로 참조하는 메서드만 호출 

    public void process(Member member){
    학생.getName().split("[a-z]"); //데미테르 법칙 위반
    
    }
    
    학생.process();

     

    3. 객체 지향 설계 과정 

     

    - 수행할 기능을 생각해본다.: 회원이 주문을 하고, 할인 정책에 따라 할인을 받는다.

    - 기능을 세분화 + 객체에 할당해보자:  책임, 역할 (어떤 메시지를 주고받을 지 생각하며 책임을 생성)

                                                                  이때 기능을 구현하는데 필요한 행위와 데이터 추가 

                                                                   최대한 캡슐화한다.

    - 협력(의존)관계를 생각해본다.

     

     

    속성,메서드(행위) 

     

     

     

    4. JVM 메모리 구조 

    Java -> J

    가상화: Virtual  (하드웨어 -> 소프트웨어)

    CPU -> Machine

     

     

     

    Java Virtual Machine: 가상회된 CUP

     

     

    jvm이 구동되면, jvm은 운영체제에서 할당받은 메모리 영역을 다음과 같이 구분해서 사용한다.

     

    - 자바 컴파일러 javac가 자바 소스코드(.java)를 바이트코드(.class)로 컴파일

    - Class Loader를 통해 JVM Runtime Data Area(메모리)에 로딩된다.

    - Runtim Data Area에 로딩된 .class 들은 Executuion Engine이 해석 (바이트 코드 해석 (인터프리터, jit))

       이 과정에서 Execution Engine에 의해 GC의 작동과 스레드 동기화가 이루어진다.

       (마지막 과정은 코드 해석을 넘어 runtime에서 객체 생성, 소멸, 함수 호출 등등을 관장할 듯)

     

    - 모든 스레드가 공유하는 공간 (JVM단위)

     

      > 메서드 영역 (데이터 영역) :

           클래스 정보를 처음 메모리에 올릴 때, 초기화 되는 대상을 저장하기 위한 공간 

          바이트코드 파일을 읽은 내용이 저장됨(runtime에서 바뀌는게 아니라, 그냥 첫 적재시)

          클래스별로 상수(final), 정적필드(static 변수, static 메서드), 메소드 코드, 생성자 코드 저장

          인스턴스 생성을 위한 객체 구조,  런타임 상수 풀(Runtime Constant Pool)과 정적  (static) 변수, 그리고 메서드 데이터와 같은 클래스 데이터들도 이곳에서 관리됩니다

     

       > 힙 : 클래스 인스턴스가 생성되어 저장되는 공간 (new 키워드로 생성된 객체와 배열 저장 - GC가 주기적으로 접근)

                 객체의 번지는 메서드 영역과 스택영역의 상수와 변수에서 참조 가능 

      

    - 스레드(Thread)마다 하나씩 생성 (Thread단위)

     

      - 스택영역 : 스택 영역은 함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는 영역이다.

                         스택 영역은 함수의 호출과 함께 할당되며 함수의 호출이 완료되면 소멸한다.

                        함수가 호출되면, 스택에는 함수의 매개변수, 호출이 끝난 뒤 돌아갈 반환 주소값, 함수에서 선언된 지역변수                      등이 저장되는데 스택 영역에 차례되로 저장되는 함수의 호출 정보를 스택 프레임이라한다.

     

      - PC 레지스터 : 스레드 생성시 마다 생성되는 영역, 현재 실행되는 스레드의 부분 주소와 명령 저장

     

      - 네이티브 메서드 스택 : 자바 이외 네이티브 코드 실행시 작동 

     

     

    * 동적 로딩이란 간단하게 프로세스 시작시 프로세스 주소 공간 전체를 메모리에 올려 두는 것이 아니라, 필요할 때 

       메모리에 적재하는 방식 (필요한 시점에만 올리니까, 메모리를 좀 더 효율적으로 사용) 

     

     

     

    6. 변수의 초기화 

     

    블럭 -> 동기화 블럭 

    웹은 멀티 스레드 환경 -> Thread safe하게~~

     

     

     

     

    '언어 > JAVA' 카테고리의 다른 글

    자바 네트워크 네트워크 입출력 (1) - TCP  (0) 2023.08.22
    Java - 일급컬렉션  (0) 2023.07.25
    Servlet-JSP MVC07 파일 수정하기  (0) 2023.07.24
    Java - File클래스  (0) 2023.07.24
    스트림(2) - 중간 처리  (0) 2023.07.14
Designed by Tistory.