패키지(package)
- 서로 관련된 클래스의 묶음(Java8 기준으로 약 4000개 클래스)
- 클래스는 클래스 파일(*. class), 패키지는 폴더. 하위 패키지는 하위 폴더
- 클래스의 실제 이름(full name)은 패키지를 포함.(java.lang.String)
- 클래스 파일을 묶어놓은 것 jar 파일.. Java9부터 rt.jar 파일은 사라지고 module개념으로 변경
- 패키지 소스파일의 첫 번째 문장으로 단 한번 선언
package com.seulgae.ch07;
- 같은 소스 파일의 클래스들은 모두 같은 패키지에 속하게 된다.
- 패키지 선언이 없으면 이름없는(unnamed) 패키지에 속하게 된다.
컴파일러로 실행할때,
C:\jdk11\work> java com.seulgae.ch07.TimeTest.java
이런 식으로 앞에 패키 지명. 클래스 파일명으로 실행하면 된다.
다음과 같이 컴파일러로 실행하려면 넓은 공간에 클래스 파일을 찾기 위해 패키지 루트를 지정해주어야 한다.
cd 명령어로 워크스페이스 패키지 경로를 찾아 디렉터리 변경 후 명령어로 실행하면 결과가 출력된다.
클래스 패스(classpath)
- 클래스 파일(*. class)의 위치를 알려주는 경로(path)
- 환경변수 classpath로 관리하며, 경로 간의 구분자는 ';'를 사용
- classpath(환경변수)에 패키지의 루트를 등록해줘야 함.
- 나중에 필요할 때 참고하는 걸로 하자.
import문
- 클래스를 사용할 때 패키지 이름을 생략할 수 있다.
- 컴파일러에게 클래스가 속한 패키지를 알려준다.
- 이클립스 단축키 : Ctrl + shift + o
- java.lang패키지의 클래스는 import하지 않고도 사용할 수 있다.
- String, Object, System, Thread...
import java.lang.*; // 모든 클래스, 생략가능
import문의 선언
- import문을 선언하는 방법은 다음과 같다.
import 패키지명.클래스명; //ctrl + shift + o 이클립스가 자동으로 import 해줌.
//또는
import 패키지명.*; // 모든 클래스
- import 문은 패키지 문과 클래스 선언의 사이에 선언한다.
package pack_For;
import java.util.Scanner;
public class ForBasic {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
1. 패키지 선언
2. import 문
3. 클래스 정의
- import문은 컴파일 시에 처리되므로 프로그램의 성능에 영향 없음.
- 다음의 두 코드는 서로 의미가 다르다.
- java 패키지의 모든 클래스(패키지는 포함 안됨.)
- 이름이 같은 클래스가 속한 두 패키지를 import 할 때는 클래스 앞에 패키 지명을 붙여줘야 한다.
import java.sql.*; //java.sql.Date
import java.util.*; //java.util.Date
static import문(꼭 필요할 때만 쓰자.)
- static멤버를 사용할 때 클래스 이름을 생략할 수 있게 해 준다.
import static java.lang.Integer.*; // Integer클래스의 모든 static메서드
import static java.lang.Math.random; // Math.random()만. 괄호 안붙임.
import static java.lang.System.out; // System.out을 out만으로 참조가능
실습 예제.
package com.seulgae.ch07;
import static java.lang.System.out;
import static java.lang.Math.*;
class StaticImportEx1 {
public static void main(String[] args) {
// System.out.println(Math.random());
out.println(random());
// System.out.println("Math.PI :"+Math.PI);
out.println("Math.PI :" + PI);
}
}
제어자(modifier) -> 형용사 + 명사
- 클래스와 클래스의 멤버(멤버 변수, 메서드)에 부가적인 의미 부여
접근 제어자 | public, protected, (default), private |
그 외 | static, final, abstract, native, transient, synchronized, volatile, strictfp |
- 하나의 대상에 여러 제어자를 같이 사용 가능(접근 제어자는 하나만)
public class ModifierTest{
public static final int WIDTH = 200;
// 관례적으로 접근제어자를 제일 왼쪽에 쓴다.
public static void main(String[] args){
Syso("WIDTH="+WiDTH);
}
}
static - 클래스의, 공통적인
제어자 | 대상 | 의미 |
static | 멤버변수 | - 모든 인스턴스에 공통적으로 사용되는 클래스의 변수가 된다. - 클래스 변수는 인스턴스를 생성하지 않고도 사용 가능하다. - 클래스가 메모리에 로드될 때 생성된다. |
메서드 | - 인스턴스를 생성하지 않고도 호출이 가능한 static 메서드가 된다. - static메서드 내에서는 인스턴스멤버들을 직접 사용할 수 없다. |
- iv 앞에 static을 붙이면 cv가 된다.
- static이 붙어있다면 인스턴스 멤버 사용 불가
왜? 인스턴스 변수는 객체를 만들고 나서 쓸 수 있기 때문이지!!
final - 마지막의, 변경될 수 없는
제어자 | 대상 | 의미 |
final | 클래스 | 변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다. 그래서 final로 지정된 클래스는 다른 클래스의 조상이 될 수 없다. |
메서드 | 변경될 수 없는 메서드, final로 지정된 메서드는 오버라이딩을 통해 재정의 될 수 없다. | |
멤버변수 | 변수 앞에 final이 붙으면, 값을 변경할 수 없는 상수가 된다. | |
지역변수 |
abstract - 추상의, 미완성의
제어자 | 대상 | 의미 |
abstract | 클래스 | 클래스 내에 추상 메서드가 선언되어 있음을 의미한다. |
메서드 | 선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알린다. |
Q. 추상 메서드란?
- {} 구현부가 없는 메서드, 몸통이 없음, 미완성 메서드, 선언 부만 있음
- 클래스도 미완성임, 아직 완성되지 않은 메서드를 갖고 있어서.
- 객체를 만들 수 없음 = 인스턴스 생성 불가
AbstractTest a = new AbstractTest(); // 에러. 추상 클래스의 인스턴스 생성불가
Q. 그럼 언제 추상 클래스를 사용할 수 있는가?
- 추상 클래스를 상속받아서 완전한 클래스(완성된 설계도, 구상 클래스)를 만든 후에 객체 생성 가능.
접근 제어자(access modifier)
private | 같은 클래스 내에서만 접근이 가능하다. |
(default) | 같은 패키지 내에서만 접근이 가능하다. |
protected | 같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근이 가능하다. |
public | 접근 제한이 전혀 없다. |
- 4개 중에서 1개 사용 가능.
제어자 | 같은 클래스 | 같은 패키지 | 자손 클래스 (다른 패키지) |
전체 |
public (접근제한없음) |
O | O | O | O |
protected (같은 패키지 + 자손) |
O | O | O | |
(default) 같은 패키지 |
O | O | ||
private 같은 클래스 |
O |
클래스에는 public, (default)
public class abcd { } // public
class abcd { } // (default)
멤버에는 public, protected, (default), private // 다 가능
public int a; // 멤버변수(인스턴스변수)
protected int b; // 멤버변수(클래스 변수)
(default) void method(){ }
private double c;
실습예제.
package com.seulgae.pkg1;
public class MyParent{ // 접근 제어자가 public
private int prv; // 같은 클래스
int dft; // 같은 패키지
protected int prt; // 같은 패키지 + 자손(다른 패키지 자손)
public int pub; // 접근제한 없음.
public void printMembers() {
System.out.println(prv); //OK
System.out.println(dft); //OK
System.out.println(prt); //OK
System.out.println(pub); //OK
}
}
class MyParentTest { // 접근 제어자가(default)
public static void main(String[] args) {
MyParent p = new MyParent();
// System.out.println(p.prv); // 에러. 접근범위가 안맞음
System.out.println(p.dft); //OK, 같은 패키지
System.out.println(p.prt); //OK
System.out.println(p.pub); //OK
}
}
package com.seulgae.pkg2;
import com.seulgae.pkg1.MyParent; //ctrl + shift + o
class MyChild extends MyParent{
public void printMembers() {
// System.out.println(prv); //에러, 패키지 벗어나서.
// System.out.println(dft); //에러, 패키지 벗어나서.
System.out.println(prt); //OK, 다른패키지 더라도 자손은 허락
System.out.println(pub); //OK
}
}
public class MyParentTest2{
public static void main(String[] args) {
MyParent p = new MyParent();
// System.out.println(p.prv); // 에러. 접근범위가 안맞음
// System.out.println(p.dft); //에러 접근범위가 안맞음
// System.out.println(p.prt); //에러 접근범위가 안맞음
System.out.println(p.pub); //OK
}
}
캡슐화와 접근 제어자
접근 제어자를 사용하는 이유?
- 외부로부터 데이터를 보호하기 위해서(캡슐화)
- 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서(정보은닉)
public class Time{
public int hour;
public int minute;
public int second;
}
- 시간 변수같은 경우 hour은 0 ~ 23, minute 0 ~ 59, second 0 ~ 59 범위 값이 정해져 있는데,
Time t = new Time();
t.hour = 25; // 멤버변수에 직접 접근
- 객체 생성 후 멤버변수에 직접 접근해서 값을 대입하게 되면 범위 외의 값이 들어가는걸 막을 수 없음.
public class Time{
private int hour; // 접근 제어자를 private로 하여
private int minute; // 외부에서 직접 접근하지 못하도록 한다.
private int second;
public int getHour() { return hour; }
public void setHour(int hour) { // 메서드를 통한 간접 접근 허용
if(hour < 0 || hour > 23) return;
this.hour = hour;
}
}
- 접근 제어자를 private로 하여 외부에서 직접 접근하지 못하도록 한다.
- 메서드는 public, 메서드를 통한 간접 접근을 허용한다.
- 데이터를 보호한다는건 t.setHour(25)로 접근했을때, 조건에 어긋나니깐 return문으로 메서드에서 빠져나가
- 범위 외의 값이 들어가는걸 막아주는걸 데이터를 보호한다고 한다.
실습 예제.
package com.seulgae.ch07;
class Time {
private int hour; // 0~23 사이의 값을 가져야함.
private int minute;
private int second;
public void setHour(int hour) {
if(isNotValidHour(hour)) return ;
this.hour = hour; // private int hour 인스턴스 변수를 가르킨다.
}
// 매개변수로 넘겨진 hour가 유효한지 확인해서 알려주는 메서드
private boolean isNotValidHour(int hour) {
return hour < 0 || hour > 23;
}
public int getHour() {return hour;}
}
public class TimeTest{
public static void main(String[] args) {
Time t = new Time();
// t.hour = -100;
t.setHour(21); // hour 값을 21로 변경
System.out.println(t.getHour());
t.setHour(100);
System.out.println(t.getHour()); //안바뀜, 100은 유효한 값이 아니니깐
}
}
- 프로그램 오류 발생 시 확인해야되는 요소를 줄이기 위해 접근제어자의 범위를 최대한 줄이는게 좋다.
'Study > Java' 카테고리의 다른 글
객체지향 프로그래밍 7장(30강 ~ 35강) (0) | 2022.06.07 |
---|---|
객체지향 프로그래밍 7장(20강 ~ 24강) (0) | 2022.06.06 |
객체지향 프로그래밍 6장(16강 ~ 19강) (0) | 2022.06.03 |
객체지향 프로그래밍 6장(11강 ~ 15강) (0) | 2022.06.03 |
객체지향 프로그래밍 6장(6강 ~ 10강) (0) | 2022.06.02 |