개발/Java, Kotlin

[WhiteShip][7주차] 패키지

Kangjieun11 2022. 11. 8. 08:40
728x90

 

 

 

WhiteShip Java Live Study 의 커리큘럼을 따라 개인적으로 공부한 내용입니다.

 

 

 

 


Codestates BE 42 : Study, Commercise 01 Java

 

Thanks to

" Codestates_SEB_BE_42 : Commercise "

강지은, 김례화, 전진우, 주대경

 

 22.11.07

 

 


 

 

7주차 : 패키지

목차

  • package 키워드
  • import 키워드
  • 클래스패스
  • CLASSPATH 환경변수
  • classpath 옵션
  • 접근지시자

 


 

package 키워드

✅ 패키지

특정한 목적을 공유하는 클래스와 인터페이스의 묶음

상위 클래스의 멤버(필드,메서드,이너 클래스)를 하위 클래스와 공유하는 것.

물리적인 하나의 디렉토리(directory). 

 

*하나의 패키지에 속한 클래스나 인터페이스 파일은 모두 해당 패키지에 속해있다.

 

⏺ 패키지의 장점

  1. 클래스들을 그룹 단위로 묶어 효과적으로 관리 (목적)
  2. 클래스의 충돌 방지 기능. 같은 이름의 클래스가 존재하더라도 서로 다른 패키지에 존재하면 이름 충돌 발생 X.

 

계층 구조를 가짐   //  계층 구조 간 구분은    . (점)

ex) package parcticepack.test;

  • 패키지가 있는 경우 소스 코드의 첫번째 줄에 반드시 package 패키지명 이 표시되어야 한다.
  • 패키지 이름은 패키지의 경로까지 포함한 풀 네임을 명시해야 한다.
  • 자바의 모든 클래스는 반드시 하나 이상의 패키지에 속해야 한다.
  • 때문에, 패키지 선언이 없으면 이름없는 패키지(unnamed package)에 속하게 되고, 패키지를 명시하지 않은 모든 클래스와 인터페이스는 모두 같은 패키지에 포함되게 된다.

패키지의 대표적인 예 ))  java.lang, java.util, java.io, java.nio ,,,

 

 

⏺ 패키지 분류 법칙

 

루트 패키지는 a.b.c의 형식으로 구성한다.

ex)

import org.apache.taglibs.* import net.sf.cglib.* import com.sum.accessibility.*

  1. org, com으로 시작하는 가장 높은 부모패키지 : 프로젝트를 이끄는 그룹의 성격을 결정 (org - organization, com - company 약자)
  2. 두번째 패키지명 : 자사의 그룹 또는 사명을 정해주는 구간 : 회사라면 사명,그룹이라면 그룹명이 들어가는게 일반적이다. ex)apache,sf,sun
  3. 세번째 패키지명 : 실제 이 프로젝트의 artifact(소프트웨어 개발 프로젝트를 진행하면서 생성하는 다양한 산출물) 구조 : 위의 두 단계에서 프로젝트 그룹의 성격과 그룹명을 정했다면 이 단계에서는 실질적인 소스의 역할 또는 프로젝트명이 들어간다.

cf) .jar 확장자를 갖는 자바 라이브러리도 아티팩트의 일종이다.

 

기능별로 구분한다.

위에서의 프로젝트를 a.b.c 형식으로 구분한 artifact 구조 다음에 나오는 패키지 분류 → 기능별로 구분하는 것이 좋음

기능별로 구분 : 구분 지어질 수 있는 가장 큰 성격

ex ) DB테이블이라고 할 수 있다.

  • 테이블은 하나의 기능에 대하여 필요한 정보를 칼럼으로 묶는 식의 설계일 것
  • 테이블은 한가지 기능에 대해 세부 데이터를 세팅하여 갖게된다.

 

◼  계층별로 분류한다.

계층별로 분류하는 것은 기능별로 분류하는 것보다 더욱 중요하다고 할 수 있다.

계층별 분류를 티어(tier, tiered) 또는 레이어(Layer)라고 부르기도 한다.

계층별 분류는 사용자가 어떤 디자인 모델을 차용해서 제작하느냐에 따라 갈리므로 작성자가 먼저 어떤 구조로 설계하는지 결정하는게 가장 중요

  • 기본적인 웹 계층은 MVC 구조로 많이 제작 (View는 JSP, Controller는 서블릿 또는 스프링, 스트럿츠 같은 프레임워크가 관리하는 형태)
    • 우리가 클래스로 묶어서 배포할 부분은 모델 부분에 해당 됨
    • 모델은 직접 DB에 접근하여 데이터를 가져오고 연산하여 컨트롤러에 넘겨주는 주된 역할을 담당
  • 모델은 DAO(Data Access Object, DB에 접속하여 데이터를 가져오는 클래스) 계층, 자바빈과 같이 테이블의 컬럼을 오브젝트로 변환시키는 domain 계층, domain과 dao계층을 활용하여 직접적인 기능을 구현하는 service 계층 등이 있다.

cf) MVC (model, view, controller) MVC 패턴은 하나의 어플리케이션, 프로젝트를 구성할때 그 구성요소를 세가지의 역할로 구분한 디자인 패턴이다.

 

 


import 키워드

 

✅ import 란

  • 소스 코드작성시 패키지명을 포함한 클래스명을 매번 사용하는것이 불편
  • 이를 코드 작성 전 import 문을 통해 사용하고자 하는 클래스의 패키지를 미리 명시함으로서 해결
    • import문 은 컴파일러에게 소스파일에 사용된 클래스의 패키지에 대한 정보를 제공하는 것
    • 컴파일 시 컴파일러는 import 문을 통해 소스파일에 사용된 클래스들의 패키지를 알아내어 모든 클래스 이름 앞에 패키지명을 자동으로 붙여준다.
  • 소스코드에 서용되는 클래스 이름에서 패키지명 생략 가능

 

* import 문은 프로그램의 성능에 전혀 영향을 미치지 않는다.

* import 문을 많이 사용하면 컴파일 시간이 아주 조금 더 걸릴 뿐이다.

 

 

⏺ import 문의 선언 위치

 

이미지출처 : https://boyboy94.tistory.com/13

 

위처럼 package, import, class 선언 순으로 선언한다.

// 패키지 
package com.importexam.examtest

// import 문 
import java.util.Date;
import java.lang.Math.*;

// class 선언
class SomeThingClass { ... }

 

⏺ 동일 패키지 내 여러 클래스 import

  • 같은 패키지에서 여러 클래스가 사용될 때 import 문을 여러번 사용해 주는 대신
    패키지명.* 과 같이 사용해 지정된 패키지에 속하는 모든 클래스를 사용할 수 있다.
    •  실행시 성능상의 차이는 전혀 없음
  • 단, import 하는 패키지의 수가 많을 때는 어느 클래스가 어느 패키지에 속하는지 구별하기 어렵다는 단점이 존재하니 무분별한 사용은 자제할 것
  • System 이나 String 같은 java.lang 패키지의 클래스들을 import 문없이 패키지명을 생략해서 사용할 수 있는 이유는 모든 소스파일에 묵시적으로 import java.lang.* 이 선언되었기 때문이다.
    • java.lang 패키지는 매우 빈번히 사용되는 중요 클래스들이 속한 패키지이므로 기본적으로 import 되도록 하였다.
  • 주의
    • 패키지명.* 은 하위패키지의 클래스까지 포함하는것이 아니다.

 

⏺ static import

  • 특정 클래스의 static 맴버를 자주 사용하는 경우 static import 문을 통해 static 맴버를 호출 시 클래스 이름을 생략할 수 있다.
    • 이를 사용하면 반복적인 클래스 이름을 적지 않아도 되므로 코드작성이 편해진다.
    • 코드가 간결해진다.
// 기존 - static import 미사용
public class ImportTest {
    public static void main(String[] args) {
				// 아래와 동일한 역할을 하는 예시를 위한 코드 
        System.out.println(Double.parseDouble(String.valueOf(Math.random())));
// ,,, 이하 생략 

// -----------------------------------------------------------------------
	
// static import 사용
import static java.lang.Math.*;
import static java.lang.System.out;
import static java.lang.Double.*;

public class ImportTest {
    public static void main(String[] args) {
				// 위와 동일한 역할을 하는 예시를 위한 코드 
				out.println(parseDouble(String.valueOf(random())));
// ,,, 이하 생략

 

 


 

클래스패스 (classpath)

 

✅ 클래스패스

(.class) 클래스를 찾기 위한 경로

JVM이 프로그램을 실행 할 때 바이트코드로 된 파일(.class)을 찾는데 경로를 의미함.

Java runtime(java or jre)으로 .class 파일에 포함된 명령어를 실행하기위해 먼저 이 파일을 찾아야한다.

 

⏺ classpath를 지정하는 방법

  • 환경변수 CLASSPATH를 사용
  • java runtime에 -classpath 옵션 사용

 

✅ CLASSPATH 환경변수

운영체제에 지정하는 변수

  • 자바 가상머신과 같은 애플리케이션들이 환경변수 값을 참고해서 동작한다.
  • 자바는 클래스 패스로 환경변수 CLASSPATH를 사용함
  • 환경변수 CLASSPATH 사용 → 실행할 때 classpath옵션을 사용하지 않아도 됨.
  • 운영체제 변경시 클래스 패스가 사라지기 때문에 이식성 면에서 불리할 수 있다.

 

⏺ classpath를 <환경변수를 통해> 지정하는 이유 (WHY)

프로젝트는 굉장히 복잡한 구조로 여러 경로가 존재하고, 많은 클래스파일을 사용하다보면

매번 컴파일 할때마다 클래스패스를 명시하는게 번거로운 일이 된다.

 

 →  이러한 이유로 운영체제 상에서 CLASSPATH 환경변수로서 설정한다.

 

 

 

Windows → 시스템설정 > 환경변수

 

 

 

IDE의 자동 클래스 패스 설정

최근엔 운영체제 상의 환경변수로 CLASSPATH를 설정하는 것을 지양, IDE나 빌드 도구를 이용해 설정한다.

 

(???그렇다고 한다 아직 확 와닿지는 않는다.????)

 

 


 

✅ classpath 옵션

 

환경변수를 통하지 않고, 컴파일 할 때 -classpath 옵션을 사용해 설정하는 방법이 있다.

 

⏺ 컴파일 할 때 option을 이용해 지정하는 이유 (WHY)

다른 클래스(Hello) 에 의존하는 클래스(app)의 파일을 컴파일 하기 위해, 컴파일 명령어와 함께 -classpath 옵션을 지정해서 Hello.class의 경로를 알려주기 위함이다.

 

⏺ classpath 옵션 사용방법

javac -classpath classpath경로 파일이름

javac -cp classpath경로 파일이름

 

💻 실습 (우분트 리눅스)

다음 그림과 같은 구조인 두개의 파일을 만들었다.

//Hello.java
public class Hello {
	public static void hello() {
		System.out.println("Hello World!");
	}
}
//App.java

public class App {
	public static void main(String[] args) {
		Hello.hello();
	}
}

 

 

 

만약 같은 폴더 내에 App.java와 Hello.java를 만들경우 Hello.class까지 자동적으로 만들어져서, classpath를 지정해줄 필요가 없다.

 

 

 

만약 같은 경로가 아니고, 다른 경로에 Hello.java가 있으면, 어떻게 될까?

 

 

 

일단 javac_classpath/HelloDir에 Hello.java를 만들고 컴파일해 Hello.class도 함께 두었다.

 

 

그리고 javac_classpath/AppDir 에 App.java를 만들었다.

결과는 직접 그린 그림으로 대체!

 

 

 

 

⏺ CLASSPATH vs -classspath

CLASSPATH 환경변수와 -classpath 옵션을 동시 진행했을 때 우선순위는 무엇이 더 높을까?

A. -classpath가 더 높게 적용 된다.

 


 

접근지시자

✅ 제어자와 접근 제어자

modifier

  • 제어자란 클래스, 멤버(필드, 메소드, 생성자 등) 선언 시 부가적인 의미를 부여하는 키워드.
  • 접근 제어자와 기타 제어자로 구분.
  • 기타 제어자는 경우에 따라 여러 개를 함께 사용 가능하지만, 접근 제어자는 여러 개를 동시에 사용 불가.

제어자 종류

접근 제어자 public, protected, default, private
기타 제어자 static, final, absteact, …

 

✅ 접근 제어자

access modifier

  • (캡슐화를 통한) 정보의 은닉화 구현을 위해 존재.
  • 클래스 외부에서의 직접적인 접근을 허용하지 않는 멤버를 설정하여 정보 은닉을 구체화
  • 자바에서는 네 가지의 접근 제어자 제공

 

접근 제어자  접근 제한 범위
public 접근 제한 없음.
protected 동일 클래스 및 패키지 + 하위(자손) 클래스
default 동일 패키지 내에서만 접근 가능
private 동일 클래스 내에서만 접근 가능.

 

제어자 
 클래스 내부  패키지 내부  다른 패키지 내부의 자식 클래스 다른 패키지의 다른 클래스
public o o o o
protected o o o x
default o o x x
private o x x x

 

⏺ Public

  • public 제어자로 선언된 클래스의 멤버는 외부로 공개됨.
  • 해당 객체를 사용하는 프로그램 어디에서나 접근이 가능.
  • 보통 private 멤버에 안전하게 접근하기 위해 public 메소드를 선언하여 선언.

package org.other;

public class A {
  public String var = "누구든지 허용"; // public 필드

  public String getVar() {          // public 메소드
    return this.var;
  }
}

// 다른 패키지
package org.App;

import org.other.A;

public class App {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        A a = new A();
        System.out.println(a.var);      // "누구든지 허용"
        System.out.println(a.getVar()); // "누구든지 허용"
    }

}

 

⏺ Protected

  • 같은 패키지와 외부 패키지 내부의 자식 클래스까지 접근 가능.

 

package org.other;

public class A {
  protected String sameVar = "다른 패키지에 속하는 자식 클래스까지 허용"; // protected 필드
}

// 다른 패키지
package org.App;

import org.other.A;

class B extends A {
    public void msg() {
        System.out.print(sameVar);
    }
}

public class App {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        A a = new A();
        // System.out.println(a.sameVar); 멤버가 보이지 않아 참조 불가
        B b = new B();
        b.msg();                       // "다른 패키지에 속하는 자식 클래스까지 허용"
    }
}

 

 

⏺ Default

  • 기본 접근 제어자.
  • 별도의 접근 제어자 삽입 불필요.
  • 같은 클래스의 멤버와 같은 패키지 내의 모든 멤버에서 접근 가능.

package org.other;

public class A {
  String sameVar = "다른 패키지에 속하는 자식 클래스까지 허용"; // default 필드
}

// 다른 패키지
package org.App;

import org.other.A;

// 다른 패키지의 자식
class B extends A {
    public void msg() {
        // System.out.print(sameVar);    멤버가 보이지 않아 참조 불가
    }
}

// 같은 패키지
class C {
    String str = "같은 패키지까지 허용";    // default 필드
}

public class App {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        A a = new A();
        // System.out.println(a.sameVar); 멤버가 보이지 않아 참조 불가
        C d = new C();
        System.out.print(d.str);       // "같은 패키지까지 허용"
    }
}

 

⏺ Private

  • 해당 클래스 멤버는 외부에 공개되지 않음. (외부에서 접근 불가.)
  • 해당 객체의 public 메소드를 통해서만 접근이 가능.
  • 클래스 내부의 세부적인 동작을 구현하는데 사용하는 멤버에 적용.

 

package org.App;

class A {
    private int data = 40;                // private 필드

    private void msg() {
        System.out.println("Hello java"); // private 필드
    }

    public void setter(int a) {           // public 메소드
        this.data = a;
        System.out.println("Hello java" + data);
    }
}

public class App {
    public static void main(String args[]) {
        A obj = new A();
        // System.out.println(obj.data); 멤버가 보이지 않아 참조 불가
        // obj.msg();                    멤버가 보이지 않아 참조 불가
        obj.setter(50);               // "Hello java50"
    }
}

 

References