본문 바로가기
java

[Java] 클래스 - 객체지향, static, instance, 접근제어자, 싱글턴 등

by jinbro 2017. 9. 19.

[객체지향과 클래스] : 조금 더 자세한 내용(http://jinbroing.tistory.com/207)
(1) 객체
- 어떠한 기능을 만들기위해 필요한 존재
- 각각의 존재가 구분되고 고유의 상태와 행동을 가짐 : 독립적인 존재, 공용 인터페이스로만 요청이 가능
=> 접근제어자 사용 : private, protected, public

- 본질은 타 객체와 협력하는 존재(협력 요청 방법) : 객체.요청인터페이스() - 요청에 응해서 결과값을 줄 것인지는 응답 객체에 달림(캡슐화)
- 타 객체가 협력 요청을 할 수 있도록 요청 인터페이스를 가지고 있음


(2) 객체지향 프로그래밍(OOP) : 객체들의 협력 관점에서 프로그래밍 하는 것 
- 사용 : A 객체가 B 객체를 사용함, 사람과 자동차
- 집합 : 완성품과 부품, 자동차와 엔진, 타이어, 핸들
- 상속 : super 타입과 sub 타입을 의미함, 기계와 자동차
=> 같은 super 타입을 상속하지만 각각 다르게 행동하도록 설정할 수 있음(다형성)
=> Animal을 상속하는 Giraffe(기린, 초식), Lion(사자, 육식) 같은 feed를 상속받지만 오버라이딩해서 전혀 다른 메서드로 사용
=> 자바에서는 void feed(Animal animal)해두고 Animal을 구현하는 객체타입이 모두 대입될 수 있도록 함 


(3) 객체의 타입화
- 같은 특징을 가진 객체들을 종류화 시킨 것 
- 예시 : 버스, 택시, 자가용(객체) -> 교통수단(타입) - 실제 구현될 때에는 각각의 상태값과 각각 세부 행동이 다름


(4) 클래스
- 객체지향으로 프로그래밍할 때 사용하는 것
- 객체 설계도면 : 어떤 메서드와 필드를 가지는가
- 새로운 세상 만들기 : 필요한 객체 파악 - 객체 간의 관계 - 메세지 설계(공용인터페이스) - 객체 타입화 - 객체 구현(필드와 메서드) - 클래스로 표현
- 결론은 설계부터하고 설계의 결과를 인터페이스, 클래스에 나타냄
- 클래스(class) 하나당 .class 파일이 1개 생김 : 두개를 선언하면 2개의 파일이 생김(그냥 .java 파일 하나당 1개만)


[클래스 살펴보기 - 객체 설계를 다했다는 전제하에]
(1) new : 인스턴스 생성 - heap 영역에 생성, 객체 주소를 리턴 - 클래스 변수가 참조(제거안됨)
(2) 필드, 생성자, 메서드
- 필드 : 객체의 상태를 나타냄, primitive / reference type이 올 수 있음 - 자동차라 했을 때 부품인 핸들 객체가 상태로 지정됨
=> 초기값이 생략되고 선언된 필드는 임의 기본값을 가짐 : 정수(0), 실수(0.0), 논리(false), 참조(null)

- 생성자 : 객체 타입의 인스턴스가 생성될 때 실행됨(new 할 때 1회)
=> 데이터(매개변수)를 받는 생성자가 실행될 때 예외처리를 해주자 : 혹은 기본 생성자()로 넘겨주자
=> 생성자가 생략되어있으면 컴파일러에서 자동추가함 : 하나라도 생성자가 있을 때 기본 생성자 추가X

- 메서드 : 객체의 구체적인 행동 방법, 타 객체에서 관여할 수 없음, 필드에 따라 행동방법이 달라지거나 행동에 따라 필드가 변경될 수 있음 
=> 객체 간 데이터 전달 역할
=> 메서드 시그니쳐 : 선언부 부분을 말함
=> 매개변수의 수를 정확히 알지 못할 때 
1) 배열을 매개변수로 설정
2) 타입 … values 로 설정 : 1번과 같음, 표현만 다름

=> 오버로딩 가능 : 같은 이름이지만 매개변수를 달리해서 다양한 요청 처리가능하도록 함
1) JVM은 매개값의 타입을 보고 메서드를 선택함 : 타입과 순서가 같아버리면 같은 메서드로 취급(물론 컴파일 자체가 안됨), 리턴타입이 달라도 안됨
2) 1번째 단계를 거치고 일치하는 것이 없을 때 자동형변환이 가능한지 테스트 함 : 가능하다면 그 메서드로 감

=> 리턴과 리턴타입 
1) 즉시 메서드 종료
2) 리턴타입보다 리턴 데이터를 저장하는 변수 데이터타입이 메모리 공간이 클 경우 : 자동형변환
3) 2번과 반대 : 캐스트 연산자로 강제형변환을 해줘야함

- 쉽게 설계하기 : 협력부터 설계하고 협력에 필요한 메세지 설계 - 메서드와 필드를 설계하는 것이 쉬움


(3) this
- 인스턴스 자기 자신을 가리킴, 인스턴스 멤버 접근
- this.필드 or this.메서드로 접근 : 내부에서 접근
- this(매개변수1, 매개변수2) : 생성자에서 다른 생성자 호출, 여러개일 경우 중복코드 생성될 수 있음 그래서 하나로 모으는걸로, 첫 줄에 위치해야함 


(4) static
- 정적 멤버 : static으로 선언된 필드나 메서드
- 객체마다 가질 필요없고 객체 타입의 인스턴스가 공통적으로 가지고 있을 필드나 메서드를 static으로 선언
- 클래스에 고정된 멤버 : 클래스 로더가 클래스(.class, 바이트코드)를 로딩해서 메서드 메모리 영역에 적재할 때 클래스 별로 관리
=> 메모리에 로딩되면 바로 사용 가능 : 인스턴스 생성없이
=> 클래스명.멤버명
=> static 에서  this나 this 멤버필드 선언x : 인스턴스 생성전…. 인스턴스 생성하면 사용됨
=> 보통 선언과 동시에 초기화
=> static { /* …. */ } 초기화 블럭 사용할 수도 있음 : 로딩될 때 자동 실행, static 멤버 초기화를 하기위한 블럭


(5) 객체.메서드()
- 객체에서 다른 객체에 요청을 할 때 사용 : 공용인터페이스라고 보면 됨, 필드와 메서드 내부 임의 조작X

(6) final 
-  불변의 데이터를 선언할 때 사용하는 키워드
- 선언 시 초기화해주거나 생성자에서 초기화해줘야함 : 객체 생성할 때
- final만 사용하면 객체마다

(7) static final
- 6번과 같지만 static 멤버로 객체가 생성되기 전에도 됨
- 상수


[패키지 : 코드 관리]
1) 유일한 클래스로 만들어줌 : 상위패키지.하위패키지.클래스 - com.jinbro.프로젝트명.dao.JDBCUtil.java
2) 목적마다 분류해서 관리 
3) 컴파일 과정에서 패키지 폴더가 따로 생김 
4) java로 시작하는 패키지명은 자바 표준 API의 패키지
5) import로 다른 패키지의 클래스를 가져올 수 있음 
- com.jinbro.exam01.* : exam01 내의 클래스 모두 import(하위 패키지는 아님, import를 하나 더 해야함)
- 보통은 클래스명 쓰고 자동완성하면 자동 import 사용


[접근제어자 : 객체 외부와 내부 분리]
(1) 완전 공개, 약간 공개, 비공개로 나눌 수 있음 : this를 기준으로함
(2) public : 완전 공개
(3) protected : 같은 패키지, sub 타입 공개(약간 공개)
(4) private : 비공개, this만 사용가능
(5) default : 다른 패키지에 소속된 클래스에서 접근 불가

- 클래스에 적용 가능한 제어자 : public / default
- 컴파일러가 추가하는 생성자의 접근제어자는 클래스 접근제어자를 따름
- 기본접근제어자 없으면 default
- getter, setter(public)로 필드를 변경하게 함 : 로직


[싱글톤 : 객체 타입 패턴]
- 단 1개의 인스턴스만을 생성하는 타입 : 1개의 인스턴스만으로 관리
- 외부에서 인스턴스 생성할 수 없도록 생성자 private 설정 : 생성자 호출한만큼 객체 생성
- 같은 인스턴스를 가리키게 됨 
public class Singleton {

private static Singleton obj = new Singleton();

private Singleton(){

}

public static Singleton getInstance(){
return Singleton.obj;
}

}


[실습코드]

package com.jinbro.source;

/* *는 하위패키지를 포함하지않음 */
import com.jinbro.test.*;
import com.jinbro.test.packtest.*;

public class Car {


/* static field */
public static final int YEAR;
static {
YEAR = 100;
}

/* instance field */
private int speed = 10;
private String color = "black";
final String name;

public Car(){
this(0, "");
}

/* method overloading */
public Car(int speed){
this(speed, "");
}

public Car(int speed, String color){
if(speed > 10){
this.speed = speed;
}

if(!color.equals("")){
this.color = color;
}

this.name = "jinbro";
}

@Override
public String toString() {
return "com.jinbro.source.Car{" + "speed=" + speed + ", color='" + color + '\'' +'}';
}

public void getCarList(String[] list){
for(int i=0; i<list.length; i++){
System.out.println(list[i]);
}
}

/* 위와 같은 메서드이기때문에 중복 에러가 발생 : 컴파일x
public void getCarList(String...list){
for(int i=0; i<list.length; i++){
System.out.println(list[i]);
}
} */

public void getCarList(int[] list){
for(int i=0; i<list.length; i++){
System.out.println(list[i]);
}
}

/* com.jinbro.source.Main 클래스에서 사용 - 흐름 제어(메인쓰레드), 실행 클래스에서 제어함 - 나머지 API import */
public static void main(String[] args) {
Car car = new Car();
System.out.println(car.toString());
car.getCarList(new String[]{"차1", "차2", "차3"});
car.getCarList(new int[]{1, 2, 3});


/* public access */
Test t1 = new Test();
System.out.println(t1.toString());


/* Sigleton */
Sigleton s1 = Sigleton.getInstance();
Sigleton s2 = Sigleton.getInstance();

if(s1 != null || s1==s2){
System.out.println("두 변수는 같은 객체를 참조하고 있습니다");
}
}
}

/* 컴파일 에러 - .java와 같은 이름의 class만 public으로 선언
public class Person {

} */

/* default */
class Person{
}


댓글