-클래스 및 클래스의 구성 멤버에 대한 접근을 제한하는 역할
1)다른 패키지에서 클래스를 사용하지 못하도록 (클래스 제한)
2)클래스로부터 객체를 생성하지 못하도록 (생성자 제한)
3)특정 필드와 메소드를 숨김 처리 (필드와 메소드 제한)
-public
다른 개발자가 사용할 수 있도록 라이브러리 클래스로 만들 때 유용
-default
1)클래스 선언할 때 public 생략한 경우
2)다른 패키지에서는 사용 불가
생성자가 가지는 접근 제한에 따라 호출 여부 결정
클래스 내부, 패키지 내, 패키지 상호간에 사용할 지 고려해 선언
-읽기 전용 필드가 있을 수 있음 (Getter의 필요성)
-외부에서 엉뚱한 값으로 변경할 수 없도록 (Setter의 필요성)
-private 필드의 값을 리턴 하는 역할 - 필요할 경우 필드 값 가공
-getFieldName() 또는 isFieldName() 메소드
1)필드 타입이 boolean 일 경우 isFieldName()
-외부에서 주어진 값을 필드 값으로 수정
1)필요할 경우 외부의 값을 유효성 검사
-setFieldName(타입 변수) 메소드
1)매개 변수 타입은 필드의 타입과 동일
데이터를 설명하는 데이터 = 메타데이터
-프로그램에게 추가적인 정보를 제공해주는 메타데이터(metadata)
-어노테이션 용도
1)컴파일러에게 코드 작성 문법 에러 체크하도록 정보 제공
2)소프트웨어 개발 툴이 빌드나 배치 시 코드를 자동 생성하게 정보 제공
3)실행 시(런타임시) 특정 기능 실행하도록 정보 제공
-어노테이션 타입 정의
1)소스 파일 생성: AnnotatoinName.java
2)소스 파일 내용 --> public @interface AnnotationName{}
-어노테이션 타입 적용 @override
@AnnotationName ---> ex public void toString(){...}
-어노테이션 적용할 때 엘리먼트 이름 생략 가능
-두 개 이상의 속성을 기술할 때에는 value=값 형태로 기술
-코드 상에서 어노테이션을 적용할 수 있는 대상
-java.lang.annotation.ElementType 열거 상수로 정의
(@Target 을 보아라!)
-어노테이션 적용 코드가 유지되는 시점을 지정하는 것
-java.lang.annotation.RetentionPolicy 열거 상수로 정의
1) SOURCE 소스상에서만 정보유지, 바이트코드에는 남지 않는다.
2) CLASS 바이트코드까지 정보를 유지한다. 리플렉션이용해서 얻지는 못한다.
3) RUNTIME 바이트코드도 유지 리플렉션을 통해 정보도 얻을 수 있다.
-리플렉션(Reflection): 런타임에 클래스의 메타 정보를 얻는 기능
1)클래스가 가지고 있는 필드, 생성자, 메소드, 어노테이션의 정보를 얻을 수 있음
2)런타임 시 어노테이션 정보를 얻으려면 유지 정책을 RUNTIME으로 설정
--------------------------------------기본적인 어노테이션 생성--------------------------
package annotationex;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) //에너테이션 정보를 언제까지 유지할지
@Target({ // <<에너테이션을 어디다가 지정해야하는지 제한해주는 에너테이션
ElementType.TYPE,
ElementType.FIELD,
ElementType.CONSTRUCTOR,
ElementType.METHOD,
ElementType.PARAMETER,
ElementType.LOCAL_VARIABLE,
ElementType.PACKAGE,
// ElementType.TYPE_USE, //메소드와 패키지를 제외한 타입과 관련된 부분만 모두 넣을 수있게 해줌
// 타입이 없는 패키지와 메소드는 안됌! 타입있는 메소드는 가능
})
@MyAnnotation //스스로 생성됌.
public @interface MyAnnotation {
// String value() ; // 이름이 value인 Default element
String value() default "3" ;
int age() default 23;
String name() default "koo"; // <- 어노테이션 속성
} // end annotation
(1) 타입명.class 속성이용:
ex) Class clazz = String.class;
(2) 참조타입변수명.getClass() 메소드 이용:
ex) String name="Yoseph";
Class clazz = name.getClass();
(3) Class.forName(FQCN) 메소드 이용:
ex) Class clazz = Class.forName("java.lang.String");
-클래스에 적용된 어노테이션 정보 얻기
클래스.class 의 어노테이션 정보를 얻는 메소드 이용
-필드, 생성자, 메소드에 적용된 어노테이션 정보 얻기
다음 메소드 이용해 java.lang.reflect 패키지의 Field, Constructor, Method 클래스의 배열 얻어냄
-Field, Constructor, Method가 가진 다음 메소드 호출
(is 구글링ㅋ)
1) isAnnotationPresent( Class<? extends Anotation> annotationClass )
: 지정한 어노테이션이 적용되었는지 여부를 boolean타입으로 리턴합니다. Class에서 호출했을 때 상위 클래스에 적용된 경우도 true를 리턴합니다.
2)getAnnotation( Class annotationClass )
: 지정한 어노테이션이 적용되어 있으면 해당 어노테이션을 리턴하고 없을 시 null을 리턴합니다. 마찬가지로 상위 클래스에 적용되어도 같습니다.
3)getAnnotations()
: 적용된 모든 어노테이션을 Annotation[] 배열로 받습니다. 상위클래스도 포함합니다.
4)getDelaredAnnotations()
: 상위 클래스를 제외한 직접 적용된 어노테이션 배열을 리턴합니다.
-------------------------------------에너테이션 정보사용-----------------------------------------
package annotationex;
import java.lang.reflect.Method;
public class PrintAnnotationExample {
//Java Reflection API를 이용한 어노테이션 처리 -->시작은 Clazz객체(바이트코드 들고 있어서)얻는데 시작
public static void main(String[] args) {
//1. Service 클래스로부터 메소드 정보를 얻음
Method[] declaredMethods = Service.class.getDeclaredMethods();
//2. Method 객체를 하나씩 처리
for(Method method : declaredMethods) {
// 3. PrintAnnotation이 적용되어있는지 확인
if(method.isAnnotationPresent(PrintAnnotation.class)) {
// 3-1. PrintAnnotation 객체 얻기
PrintAnnotation printAnnotation = method.getAnnotation(PrintAnnotation.class);
// 3-2. 메소드 이름 출력
System.out.println("["+method.getName()+"]");
//3-3. 구분선 출력
for(int i=0; i<printAnnotation.number(); i++) {
System.out.println(printAnnotation.value());
}//for
System.out.println();
try {
// 3-4 메도스 호출
method.invoke(new Service());
} catch (Exception e) {}
System.out.println();
} //if
}//for
}// main
}// end class
-------------------------------------에너테이션본문-----------------------------------------
package annotationex;
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;
} // end annotation
-자식(하위, 파생) 클래스가 부모(상위) 클래스의 멤버를 물려받는 것
-자식이 부모를 선택해 물려받음
-상속 대상: 부모의 필드와 메소드
-상속의 효과
1)부모 클래스 재사용해 자식 클래스 빨리 개발 가능
2)반복된 코드 중복 줄임
3)유지 보수 편리성 제공
4)객체 다형성 구현 가능 ★★★★★
-상속 대상 제한
1)부모 클래스의 private 접근 갖는 필드와 메소드 제외
2)부모 클래스가 다른 패키지에 있을 경우, default 접근 갖는 필드와 메소드도 제외
-상속 키워드 =extends 키워드
(1)자식 클래스가 상속할 부모 클래스를 지정하는 키워드
(2)자바는 단일 상속 - 부모 클래스 나열 불가
자식 객체 생성할 때는 부모 객체부터 생성 후 자식 객체 생성
부모 생성자 호출 완료 후 자식 생성자 호출 완료
(부모 없는 자식 없다고 함)
-부모 객체 생성할 때, 부모 생성자 선택해 호출
-super(매개값,…) =매개값과 동일한 타입, 개수, 순서 맞는 부모 생성자 호출
-부모 생성자 없다면 컴파일 오류 발생
-반드시 자식 생성자의 첫 줄에 위치
-부모 클래스에 기본(매개변수 없는) 생성자가 없다면 필수 작성
----------------------------부모생성자 클래스 호출------------------------------------
public class DmbCellPhone extends CellPhone {
int channel;
DmbCellPhone(String model, String color, int channel){
super(); //만일, 부모클래스의 생성자가 매개변수가 있으면
// 개발자 명시적으로 부모 생성자를 가장 첫 행에서 호출해줘야한다.
System.out.println("DmbCellPhone::constructor invoked.");
// System.out.println("- super"+ super);
this.model =model;
this.color = color;
this.channel = channel;
}
}
-부모 클래스의 상속 메소드 수정해 자식 클래스에서 재정의하는 것
-메소드 재정의(오바라이딩) 조건
1)부모 클래스의 메소드와 동일한 시그니처 가져야
2)접근 제한을 더 강하게 오버라이딩 불가
3)새로운 예외(Exception) throws 불가
-재정의로 인해 부모 메소드는 숨겨지는 효과 발생
1)자식의 재정의된 메서드가 수행된다.
2)사용하고자 하면 super.메소드이름을 통해서 사용
-@Override 어노테이션
1)컴파일러에게 부모 클래스의 메소드 선언부와 동일한지 검사 지시
2)정확한 메소드 재정의 위해 붙여주면 OK
------------------------------------부모 메소드 재정의 및 사용 ----------------------
package inherit;
public class Computer extends Calculator {
// 다형성 -2 : 상속으로 물려받은 메소드를 재정의하면 상속메소드 호출시, 무조건! 재정의된 메소드호출된다.
@Override
double areaCircle(double r) {
System.out.println("Calculator :: areaCircle() invoked.");
return Math.PI * r * r ;
}// areaCircle
}
---------------------------------------자식 클래스---------------------------
package inherit;
public class ComputerEx {
//다형성 -2 확인
public static void main(String[] args) {
int r = 10;
Calculator calculator =new Calculator();
System.out.println("원면적 : " + calculator.areaCircle(r));
System.out.println();
// ---
Computer computer = new Computer();
System.out.println("원면적 : " + computer.areaCircle(r));
}//main
}// end class
---------------------------------------부모 클래스---------------------------
package inherit;
//POJO: Plain Old Java Object : 진부하고 늙은 자바 클래스
public class Calculator { // POJO : 상속관계가 없는 단순 자바 클래스
double areaCircle(double r) {
System.out.println("Calculator :: areaCircle(r)");
return 3.141592 * r * r ;
}// areaCircle
}
-final 키워드의 용도
1)final 필드: 수정 불가 필드
2)final 클래스: 부모로 사용 불가한 클래스(자식생성불가/정관수술)
3)final 메소드: 자식이 재정의할 수 없는 메소드(그냥 고대로 써야함)
-------------------------부모 클래스 final 메소드 선언 -------------------------------------
package inherit.finalex;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class Car {
// 상태 필드
public int speed;
//1. 메소드
public void speedUp() {
speed +=1;
}// speedUp
//2. final 메소드 - 자식클래스에서 메소드 재정의 불허
public final void stop() {
System.out.println("Car :: stop() invoked");
speed = 0;
}//stop
}
-------------------------자식 클래스 final 메소드 재정의 불가 -------------------------------------
package inherit.finalex;
public class SportsCar extends Car {
@Override
public void speedUp() {
speed += 10;
} //speedUp
// final 메소드로 오버라이딩 불가
// public final void stop() {
// System.out.println("스포츠카 멈추기");
// speed = 0;
// }
}// end class
------------------------- final 클래스 생성-------------------------------------
package inherit.finalex;
public final class Member {
;;
} //class end
------------------------- final 클래스 사용 불가-------------------------------------
package inherit.finalex;
public class VeryVeryImportantPerson /* extends Member */ {
} //class end
-상속과 관련된 접근 제한자
1)같은 패키지: default와 동일
2)다른 패키지: 자식 클래스만 접근 허용
---------------------------------------생성자 protected 부모 클래스 생성 ------------------
package inherit.pakege1;
public class A {
protected String field;
protected A() { // 의미를 오해 말아야한다. 즉 new 생성자가 아니다!!!!!
;;
}// default constructor
protected void method( ) {}
}
----------------------------------- 같은 패키지에서 접근 ------------------------------------
package inherit.pakege1;
public class B {
public void method() {
A a = new A();
a.field = "value";
a.method();
}// method
}//end class
----------------------------------- 다른 패키지에서 접근 ------------------------------------
package inherit.pakage2;
import inherit.pakege1.A;
public class C { // C는 A 의 default 접근제한으로 막힘
public void method() {
// A a = new A();
//
// a.field = "value";
//
// a.method();
}// method
}
----------------------------------- 다른 패키지에서 자손이 접근 ------------------------------------
package inherit.pakage2;
import inherit.pakege1.A;
public class D extends A{ // 자식이어서 protected 사용 가능
public D() {
super(); // protected의 접근제어자를 가진 생성자는 생성자만 super()로만 참조 할 수 있게 해준다.
// A a = new A(); << protected의 접근제어자를 가진 생성자는 객체생성을 허용하는게 아니다.
this.field = "value";
this.method();
}// method
}//end class