본문 바로가기

자바스프링웹공부(2024)/자바

2024.09.05.import, static

반응형

* import문

 - 특정 패키지 또는 패키지 내의 클래스를 현재 클래스 내에 포함시키는 키워드
 - 자신과 동일한패키지에 존재하는 클래스가 아닌 다른 패키지의 클래스는 직접 이름만으로 접근이 불가능하며, 
    반드시 패키지 명을 포함하여 지정해야 함. ex) new java.util.Scanner() 
    => 원래 클래스명을 지정할 때 [패키지명.클래스명] 형태로 지정해야하지만  패키지명을 생략하고 싶은 경우 해당 패키지명은 import문으로 등록시키면 해당 패키지명을 생략하고 클래스명만으로 사용 가능해짐 ex) new Scanner()
 - package 문과 달리 여러번 사용할 수 있으며 package 문 아래쪽 다른 코드들보다 위쪽에 위치해야함.
 - 클래스명 지정 시 자동 완성 기능을 사용햐여 import문을 자동 생성하거나  단축키를 사용하여 자동생성가능

    이클립스 단축키 : ctrl + shift + o
     => 동일한 이름의 클래스가 여러 패키지에 존재할 경우 선택창 표시

- import java.util.*; // util안에 있는 폴더만 한다는 거지 밑에 있는 하위폴더들 포함이라는 말이 아니다.
  => util 패키지 내의 모든 클래스를 import 하겠다는 뜻.
  => util 패키지 내의 하위 패키지에 클래스까지 import 되는 것 아님.!!

- 이름이 같은 클래스가 여러개 있을 때 패키지를 선택하여 사용하여야 함.

   ex) Date 클래스의 경우, 여기서는 java.util.Date를 선택함.

패키지가 2개가 있다(java.util, java.sql)


  다른 패키지인 java.sql.Date 클래스를 사용하려면 import문 중복이 불가능하므로  패키지명을 포함하여 클래스명을 지정해야한다! ex) java.sql.Date date = new java.sql.Date(21L);


* static

* 변수 (선언 위치에 따른 분류)
1. 로컬변수(Local Variable) = 조금 쓰다가 사라지면 로컬변수라고 보면됨.
   - 메서드 내부에서 선언된 변수(for문, if문 등 포함)
   - 주로 메서드 중괄호 내부에서 선언되는 변수를 말하며  for 문의 소괄호() 에서 선언되는 제어변수도 로컬변수에 해당함
     => 메서드 파라미터 부분인 소괄호() 에서 선언되는 변수를 별도로 파라미터 변수라고도 하지만 로컬변수로 통일해도 무방함.
   - 해당 변수가 선언된 위치로부터 소속된 중괄호가 끝나는 지점까지만 접근가능
    => 라이프 사이클 (Life Cycle)이라고 하며, 로컬변수의 라이프 사이클은 선언 지점부터 중괄호가 끝나는 지점까지이다. 
   - 반드시 초기화 후에 사용해야 한다. 
     
2. 멤버변수(Member Variable)
 - 클래스 내부, 메서드 외부에서 선언되는 변수
 - 클래스 내의 어느위치에서라도 동일한 변수로 취급됨.(메모리 생성 시점은 다름)
 - 클래스 내의 생성자나 메서드 등에서 접근가능 
 - 별도의 초기화를  하지 않을 경우 기본값으로 자동 초기화 됨. 
 
 (static 이 붙고 안붙고 차이 1) 안붙고 2) 붙고)
  1) 인스턴스 멤버변수
  - 멤버변수의 선언부 접근제한자 뒤(리턴타입)에 아무것도 붙지 않은 변수
  - 인스턴스가 생성될 때마다 각각의 공간이 새로 할당되므로  인스턴스가 다르면 인스턴스 멤버변수(저장공간)가 다르며,
    인스턴스 멤버변수에 저장되는 값이 다를 수 있다. 
  - 인스턴스가 생성(new)되는 시점에 메모리에 로딩(생성)되며,  인스턴스가 제거되는 시점에 메모리에서 제거됨.
  2) 클래스(정적, static) 멤버변수 = static으로 이해하면 된다.
  - 멤버변수의 선언부 접근제한자 뒤에 static 키워드를 붙여 선언한 변수. 
  - 이거는 쓰면 바로 메모리에 올라가니까 무조건 좋은 것이 아니다.
  - static 멤버 접근 방법 : 인스턴스명을 앞에 굳이 붙이지 않고. 속해있는 클래스 명만 적어도 사용가능함.

  - 메서드 내에서는 멤버변수와 자신의 메서드에서 선언된 로컬변수에만 접근 가능!


<자바 프로그램 실행과정>
  1. 소스코드 작성 및 컴파일(번역) 후 클래스 실행 (ctrl + F11)
  2. 클래스 로딩 - 클래스(정적) 멤버변수 및 메서드가 메모리에 로딩
  3. JVM에의해 main() 메서드 호출(실행)
  4. 인스턴스 생성 - 인스턴스 멤버변수 및 메서드가 메모리에 로딩 (new XXX)
  5. 메서드 호출(실행) - 메서드 내의 로컬 변수가 메모리에 로딩
  6. 결과 출력
 
  <static 키워드> 

- 프로그램 시작되자마자 데이터 저장가능한 상태로 프로그램 종료될때까지 상주해서 메모리에 계속 고정(static)되어있다.
- 정적(고정된) 이라는 의미를 갖는 키워드
- 클래스, 메서드, 변수의 지정자로 사용가능
- 멤버 메서드 또는 변수에 static 키워드를 사용할 경우
    인스턴스 생성과 관계없이 클래스가 로딩되는 시점에 함께 메모리에 로딩됨.
    => 인스턴스 생성 전에 메모리에 로딩됨.  따라서, 인스턴스 생성 없이도 접근가능 (클래스 명만으로 접근가능)
 <static 멤버변수>
- 인스턴스 생성전, 클래스가 메모리에 로딩될 때 static 변수도 함꼐 로딩됨.
    => Heap 공간이 아닌 Method Area (=(Static Area)에 변수가 생성됨(공유영역) - 전역변수들은 죄다 여기에 올라와잇음
- 모든 인스턴스가 하나의 변수(메모리)를 공유함.
    (= 클래스 하나당 하나의 변수만 생성되며, 해당 변수를 모든 인스턴스가 공유) 

    ex) 객체.멤버변수 로 사용해도 결국 하나밖에 없다
- 참조변수 없이 클래스 명만으로 해당 멤버에 접근 가능 ex) 클래스명.멤버변수명
 <static 메서드>
 -static 멤버변수와 마찬가지로 클래스 로딩 시 함께 메모리에 로딩되므로 클래스명만으로 호출 가능한 메서드
  ex) 클래스명.메서드명()

class StaticMember {
    static int a = 10;
    int b = 20;
    public void normalMethod() {
    	System.out.println("일반메서드");
	}
	public static void staticMethod() {
		System.out.println("static 메서드");
	}
}
public class Ex2 {
    public static void main(String[] args) {
    StaticMember s1 = new StaticMember();
    StaticMember s2 = new StaticMember();
    System.out.println("s1.a = " + s1.a + ", s2.a = " + s2.a); // s1.a = 10, s2.a = 10
    System.out.println("s1.b = " + s1.b + ", s2.b = " + s2.b); // s1.b = 20, s2.b = 20
 
 	StaticMember.a = 99; // static 멤버변수 변경
    System.out.println("s1.a = " + s1.a + ", s2.a = " + s2.a); // s1.a = 99, s2.a = 99 : 실제 하나밖에 없기때문에 인스턴스명을 다른것을 적어도 값이 같다.
	System.out.println("s1.b = " + s1.b + ", s2.b = " + s2.b); // s1.b = 20, s2.b = 20
    
	s2.b = 999; // s2. 인스턴스 변수 b의 값을 999로 변경
    System.out.println("s1.a = " + s1.a + ", s2.a = " + s2.a); // s1.a = 99, s2.a = 99 
	System.out.println("s1.b = " + s1.b + ", s2.b = " + s2.b); // s1.b = 20, s2.b = 999; 
    // => s1과 s2는 서로 다른 인스턴스 변수 b를 갖게 되므로
	// 		s2인스턴스의 b값을 변경하더라도 s1인스턴스의 b는 영향을 받지 않는다. 
}

 

<static 메서드>
 - static 멤버변수와 마찬가지로 클래스 로딩 시 함꼐 메모리에 로딩되므로 인스턴스 생성과 관계없이 클래스명만으로 호출 가능한 메서드 ex)클래스명.메서드명() - 형태로 호출
 
< static 메서드 주의사항>
  1. static 메서드 내에서는 인스턴스 멤버변수에 접근 불가! (staticMethod안에서 객체생성하여 인스턴스 멤버변수를 사용하면 가능)
  => static 메서드가 로딩되는 시점에서는 인스턴스가 생성되기 전이므로 인스턴스 멤버변수도 로딩되지 않은 상태이다.
  따라서, static 메서드 호출 시점에 인스턴스 멤버변수가 존재하지 않을 수 잇따. 
   2. static 메서드 내에서 일반 메서드 호출 불가!
   => 사유 동일
   3. static 메서드 내에서 this, super 사용불가
   => static 멤버가 메모리에 로딩되는 시점에는 인스턴스가 생성되기 전이므로

        인스턴스 주소를 저장하는 레버런스 this 도 생성되기 전이다.
        따라서 static 메서드 내에서는 this 사용이 불가능하다. 

class StaticMethod {
	private int normalVar = 10;
	private static int staticVar = 20;
	// normalVar 변수에 대한 Setter 정의
	public void setNormalVar(int normalVar) {
		this.normalVar = normalVar;
	}
	// staticVar 변수에 대한 Setter 정의
	//public void setStaticVar (int staticV) { // 이거는 메인에서 사용할 때 객체 생성을 해야하므로 안됨.
	public static void setStaticVar (int staticV) {
		//	this.staticVar = staticV; 사용안됨. // 오류 static 메서드 내에서 this 사용불가
	    // 레퍼런스 this 대신 클래스명을 사용하여 멤버변수 지정 가능.
		StaticMethod.staticVar = staticV;
	}
	public void normalMethod() {
		// 일반 메서드에서는 멤버변수 둘다 사용 가능하다. 
		System.out.println(normalVar);
		System.out.println(staticVar); 
		
	}
	public static void staticMethod() {
		// 메서드 안에서 인스턴스 생성후에 변수를넣으면 사용가능하다. 
		StaticMethod sm = new StaticMethod();
		System.out.println(sm.normalVar);
		sm.normalMethod(); 
	}
}

public class Study {
	public static void main(String[] args) {
		StaticMethod.staticMethod();
        /* 결과 
        10
        normalVar10
        staticVar20
        */
	}
}

 

 

*static 변수와 일반변수의 실행순서

public class Study {
	int b = check(2); 	
	static int a = check(1); // static이 붙으면 저장공간이 바로 생긴다. 
	public static int check (int i) { // JVM이 실행하여 호출하면 실행 가능한 상태로 세팅됨 
		System.out.println("call : " + i);
		return i;
	}
	public static void main(String[] args) {
		System.out.println("main() 메서드");
		Ex4 ex = new Ex4();
	}
	static int c = check(3);
}
[ 실행순서 ]

 

* 싱글톤 패턴 (Singleton Pattern)
- 애플리케이션이 시작될 때 어떤 클래스의 객체(왜냐면 클래스는 원래 1개고 여기서는 new가 1개이고 싶다는 뜻)가 최초 한번만 메모리를 할당받고   그 메모리에 인스턴스를 만들어 사용하는 디자인 패턴.
- 일반적으로 java에서는 생성자를 private 로 선언해서 생성불가능하게 하고 getInstance() 메서드 작성해서 객체를 받도록 구현
   => 싱글톤 패턴은 단 하나의 인스턴스를 생성해 사용하는 디자인 패턴

class Person {}
class Car {
	String model;
	public void accelotor() {}
//		car 는 하나만 사용하고 싶다. 인스턴스가 생성이 된다면 절대로 한개만 사용할 수 없다. 위에 Person 인스턴스처럼 주소가 다른 인스턴스들이 쏟아져 나올 것이다.
//      1. 외부에서 객체를 생성할 수 없도록 생성자 private 처리 - 내부에서는 객체생성을 할 수 있다. 
	private Car() {}
// 		2. 자동차 한대(new Car())를 생성하여 static 변수에 저장(1개 보장)
// 		3. 외부에서 car 객체를 사용할 수 있도록 car 변수에 대한 getter 메서드 정의
	// => 일반 메서드로 선언할 경우 외부에서 호출할 방법이 없으므로(객체생성도 막아버렸음.) 
	public static Car getInstance() { // getInstance() 메서드가 있으면 무조건 싱글톤이라고 생각해도 무방하다.
		return car;
	}
}
public class Ex5 {
	public static void main(String[] args) {
		Person p1 = new Person();
		Person p2 = new Person(); 
		System.out.println(p1 == p2); // false : 둘다 주소가 다르니까. 서로 다른 사람임.
		
		Car car1 = Car.getInstance();
		Car car2 = Car.getInstance();
		Car car3 = Car.getInstance();
		
		System.out.println(car1);
		System.out.println(car2);
		System.out.println(car3); // 같은 차를 가리키므로 주소가 1개이다.
		System.out.println(car1==car2); // true
		System.out.println(car2==car3); // true
		
		car1.model = "Sonata";
		System.out.println(car2.model); // car2.model 도 결과가 Sonata이다. 
	}
}
반응형