오늘은 JAVA에서 클래스, 인스턴스 변수들을 안전하게 사용하기 위한 접근 제어를 공부했다.
정보은닉이란?
-> 외부에서 인스턴스의 변수에 직접적인 접근을 막는 것이다.
방법은 변수 앞에 private을 선언하는 것이다. 그렇게 되면 그 변수는 그 인스턴스 안의 메소드를 이용해서만 접근 할 수 있다.
* 프로그램의 안전성을 높이기 위해 인스턴스 변수는 가급적 private으로 선언하자.
이러한 정보은닉은 접근제어 지시자를 통해 이루어진다.
접근제어 지시자는 private, public, protected, default 가 있다.
private는 위에서 말한 것처럼 외부에서 건들지 못하게 하는 것이고
public은 아무데서나 사용할 수 있도록 한다. 그래서 메소드에는 public을 많이 쓴다.
default는 변수 앞에 아무것도 적지 않았을 때인데 동일 패키지 내에서의 접근까지 허용한다.
protected 개념은 상속 개념을 이해해야하는데,
상속받은 클래스안의 변수를 이어받을 수 있다. private으로 선언된 변수가 있는 클래스를 상속 받았다면 그 속에 있는 그 변수는 사용하지 못하는 것이다. 하지만 protected로 선언된 변수는 상속 받고 난 후도 사용할 수 있다. 물론 외부에서 접근은 허용하지 않는다.
그렇다면 class에는 public? default? private? 어떤걸 사용할까??
상식적으로 private를 사용해 class를 선언한다면 왜 선언하는 걸까? 외부에서 접근을 못하므로 외부에서 인스턴스 생성을 허용하지 않는다. 사용하지 못하는 class가 될 뿐이다. 즉 class에서 private는 사용하지 않는다.
public으로 선언하면 어디서든 인스턴스 생성이 가능하다. 하지만 조건이 있다.
1. 하나의 소스파일에는 하나의 클래스만 public으로 선언해야한다.
2. public 클래스의 이름과 소스파일의 이름은 완전히 일치해야 한다.
-> 보통 외부로 노출시키고 싶은 class에 public을 붙인다.(라이브러리생성시)
캡슐화
-> class로 감싸는 것을 의미한다. 이 캡슐화는 정답이란 것이 없고 필요한 상황에 맞게 class 안에 필요한 메소드나 변수들을 구성하는 것이다.
문제 9-2
원을 의미하는 클래스를 정의하고 Circle 클래스 좌표 정보와 반지름길이 정보를 저장할 수 있게 한다. Ring 클래스도 정의한다. Ring 클래스는 내부원 외부원으로 구성된다.
public static void main(String[] args)
{
Ring ring=new Ring(1, 1, 4, 2, 2, 9);
ring.showRingInfo();
}
위 main 메소드를 이용해 링의 정보를 출력한다.
먼저 각 클래스 Circle, 클래스 Ring을 설계하고 위 main 메소드에 맞추어 설계하였다.
작성한 코드는 아래와 같다.
---------------------------------------------------------------------------------------------
class Point
{
int xPos, yPos;
public Point(int x, int y)
{
xPos = x;
yPos = y;
}
public void showPointInfo() { System.out.println("["+xPos+", "+yPos+"]");}
}
class Circle
{
Point posit;
int r;
public Circle(int xi, int yi, int ri)
{
posit = new Point(xi, yi);
r = ri;
}
public void showCircleInfo()
{
System.out.println("radius : " + r);
posit.showPointInfo();
}
}
class Ring
{
Circle inner;
Circle outter;
public Ring(int x1, int y1, int r1, int x2, int y2, int r2)
{
inner = new Circle(x1, y1, r1);
outter = new Circle(x2, y2, r2);
}
public void showRingInfo()
{
System.out.println("Inner Circle Info...");
inner.showCircleInfo();
System.out.println("Outter Circle Info...");
outter.showCircleInfo();
}
}
class Problem92
{
public static void main(String[] args)
{
Ring ring = new Ring(1, 1, 4, 2, 2, 9);
ring.showRingInfo();
}
}
---------------------------------------------------------------------------------------------
위 코드의 결과로
(결과 화면)
아래와 같이 나왔다.
외부 원과 내부 원의 정보를 화면에 출력하였다.
클래스 변수, 클래스 메소드
static 선언이란?
-> static으로 선언된 변수는 변수가 선언된 클래스의 모든 인스턴스가 공유하는 변수다.
즉, static은 딱 하나만 존재하는 변수다.
모두 여기에 접근을 해서 사용하는 것이다.
그렇다면 접근 방법은 어떻게 할까??
방법은 3가지가 있다.
1. 내부에서 접근 : 다른 변수와 똑같이 다룬다.
2. 참조변수를 통한 접근 : 참조변수.변수
3. 클래스 이름을 통한 접근 : 클래스이름.변수
static 변수는 언제 초기화 될까?
-> static변수는 인스턴스를 생성하기도 전에 이미 메모리에 올라가 있다. 자바 가상머신에 올라가면서 static 변수는 초기화된다.
* static변수가 초기화되는 시점은 JVM에 의해서 클래스가 메모리 공간에 올라가는 순간이다.
* “그래서 static변수를 생성자를 통해서 초기화하는 실수를 범하면 안된다."
static을 메소드에 적용하게 되면??
인스턴스를 생성하지 않아도 static 메소드를 호출 할 수 있다.
static은 클래스가 메모리에 올라가는 순간 시작 되므로
인스턴스를 생성하지 않아도 바로 쓸수 있다.
보통 쓴다면 외부에서 쓰기 때문에
public과 같이 쓴다.
메소드 오버로딩은 무엇일가?
메소드 오버로딩이란
class Example
{
void isItOk(int n) {};
void isItOk(int n, int m) {};
void isItOk(int n, double m) {};
}
위와 같이 메소드 이름이 같게 사용하는 것이다.
결론은 메소드 이름이 같아도 괜찮다.
다만, 메소드 이름이 같더라도 매개변수는 달라야한다.
매개변수가 다르다면
메소드 오버로딩으로 이름이 같아도 괜찮다.
(*생성자도 오버로딩이 가능하다.)
오버로딩의 중요성은 여기에 있다.
생성자도 오버로딩이 가능하다는 것이다.
그렇게 되면 이
생성자의 오버로딩으로 선언된 하나의 클래스로 다양한 형태의 인스턴스 생성이 가능하다.
생성된 오버로딩의 중복되는 내용은 this 라는 키워드를 사용해 해결한다.
(이와 관련된 예시는 단계별 프로젝트에서 진행하였다.)
String 클래스
-> 문자열 클래스다.
다만 C언어와 다른점은 String 클래스의 문자열은 바꿀수 없다..
또 같은 문자열이라면 기존에 있던 문자열을 같이 사용한다.
다시말하면 문자열은 상수형이다 처음 입력되는 값이 유지된다고 생각하면 된다.
* "문자열이 동일한 경우에는 하나의 String 인스턴스만 생성해서 공유하도록 한다"
문자열을 조금 유연하게 다루고 싶다면
StringBuilder 혹은 StringBuffer 클래스를 이용하는 것이 좋다.
문자열을 복사하는 법 (자바에서)
String str1 = "Testing";
String str2 = new String(str1);
인스턴스를 새로 생성하여 만들면 된다.
(하지만 자바에서는 문자열을 직접 복사할 필요를 못 느낄만큼 다른 것들을 많이 지원해 주고 있다.)
(문자열에 관한 예시도 다음 단계별 프로젝트에서 같이 진행하겠다.)
(* 참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)