JAVA/이론 정리 및 예제

[JAVA/자바] #6_3 필드(field)/ 예제

chaewon 2021. 9. 14. 17:08

                                    Stack                  heap(동적메모리영역)  static(정적메모리영역)

메모리는 JVM에 의해서 3가지로 나뉜다.

  • codeArray : 작성한 코드(클래스) 
  • static 변수 : Full클래스명으로 명시
    • 모든 메소드 접근 가능
    • 모든 객체들이 공유해서 사용하는 변수
  • num : new 연산자를 사용해서 생성되고 참조가 끝나면 GC에 의해 소멸된다.

 

Life cycle

  • Stack : 메소드가 호출되었을때 생성되고, 메소드가 끝나면 소멸된다.
  • heap : num은 new 연사자를 통해 객체가 생성되고 참조가 끝나게 되면 GC를 통해서 소멸된다.
  • static : size는 프로그램이 시작되면 할당받고 프로그램이 종료되면 소멸된다.

변수 종류별 라이프사이클

 

public class Variable { 
    public static int size; 
    private int num; 
    public void test(){ 
      int num = 100; 
    } 
}

 

변수의 종류

  • 변수들은 선언하는 위치에 따라 종류가 달라진다.
  1. 클래스 영역내부에 작성하는 변수
    • = 맴버변수 (클래스가 가지는 맴버)
    • = 인스턴스 변수 (heap에 할당했을때 생성되는 객체를 인스턴스라고 한다.)
    • = 전역변수 (grobal variable)
    • = 필드
      • 클래스 변수 중 static 키워드가 붙으면
        • = 클래스 변수
        • = static 필드
        • = 정적 필드
  2. 메소드 영역내에 있는 변수
    • = 지역변수
  3. 괄호 안에 있는 변수 
    • - 매개변수
    • = 지역변수 (스택을 사용)
package com.kh.chap03.field.part01_kindsOfVariable;

//변수 선언 위치에 따른 구분
public class kindsOfVariable {                  //클래스 영역의 시작
        //클래스 영역에 작성하는 변수를 필드라고 한다.
        //필드 == 맴버변수 (클래스가 가지는 맴버라는 의미)
        //    == 전역변수 (클래스가 전역에서 사용할 수 있는 변수라는 의미)
        //    == 인스턴스변수 (인스턴수 생성 시 할당받는 변수라는 의미)
        private int globalNum;                 //접근제한자 자료형 변수명
        
        public void testMethod(int num) {        //메소드 영역의 시작
                //메소드 영역에서 작성하는 변수를 지역변수라고 한다.
                //메소드의 괄호 안에 작성하는 변수를 매개변수라고 한다.
                //매개변수도 일종의 지역변수로 생각하면 된다.
                int localNum;
                
                //지역 변수는 선언 외에 다시 사용하기 위해서는 반드시 초기화가 되어 있어야 한다.
                /*System.out.println(localNum);*/        //에러발생
                
                //매개변수는 호출 시 값이 넘어와서 변경되기 때문에 초기화가 필요 없다.
                System.out.println(num);//메소드 호출할때 인자를 줘야하기때문에(강제적) 보장이 되어있어서 에러가 나지 않는다.
                
                //전역변수는 클래스 전역에서 사용 가능하다.
                System.out.println(globalNum);
                
        }        //메소드 영역의 끝
        
        public void testMethod2() {
                //지역변수는 해당 지역(블럭 내)에서만 사용 가능하다.
                /*System.out.println(localNum);*/
                //전역변수는 다른 메소드에서도 사용 가능하다.
                System.out.println(globalNum);
        }
        
}        //클래스 영역의 끝

 

클래스 필드 예약어

  • static : 여러 객체가 공유할 목적의 필드에 사용하며, 프로그램 시작시 정적(static) 메모리영역에 자동 할당되는 멤버에 적용한다. (필드 영역에 붙을 수 있다.)
    → static자체가 캡슐화 원칙에 위배(특수한목적이 아닌이상 사용 x)
  • final : 하나의 값만 계속 저장해야 하는 변수에 사용한다.
    • final을 할땐 반드시 초기값을 선언#화해줘야한다. (필드에 final이 붙으면 값을 변경하지 못한다.)
      --> new라는 연산자를통해 heap에 할당되는데 빈공간으로는 생성이 안되므로 JVM이 정한 기본값으로 설정되는데 후에 변경하지 못하기 때문에 반드시 선언과 동시에 초기화 해줘야한다
  • static final : 상수 필드이다. (변경은 못하고 불러서 사용할 수 있는것)
    • 상수이면서 정적 영역에 보관하여 여러 객체가 공유할 목적으로 사용한다.
      =>반드시 초기값을 지정하며 선언.
    • public static fianl 접근제한자 (예 : Math.PI)
      • public인 상수필드 => 공유할목적으로 사용. 값을 바꾸지못하고, 어디서나 사용할 수 있다.
      • static영역에 올라와있기 때문에 new를 사용하지않고 Math.PI라는 이름으로 공간에 접근할수있다.
package com.kh.chap03.field.part01_kindsOfVariable;

//static 키워드에 대한 구분
public class kindsOfVariable2 {
        //전역변수에서 static 키워드 사용 가능하다.
        //전역변수 테스트
        public static int staticNum;
        
        //public 접근제한자에 static과 final 키워드를 함꼐 사용하는 것을
        //'상수필드' 라고 한다.
        //상수필드는 반드시 선언과 동시에 초기화가 되어야 한다.
        //프로그램 실행 시 static 키워드가 붙은 맴버는 전부 클래스영역(static area)에
        //저장되기 때문이다.
        //프로그램 시작 시 값이 저장되면 변경되지 않고 사용할 목적으로 사용한다.
        /*public static final int STATIC_NUM;*/
        
        //static 영역은 모든 객체가 공유할 목적으로 사용되기 때문에
        //캡슐화 원칙에 위배된다.
        //따라서 static 키워드는 특별하게 명확한 목적이 있을 경우만 사용한다.
        public static final int STATIC_NUM1 = 1;
        //static과 final은 순서를 바꿔도 상관 없다.
        public final static int STATIC_NUM2 = 1;
        
        public void methodTest() {
                //지역변수에서는 static 키워드 사용이 불가능하다.
                //non-static 메소드는 객체가 만들어지고 호출해야만 실행하기 때문이다
                //static 키워드를 변수에 불일 수 없다.
                /*static int localStaticNum;*/
        }
        
        public static void staticMethodTest() {
                //static 메소드 내에서도 static 변수 사용이 불가능하다.
                //static 메소드 내의 변수도 지역변수 이고,
                //메소드 호출 시 stack에 할당을 받는 변수이기 때문에 
                //static 영역에 할당을 하라는 키워드는 사용 불가능하다.
                /*static int localStaticNum;*/
        }
}

 

클래스 필드 접근제한자

클래스 필드의 접근제한자

 


실습문제2

클래스 다이어그램을 보고 클래스 작성하기

 

package com.kh.silsub2.product.model.vo;

public class Product {
        private String pName;        //private 접근제한자는 해당 클래스 내부에서만 사용이 가능하기 때문에 외부에서 접근이 불가능 하다.
        public int price;
        String brand;
        protected static double taxRate;

        public Product() {}

        //setter
        public void setpName(String pName) {
                this.pName = pName;
        }
        public void setPrice(int price)
        {        
                this.price = price;
        }
        public void setBrand(String brand)
        {        
                this.brand = brand;
        }
        public static void setTaxRate(double taxRate) {
                Product.taxRate = taxRate;
        }
        
        //getter
        public String getpName() {
                return pName;
        }
        public int getPrice() {
                return price;
        }
        public String getBrand() {
                return brand;
        }
        public static double getTaxRate() {
                return /*Product.*/taxRate;
        }
        public void information() {
                System.out.println(pName + ", " + price + ", " + brand + ", " + taxRate);
        }
}
package com.kh.silsub2.product.controller;

import com.kh.silsub2.product.model.vo.Product;

public class Run /*extends Product(상속)*/{

        public static void main(String[] args) {
                Product p1 = new Product();
                
                p1.setpName("아이뽕");
                p1.setPrice(1000000);
                p1.setBrand("사과");
                Product.setTaxRate(0.1);
                
                p1.information();
                
                Product p2 = new Product();
                
                /*p2.pName = "아이뽕";*/   //에러, private는 해당 클래스 내부 접근 가능
                p2.price = 100000;
                /*p2.brand = "사과";*/    //에러, default는 해당 패키지 내부에서만 접근 가능
                /*Product.taxRate = 0.1;*/    //에러, static이어도 접근제한자는 적용됨
                
                p2.information();
        }
}

 

실습문제3

클래스 다이어그램을 보고 클래스 작성하기

package com.kh.silsub3.circle.model.vo;


public class Circle {
        private static double PI = 3.14;
        private static int radius = 1;

        public Circle() {}

        //getter
        public static double getPi(){
                return PI;
        }
        public static int getRadius(){
                return radius;
        }
        
        //setter
        //final 키워드가 붙은 필드는 setter 만들지 못함
        /*public static void setPi(double pi) {
                Circle.PI = pi;
        }*/
        public static void setRadius(int radius) {
                Circle.radius = radius;
        }

        //원의 지름을 1 증가시키는 메소드
        public void incrementField() {
                radius++;
        }
        //원의 면적을 구하는 메소드
        public void getAreaOfCircle() {
                double area = radius * radius * PI;
                System.out.println("원의 면적은 " + area + "입니다.");
        }
        //원의 둘레를 구하는 메소드
        public void getSizeOfCircle() {
                double size = 2 * radius * PI;
                System.out.println("원의 둘레는 " + size + "입니다.");
        }

}
package com.kh.silsub3.circle.controller;

import com.kh.silsub3.circle.model.vo.Circle;

public class Run {

        public static void main(String[] args) {
                Circle c = new Circle();
                
                c.getAreaOfCircle();
                c.getSizeOfCircle();

                //지름 1 증가
                c.incrementField();

                //다시 둘레와 면적 구하기
                c.getAreaOfCircle();
                c.getSizeOfCircle();
        }

}

 

클래스 초기화블럭

  • 맴버변수(필드)를 초기화시키는 블록
    • static 블록 : static 필드 초기화, 프로그램 시작시 초기화
    • 인스턴스 블록 : 인스턴스 변수 초기화, 객체 생성시 마다 초기화
private String pName = "갤럭시";       //JVM -> 명시적 초기화값으로 덮어쓰기
private int price = 100000;
private static String brand = "삼송";

{//초기화 블럭값으로 덮어쓰기
		pName = "사이언";
		price = 900000;
		//인스턴스 초기화 블럭에서는 static 필드를 초기화 할 수 있다.
		//하지만 static 초기화 블럭은 프로그램 시작 시에 초기화를 하기 때문에
		//객체 생성 이후 값을 초기화하는 인스턴스 초기화 블럭의 값으로 덮어쓰게 된다.
		brand = "사과";
}

static { //static 초기화 블럭도 start시 같이 실행하기 때문에 static 필드만 초기화
		//static 초기화블럭에서는 non-static 필드를 초기화하지 못한다.
		/*pName = "아이뽕";
		price = 1000000;*/
		brand = "헬지";
}

 

초기화 순서

  • 클래스 변수

static변수는 프로그램 시작시 함께 실행된다.

  • 인스턴스 변수

 

실습문제4

클래스 다이어그램을 보고 클래스 작성하기

package com.kh.silsub4.lotto.model.vo;

import java.util.Random;

public class Lotto {
        //배열 선언
        private int lottoNums[];
        {
                //배열 할당
                lottoNums = new int[6];
                //중복 없이 난수 값 대입
                for(int i = 0; i < lottoNums.length; i++) {
                        lottoNums[i] = new Random().nextInt(45) + 1;
                        
                        for(int j = 0; j < i; j++)
                                if(lottoNums[i] == lottoNums[j]) {
                                        i--;
                                        break;
                                }
                }
                //정렬
                for(int i = 0; i < lottoNums.length; i++) {
                        for(int j = 0; j < i; j++) {
                                if(lottoNums[i] < lottoNums[j]) {
                                        int temp;
                                        temp = lottoNums[i];
                                        lottoNums[i] = lottoNums[j];
                                        lottoNums[j] = temp;
                                }
                        }
                }
        }

        public Lotto() {}

        //getter
        public int[] getLottoNums() {                        
                return lottoNums;                        
        }
        //setter
        public void setLottoNums(int[] lottoNums) {                
                this.lottoNums = lottoNums;
        }
        
        public void information() {
                for(int i = 0; i < lottoNums.length; i++) {
                        if(lottoNums[i] < 10) {
                                System.out.print("0" + lottoNums[i] + " ");
                        }else {                                
                                System.out.print(lottoNums[i] + " ");
                        }
                }
                System.out.println();
        }
}
package com.kh.silsub4.lotto.controller;

import com.kh.silsub4.lotto.model.vo.Lotto;

public class Run {

        public static void main(String[] args) {
                /*Lotto lotto = new Lotto();
                lotto.information();*/
                
                //로또 자동 5게임 구매
                System.out.println("=== 이번주 당첨 예상 번호 ===");
                for(int i = 0; i < 5; i++) {
                        Lotto lotto = new Lotto();
                        
                        lotto.information();
                }
        }

}