반응형
객체 지향 프로그래밍
- 현실에서 제품을 만드는 과정과 유사하여 제품을 만들기 위해 부품을 먼저 만들고 부품들을 조립해서 제품을 완성하는 방식
- 소프트웨에서도 부품에 해당하는 객체들을 만들어 하나의 완성된 프로그램을 만드는 기법을 객체 지향 프로그래밍(OOP)라 한다.
- 공장에서 설계도를 가지고 부품을 조립하여 제품을 출하하는 개념과 유사하다.
클래스란?
- 공장에서 부품과 제품을 만들기 위한 설계도이다.
- 실제하지 않지만 객체를 만들기 위해서 미리 정의해둔 필드와 메서드들이다.
객체란?
- 공장에서 설계로를 가지고 만든 부품과 제품이다.
- 실제하고 설계도를 기반으로 필드와 메서드들이 실제 동작한다.
객체 프로그래밍의 특징
- 캡슐화 : 객체의 필드, 메서드를 하나로 묶고, 실제 구현 내용을 감추는 것을 말한다. 외부 객체는 객체 내부의 구조를 알지 못하며 객체가 노출해서 제공하는 필드와 메서드만 이용할 수 있다.
- 상속 : 부모(조상)이 가진 재산을 자식에게 물려주는 것으로 상위 객체가 가진 필드와 메서드를 자식이 사용할 수 있고 다시 재정의할 수도 있다.
- 다형성 : 같은 타입이지만 실행 결과가 다양한 객체를 이용하는 성질을 말한다. 부모 타입에는 모든 자식 객체가 대입될 수 있고 인터페이스 타입에는 모든 구현 객체가 대입될 수 있다.
객체와 클래스
- 클래스를 설계하고 설계 된 클래스를 가지고 사용할 객체를 생성한 후 생성된 객체를 사용한다.
- 관례적으로 클래스 이름이 단일 단어라면 첫 자를 대문자로 하고 나머지는 소문자로 작성한다.
- 파일 이름과 동일한 이름의 클래스 선언에만 public 접근 제한자를 붙일 수 있고 가급적 소스 파일 하나당 동일한 이름의 파일 클래 하나를 선언하는게 좋다.
// Car.java
public class Car {
String name; // 클래스 필드 : 객체의 속성을 의미하며 데이터 저장
int speed; // 클래스 필드
int val;
public Car() { // 기본 생성자 : 생성자는 프로그래머가 만들지 않으면 컴파일러가 자동으로 하나 만들어준다.
// 객체 생성 시 초기화 역할
}
public Car(String name) { // 매개변수를 받는 생성자
this.name = name // this는 해당 객체를 의미함 : name이 같으므로 어떤 name을 의미하는지 명시
}
public Car(String name, int speed) {
this(name); // 중복 코드를 없애기 위해 name은 다른 생성자 호출 : this와 this()는 다르다.
this.speed = speed;
}
public void open() { // 메서드 : 객체의 기능을 의미하며 CRUD 조작을 함
}
public int value(int ... values) { // 매개 변수의 수를 모를 때 받는 가변인자이고 배열([])로 전달 받아진다.
for (int i = 0; i < values.length; i++) {
this.val += values[i];
}
return this.val; // 객체가 가지고 있는 val을 return 함
}
}
// Test.java
public class Test {
public static void main(String args[]) {
Car c = new Car(); // 객체 생성
c.value(1,2,3,4); // 가변인자를 가진 value 호출
c.value(1,2,3,4, 5); // 가변인자를 가진 value 호출
}
}
객체의 메서드 호출
- 객체 내부에서의 호출 : method2() -> method1()
- 객체 외부에서의 호출 : c.method2()
메서드 오버로딩
- 같은 이름을 가진 메서드의 매개 변수의 타입, 개수, 순서에 따라 호출하는 메서드가 달라짐
int plus(int x, int y) { }
int plus(double x, int y) { }
int plus(int x, int y, int z) { }
정적 멤버와 static
- 정적은 고정되어 있다는 의미로 정적 멤버는 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메서드를 말한다.
- 프로그램이 시작하고부터 종료될 때까지 공유 메모리 영역에 정적 멤버를 올려두고 어디서든 참고해서 쓸 수 있다.
- 필드의 경우 객체가 가지고 있어야 할 데이터라면 인스턴스 필드로 선언하고, 객체마다 가지고 있을 필요성이 없는 공용적인 데이터라면 정적 필드로 선언하는 것이 좋다. => PI같은 데이터
- 메서드의 경우 인스턴스 필드를 이용해서 실행해야 한다면 인스턴스 메서드로 선언하고, 인스턴스 필드를 이용하지 않는다면 정적 메서드로 선언한다. => 덧셈, 뺄셈의 기능은 정적 메서드로 선언하는게 좋다.
public class Test {
// 정적 필드
static int x = 10;
// 정적 메소드
static int plus(int x, int y) {}
int field1;
void method1() {}
static int field2;
static void method2() {}
static { // 정적 블록
field1 = 10; // 컴파일 에러
method1(); // 컴파일 에러
field2 = 10; // 같은 정적만 가능
method2(); // 같은 정적만 가능
}
static void Method3() {
this.field1 = 10; // 컴파일 에러
this.method1(); // 컴파일 에러
field2 = 10; // 같은 정적만 가능
method2(); // 같은 정적만 가능
}
public void static main(String args[]) { // main도 static이라 바로 field1에 접근할 수 없어서 객체를 생성하고 접근해야 한다.
Test t = new Test();
t.field1 = 20;
}
}
싱글톤
- 객체가 단 하나만 생성됨을 보장하는 객체를 싱글톤이라고 한다.
- 객체를 아무리 생성해도 같은 객체를 반환하여 같은 객체임을 보장한다.
public class Test {
// 정적 필드
private static Test singleton = new Test();
// 생성자
public Test() { }
// 정적 메서드
public Test getInstance() {
return singletone;
}
}
final 필드
- 최종의 마지막의 뜻으로 최종적인 필드, 메서드임을 의미하여 객체가 생성되고 한번 초기화 되면 바꿀 수 없음을 말한다.
- final 필드는 객체마다 저장되고, 생성자의 매개값을 통해서 여러 가지 값을 가질수 있기 때문에 상수가 될 수 없다.
상수(static final)
- 불변의 값을 상수라고 하며 선언과 동시에 한번 초기값이 저장되면 변경할 수 없다.
패키지
- 클래스를 체계적으로 관리하기 위해 패키지를 사용하며 파일을 넣어두는 폴더라고 생각하면 된다.
- package 상위패키지.하위패키지.클래스; 로 작성된다.
- 회사에서는 보통 도메인 이름을 패키지로 한다. => com.otrodevym.test
- 규칙
- 숫자로 시작해서는 안 되고, _, $를 제외한 특수 문자를 사용해서는 안 된다.
- java로 시작하는 패키지는 자바 표준 API에서만 사용하므로 사용해서는 안 된다.
- 모두 소문자로 작성하는 것이 관례이다.
패키지 선언이 포함된 클래스 컴파일
java의 컴파일 된 class 파일 위치를 잡는 방법이다.
- cmd 기준
- javac -d . // 현재 폴더 내에 생성
- javac -d ..\bin // 현재 폴더와 같은 위치의 bin 폴더에 생성
- javac -d C:\Temp\bin // C:\Temp\bin 폴더에 생성
접근 제한자
접근 제한 | 적용 대상 | 클래스 내부 | 동일 패키지 | 하위 클래스 | 그 외 영역 |
public | 클래스, 필드, 생성자, 메서드 | O | O | O | O |
protected | 필드, 생성자, 메서드 | O | O | O | X |
default | 클래스, 필드, 생성자, 메서드 | O | O | X | X |
private | 필드, 생성자, 메서드 | O | X | X | X |
- public : 제한 없이 접근 가능
- protected : 본인과 하위(자식) 클래스와 동일 패키지에서 접근 가능
- default : 본인과 동일 패키지에서만 접근 가능
- private : 본인만 접근 가능
Getter와 Setter 메서드
- 일반적으로 객체 지향 프로그래밍에서 객체의 외부에서 객체의 데이터를 읽고 변경할 수 있으면 객체의 무결성 결점이 깨질 수 있기 때문에 객체의 데이터는 객체 외부에서 직접적으로 접근하는 것을 막는다.
public class Car { // 필드 private int speed; private boolean stop; // 생성자 public Car() { } // getter 메서드 public int getSpeed() { return speed; } // setter 메서드 public void setSpeed(int speed) { if(speed < 0) { this.speed = 0; return ; }else { this.speed = speed; } } }
어노테이션
- 어노테이션은 메타 데이터라고 볼 수 있으며 메타데이터란 애플리케이션이 처리해야 할 데이터가 아니라, 컴파일 과정과 실행 과정에서 코드를 어떻게 컴파일하고 처리할 것인지 알려주는 정보이다.
- 어노테이션의 용도
- 컴파일러에게 코드 문법 에러를 체크하도록 정보를 제공
- 소프트웨어 개발 툴이 빌드나 배치 시 코드를 자동으로 생성할 수 있드록 정보를 제공
- 실행 시(런타임 시) 특정 기능을 실행하도록 정보를 제공
- 빌드 시 자동으로 XML 설정 파일을 생성하거나, 배포를 위해 JAR 압축 파일을 생성하는데에도 사용된다.
- 인터페이스를 정의하는 방법과 유사하다.
public @interface AnnotationName {
String elementName1();
int elementName2() default 5;
@AnnotationName(elementName1 = "값", elementName2 = 10)
class Test {
}
}
어노테이션 적용 대상(@Target)
- 적용될 대상을 지정 할 때 @Targe을 사용한다.
- @Target의 기본 엘리먼트인 value는 ElementType 배열을 값으로 가지며 복수로 지정할 수 있다.
@Target({ElementType.TYPE, ElementType.FIELD})
public @interface AnnotationName{}
ElementType열거 상수 | 적용 대상 |
TYPE | 클래스, 인터페이스, 열거 타입 |
ANNOTATION_TYPE | 어노테이션 |
FIELD | 필드 |
CONSTRUCTOR | 생성자 |
METHOD | 메서드 |
LOCAL_VARIABLE | 로컬 변수 |
PACKAGE | 패키지 |
어노테이션 유지 정책(@Retention)
- 사용 용도에 따라 어느 범위까지 유지할 것인지를 지정해야 한다,
- 소스상에서만 유지할 건지, 컴파일된 클래스까지 유지할 건지, 런타임 시에도 유지할 건지를 지정해야 한다.
- 리플렉션이란 런타임 시에 클래스의 메타 정보를 얻는 기능을 말한다.
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationName{}
RetentionPolicy 열거 상수 | 설명 |
SOURCE | 소스상에서만 어노테이션 정보를 유지한다. 소스 코드를 분석할 때만 의미가 있으며, 바이트 코드 파일에는 정보가 남지 않는다. |
CLASS | 바이트 코드 파일까지 어노테이션 정보를 유지한다. 하지만 리플렉션을 이용해서 어노테이션 정보를 얻을 수는 없다. |
RENTIME | 바이트 코드 파일까지 어노테이션 정보를 유지하면서 리플렉션을 이용해서 런타임 시에 어노테이션 정보를 얻을 수 있다. |
런타임 시 어노테이션 정보 사용하기
- 클래스에 적용된 어노테이션 정보를 얻으려면 java.lang.Class를 이용하면 되지만, 필드, 생성자, 메서드에 적용된 어노테이션 정보를 얻으려면 java.lang.reflect 패키지의 Field, Constructor, Method 타입의 배열을 얻어야 한다.
리턴 타입 | 메소드명(매개변수) | 설명 |
Field[] | getFields() | 필드 정보를 Field배열로 리턴 |
Constructor[] | getConstructors() | 생성자 정보를 Constructor 배열로 리턴 |
Method[] | getDeclaredMethods() | 메서드 정보를 Method 배열로 리턴 |
Class, Field, Constructor, Method를 얻으면 아래 메서드로 어노테이션 정보를 얻을 수 있다.
리턴 타입 | 매소드명(매개변수) |
boolean | isAnnotationPresent(Class<? extedns Annotation> annotationClass) |
지정한 어노테이션이 적용되었는지 여부. Class에서 호출했을 때 상위 클래스에 적용된 경우에도 true를 리턴한다. | |
Annotation | getAnnotation(Class<T> annotationClass) |
지정한 어노테이션이 적용되어 있으면 어노테이션을 리턴하고 그렇지 않으면 null을 리턴한다. Class에서 호출했을 때 상위 클래스에 적용된 경우에도 어노테이션을 리턴한다. |
|
Annotation[] | getAnnotations() |
적용된 모든 어노테이션을 리턴한다. CLass에서 호출했을 때 상위 클래스에 적용된 어노테이션도 모두 포함한다. 적용된 어노테이션이 없을 경우 길이가 0인 배열을 리턴한다. | |
Annotation[] | getDeclaredAnnotations() |
직접 적용된 모든 어노테이션을 리턴한다. Class에서 호출했을 때 상위 클래스에 적용된 어노테이션은 포함되지 않는다. |
어노테이션 실습
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface PrintAnnotation {
String value() default "-";
int number() default 15;
}
- PrintAnnotation.java
import java.lang.reflect.Method;
public class Service {
@PrintAnnotation
public void method1() {
System.out.println("실행 내용1");
}
@PrintAnnotation
public void method2() {
System.out.println("실행 내용2");
}
@PrintAnnotation
public void methdo3() {
System.out.println("실행 내용3");
}
public static void main(String[] args) {
Service s = new Service();
s.method1();
System.out.println("=======================");
Method[] declareMethods = Service.class.getDeclaredMethods();
for (Method method : declareMethods) {
// PrintAnnotation이 적용되었는지 확인
if (method.isAnnotationPresent(PrintAnnotation.class)) {
// PrintAnnotation 객체 얻기
PrintAnnotation printAnnotation = method.getAnnotation(PrintAnnotation.class);
// 메소드 이름 출력
System.out.println("[" + method.getName() + "] ");
// 구분선 출력
for (int i = 0; i < printAnnotation.number(); i++) {
System.out.print(printAnnotation.value());
}
System.out.println();
try {
// 메소드 호출
method.invoke(new Service());
} catch (Exception e) {
}
System.out.println();
}
}
}
}
- Service.java
반응형
'개발(합니다) > Java&Spring' 카테고리의 다른 글
[java-기초-08] 인터페이스 (0) | 2021.01.06 |
---|---|
[java-기초-07] 상속 (0) | 2021.01.05 |
[java-기초-05] 참조 타입 (0) | 2021.01.03 |
[java-기초-04] 조건문과 반복문 (2) | 2021.01.02 |
[java-기초-03] 연산자 (0) | 2021.01.01 |