JAVA 5주차

ndy·2022년 10월 2일

Java

목록 보기
5/10

인스턴스 맴버

  • 객체(인스턴스)마다 가지고 있는 필드메소드를 말함
  • 인스턴스 맴버는 객체에 소속된 맴버이기 때문에 객체 없이 사용 불가
public class Car {
	//필드
    int gas;
    
    //메소드
    void setSpeed(int speed) {...}
}

Car myCar = new Car();
myCar.gas = 10;	// 인스턴스 필드
myCar.setSpeed(60);	// 인스턴스 메소드

Car yourCar = new Car();
myCar.gas = 20;
myCar.setSpeed(80);

this

  • 객체(인스턴스) 자신의 참조(번지)를 가지고 있는 키워드
  • 객체 내부에서 인스턴스 맴버임을 명확히 하기 위해 this.을 붙일 수 있음
class Car {
	String model;
    
	Car(String model) {
		this.model = model;
	}
    void setModel(String model) {
    	this.model = model;
    }
}

정적(static) 맴버

  • 클래스에 고정된 필드메소드를 말함
  • 정적 맴버는 클래스에 소속된 맴버로, 객체 내부에 존재하지 않고, 메소드 영역에 존재함
  • 객체를 생성하지 않고 클래스로 바로 접근 가능
// 정적 맴버 선언
public class Car {
	static model;
    
    static setModel(String model){...}
}

메소드 영역에 고정됨


//정적 맴버 사용
public class Calculator {
	static double pi = 3.14159;
    static int add(int x, int y){return x+y;}
    static int sub(int x, int y){return x-y;}
}
double result1 = 10 * 10 * Calculator.pi;
int result2 = Calculator.add(10, 5);
int result3 = Calculator.sub(10, 5);

객체를 생성하지 말고 클래스를 불러와서 사용


인스턴스 맴버 선언 vs 정적 맴버 선언의 기준

  • 필드
    • 객체 마다 가지고 있어야 하는 데이터 : 인스턴스 필드
    • 공용적인 데이터 : 정적 필드
  • 메소드
    • 인스턴스 필드로 작업해야할 메소드 : 인스턴스 메소드
    • 인스턴스 필드로 작업하지 않는 메소드 : 정적 메소드
public Calculator {
	String color; // 필드
    void setColor(String color) { this.color = color; }
    // static 사용하면 오류남 (this는 인스턴스 맴버를 가르킴)
    
    static int add(int x, int y){ return x+y; }
    static int sub(int x, int y){ return x-y; }
}

정적 초기화 블록

  • 클래스가 메소드 영역으로 로딩될 때 자동으로 실행하는 블록
  • 정적 필드의 복잡한 초기화 작업정적 메소드를 호출할 수 있음
  • static 필드 여러 개 선언 가능
static Television {
	static String company = "Samsung";
    static String model = "LCD";
    static String info;
    
    static {
    	info = company + "-" + model;
    }
    static {}
    static {}
    ...
}

main() 메소드도 정적 메소드임

public class Car {
	int speed;
    void run(){};
    
    public static void main(String[] args) {
    	speed = 60; // 불가능, 객체가 생성 되지 않음
    
        Car myCar = new Car();
        myCar.speed = 60;
        
    }
}

싱글톤

  • 하나의 애플리케이션 내에서 단 하나만 생성되는 객체를 말함

싱글톤을 만드는 방법

  • 외부에서 new 연산자로 생성자를 호출할 수 없도록 함
    • private 접근 제한자 사용
  • 클래스 자신의 타입으로 정적 필드를 선언, 객체를 생성해 초기화함
  • 외부에서 호출할 수 있는 정적 메소드인 getInstance()를 선언
public class Car {
	// 정적 필드
    private static Car myCar = new Car();
    
    // 생성자
    private Car(){...}
    
    // 정적 메소드
    static Car getInstance() {
    	return myCar; 
        // myCar이 참조하는 객체의 번지가 100이면 100을 리턴
       
    }
}

싱글톤을 얻는 방법

Car Car1 = new Car(); // 오류

Car Car1 = Car.getInstance(); // 정적 객체 myCar의 번지가 저장


final 필드

  • 최종적인 값을 가지고 있는 필드 = 값 변경 불가능
  • 딱 한번 초기값 지정 방법
    1. 필드 선언시
    2. 생성자
public class Person {
	final String nation = "Korea"; // 필드에서 초기화
    final String ssn;
    
    public Person(String ssn, String name) {
    	this.ssn = ssn; // 생성자에서 초기화
    }
}

상수 (static final)

  • 상수 = 정적 final 필드
  • 객체마다 가지지 않는 정적 필드

상수 선언과 초기화

  • 전부 대문자로 작성하는 것이 관례
  • 다른 단어와 결합되면 _로 연결
static final double EARTH_RADIUS = 6400; // 필드에서 초기화
static final double EARTH_SURFACE_AREA;

static { // static 메소드로 초기화
	EARTH_SURFACE_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS
} 

패키지

  • 클래스를 기능별로 묶어서 그룹 이름을 붙여 놓은 것을 말함
  • 패키지는 클래스 이름의 일부
    • 전체 클래스 이름 : 상위패키지.하위패키지.클래스
  • 클래스를 선언할 때 패키지가 결정됨

패키지 선언

  • 패키지 선언은 클래스 선언 첫 줄에 함
  • 상위 패키지와 하의 패키지는 도트(.)으로 구분
package 상위패키지.하위패키지;

public class ClassName{...}

패키지 이름 규칙

  • 전부 알파벳 소문자로 작성이 관례
  • 숫자로 시작 x
  • _, $을 제외한 특수 문자 사용 x

패키지 선언이 포함된 클래스 컴파일

  • 명령 라인에서 컴파일 할 경우
    • javac XXX.java

      • 바이트 코드 파일(~.class)만 생성됨
      • 폴더를 직접 만들어 저장해줘야 함
    • javac -d [패키지 생성 위치] XXX.java

      • 패키지 생성 위치에 폴더가 생성됨

        javac -d ../bin ClassName.java

패키지 선언이 포함된 클래스 실행

  • 상위(루트) 패키지가 시작하는 곳에서 실행해야 함

  • java 상위패키지.하위패키지.클래스

    	java sec12.exam01_package_complile.ClassName

import 문

  • 패키지 내에 같이 포함된 클래스간에는 클래스 이름으로 사용 가능
  • 패키지가 다른 클래스를 사용해야 할 경우, 2가지 방법
    • 패키지명이 포함된 전체 클래스 이름 사용

      package com.mycompany;
      
      public class Car {
      	com.hankook.Tire tire = new com.hankook.Tire();
      }
    • import 문으로 패키지를 지정하고 사용

      package com.mycompany;
      
      import com.hankook.Tire;
      //import com.hankook.*;
      
      public class Car {
      	Tire tire = new Tire();
      }

접근 제한자

  • 클래스 및 클래스의 구성 맴버에 대한 접근을 제한하는 역할

public class ClassName {
	public int field1;
    int field2;
    private int field3;
}

Getter와 Setter

  • 클래스를 선언할 때 필드는 일반적으로 private 접근 제한을 함
    • 읽기 전용 필드가 있을 수 있음 Getter
    • 외부에서 엉뚱한 값으로 변경할 수 없게 함 Setter

Getter

  • private 필드의 값을 리턴하는 역할
  • getFieldName() 또는 isFieldName() 메소드를 말함
    • 필드 타입이 boolean 이면 isFieldName()
class Car {
	private double speed;
    public double getSpeed(){return speed;} // Getter
}
class Car {
	private boolean stop;
    public boolean isStop() {return stop;} // Getter
}

Setter

  • 외부에서 주어진 값을 필드값으로 수정
    • 필요할 경우 외부 값의 유효성을 검사
  • setFieldName(타입 변수) 메소드를 말함
    • 매개 변수 타입은 필드의 타입과 동일
class Car {
	private double speed;
    public void setSpeed(double speed) { // Setter
    	if(speed < 0) {	// 유효성 검사
        	this.speed = 0;
            return;
        }else {
        	this.speed = speed;
        }
    }
}

어노테이션

  • 프로그램에게 추가적인 정보를 제공해주는 메타데이터

어노테이션 용도

  • 컴파일러에게 코드 작성 문법 에러를 체크하도록 정보 제공
  • 소프트웨어 개발 툴이 빌드가 배치시 코드를 자동으로 생성할 수 있도록 정보 제공
  • 실행시(런타임시) 특정 기능을 실행하도록 정보를 제공

어노테이션 타입 정의와 적용

  • 어노테이션 타입 정의

    • 소스 파일 생성 : AnnotationName.java
public @interface AnnotationName {
}
  • 어노테이션 타입 적용
@AnnotationName

ex)

@Override // 어노테이션
public void toString(){...}

어노테이션의 엘리먼트(element) 맴버

  • 어노테이션을 코드에 적용할 때 외부의 값을 입력받을 수 있도록 하는 역할
public @interface AnnotationName {
	String elementName1();
    int elementName2() default 5;
}
  • 어노테이션 적용시 엘리먼트 값을 지정하는 방법
@AnnotationName(elementName1 = "값", elementName2 = 3);
@AnnotationName(elementName1 = "값"); // elementName2은 default값 3
  • 기본 엘리먼트 value
public @interface AnnotationName {
	String value();
    int elementName() default 5;
}
  • 어노테이션을 적용할 때 엘리먼트명을 생략 가능
@AnnotationName("값"); // 기본 엘리먼트 value의 값으로 들어감
  • 두 개 이상의 속성을 기술할 때에는 value="값" 형태로 기술
@AnnotationName(value="값", elementName=3);

어노테이션 적용 대상

  • java.lang.annotation.ElementType 열거 상수로 정의 되어 있음

어노테이션 적용 대상 지정 방법

  • @Target 어노테이션으로 적용 대상 지정
  • @Target의 기본 엘리먼트인 value의 타입은 ElementType 배열
@Target((ElementType.TYPE, ElementType.FIELD, Element.Type.METHOD))
public @interface AnnotationName {
}
@AnnotationName
public class ClassName {
	@AnnotationName
    private String fieldName;
    
    // @AnnotationName 불가능 (위에 CONSTRUCTOR(생성자) 타겟 지정이 안되어있음)
    public ClassName(){}
    
    @AnnotationName
    public void methodName(){}
}

어노테이션 유지 정책

  • 어노테이션 적용 코드가 유지되는 시점을 지정
  • java.lang.annotation.RetentionPolicy 열거 상수로 정의 되어 있음

유지 정책 지정 방법

@Target((ElementType.TYPE, ElementType.FIELD, Element.Type.METHOD))
@Retention(RetentionPolicy.RUNTIME) // 유지 정책 지정
public @interface AnnotationName {}

런타임시에 어노테이션 정보 사용하기

  • 클래스에 적용된 어노테이션 정보 얻기

    • 클래스.class의 어노테이션 정보를 얻는 메소드 이용

  • 필드, 생성자, 메소드에 적용된 어노테이션 정보 얻기

    • 클래스.class의 다음 메소드를 이용 해서
    • java.lang.reflect 패키지의 Field, Constructor, Method 클래스의 배열을 얻어냄
  • 어노테이션 정보를 얻기 위한 메소드

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PrintAnnotation {
	String value() default "-";
    int number() default 15;
}
public class Service {
	@PrintAnnotation
	public void method1(){
    	System.out.println("실행 내용1");
    }
    @PrintAnnotation("*")
    public void method2(){
    	System.out.println("실행 내용2");
    }
    @PrintAnnotation(value = "#", number = 20)
    public void method3(){
    	System.out.println("실행 내용3");
    }
}

import java.lang.reflect.*;

public class PrintAnnotationExample {
	public static void main(String[] args) {
    	Method[] declaredMethods = Service.class.getDeclaredMethods();
        
        for(Method method : declaredMethods) {
        	if(method.isAnnotationPresent(PrintAnnotation.class)) {
        		System.out.println(method.getName() + "에는 적용 o");
        	}else {
        		System.out.println(method.getName() + "에는 적용 x");
        	}
        }
    }
}

0개의 댓글