[Java] 클래스와 객체, 객체지향언어, 캡슐화, 추상화, 생성자, 오버로딩
클래스란
서로 다른 자료형의 데이터들을 하나로 묶어 새로운 타입을 정의한 것이다.
(배열과 달리 다른 자료형들의 값을 하나로 묶을 수 있음)
클래스는 객체를 생성하는데 사용
String id;
String pwd;
String name;
int age;
char gender;
String[] hobby;
<출력메소드>
System.out.println("member.id : " + member.id);
System.out.println("member.pwd : " + member.pwd);
System.out.println("member.name : " + member.name);
System.out.println("member.age : " + member.age);
System.out.println("member.gender : " + member.gender);
System.out.print("member.hobby : ");
지금까지는 클래스 내부에 메소드만 작성해 보았지만
클래스 내부에서 메소드를 작성하지 않아도 바로 변수를 선언할 수 있다.
다른 곳에서 클래스의 필드에 접근하기 위해 '.' (참조연산자)를 활용한다.
필드에 직접 접근 시 문제점
필드에 올바르지 않은 값이 들어가도 통제가 안 된다.
나이를 입력해야 하는데 올바르지 않은 값이 대입이 가능하다.
필드명이 변경되면 관련 코드를 수정해야 하는 번거로움이 있다.
캡슐화
결합도를 낮추기 위해 직접 접근을 제한하고 public 메소드를 이용해서 간접적으로 접근하여 사용할 수 있도록 만든 기술이다.
접근제한자
클래스 혹은 클래스의 멤버에 참조연산자로 접근할 수 있는 범위를 제한하기 위한 키워드이다.
-public : 모든 패키지에 접근 허용
-protected : 동일 패키지에 접근 허용. 단, 상속관계에 있는 경우 다른 패키지에서도 접근 가능
-default : 동일 패키지에서만 접근 허용 (작성하지 않는 것이 default)
-private : 해당 클래스 내부에서만 접근 허용
위의 네 가지 접근 제한자는 클래스의 멤버(필드, 메소드)에 모두 사용 가능하다.
단, 클래스 선언 시 사용하는 접근 제한자는 public과 default만 사용 가능하다.
객체 지향 언어
현실 세계는 사물이나 개념처럼 독립되고 구분되는 각각의 객체로 이루어져 있으며 발생하는 모든 사건들은 객체 간의 상호작용이다. 이 세계관을 프로그래밍 언어에 도입하여 만들어진 언어가 객체지향언어 이다.
객체란?
현실에 존재하는 독립적이면서 하나로 취급되는 사물이나 개념
클래스에 정의된대로 new 연산자를 통해 heap에 할당된 공간(==인스턴스)
객체의 할당
객체 생성 시 heap메모리 공간에 서로 다른 자료형의 데이터가 연속으로 나열/할당된 인스턴스 공간
객체의 용도
객체가 가지고 있는 기능과 속성에 따라 다름
객체의 구성요소
속성과 기능
클래스와 인스턴스
객체를 추상화한 것으로 인스턴스를 생성할 목적으로 정의 해놓은 소스코드 작성 단위이다.
추상화(abstraction)란?
프로그램에서 필요한 공통점을 추출하고 불필요한 공통점을 제거하는 과정
-유연성을 확보하기 위해 구체적인 것은 제거한다는 의미이다.
-유언성 확보는 여러 곳에 적용될 수 있는 유연한 객체를 의미하며, 재사용성이 높아질 수 있다는 의미이다.
-객체의 재사용성이 증가하면 중복 작성되는 코드를 줄일 수 있으며, 오류 발생 가능성을 감소시키고 유지보수성을 증가시킨다.
생성자(Constructor)란?
객체가 new연산자를 통해 Heap메모리 영역에 할당될 때 1회성으로 호출되는 리턴타입이 없는 메소드
-인스턴스를 생성할 때 매개변수가 초기 수행할 명령이 있는 경우 미리 작성해두고, 인스턴스를 생성할 때 마다 호출된다.
-인스턴스 생성 시 필드 초기화 목적으로 주로 사용된다.
-생성자 함수에 매개변수가 없는 생성자를 기본 생성자(default constructor)라고 한다.
-필드 초기값을 사용자가 원하는대로 설정하고 싶은 경우 생성자 호출 시 인자로 값을 전달하여 호출할 수 있다. 이러한 인자를 받아 필드를 초기화할 목적의 생성자를 매개변수 있는 생성자라고 한다.
생성자의 작성 위치
필드 선언부와 메소드 선언부 사이에 작성하는 것이 관례이다.
생성자의 사용 목적
1. 인스턴스 생성 시점에 수행할 명령이 있는 경우 사용한다.
2. 매개변수 있는 생성자의 경우 매개변수로 전달받은 값으로 필드를 초기화하며 인스턴스를 생성할 목적으로 사용된다.
3. 작성한 생성자 외에는 인스턴스를 생성하는 방법을 제공하지 않는다.
따라서, 인스턴스를 생성하는 방법을 제한하기 위한 용도로 사용할 수도 있다. (초기값 전달 강제화)
생성자 작성 방법
[표현식]
접근제한자 클래스명(매개변수) {
인스턴스 생성 시점에 수행할 명령 기술 (주로 필드초기화)
this.필드명 = 매개변수;
}
/* 기본 생성자 호출*/
User user1 = new User();
System.out.println(user1.getInformation());
/* id, pwd, name 초기화 하는 매개변수 생성자 호출 */
User user2 = new User("user01", "pass01", "유관순");
System.out.println(user2.getInformation());
/* 모든 필드를 초기화 하는 생성자 호출 */
User user3 = new User("user02", "pass02", "홍길동", new java.util.Date());
System.out.println(user3.getInformation());
/* 복사 생성자 호출 */
User user4 = new User(user3);
System.out.println(user4.getInformation());
this
this는 인스턴스가 생성되었을 때 자신의 주소를 저장하는 레퍼런스 변수
-할당된 인스턴스의 주소가 저장된다.
-지역변수와 전역변수의 이름이 동일한 경우 지역변수를 우선적으로 접근하기 때문에전역변수에 접근하기 위해서 this. 를 명시해야 한다.
public class Academy{
private String name;
public Amademy(){}
public Academy(String name) {this.name = name;}
}
위의 코드와 같이 매개변수를 가지는 생성자에서 매개변수 명이 필드명과 같은 경우 this를 이용하여 필드라는 것을 구분해 준다.
오버로딩(Overloading)이란?
동일한 메소드명으로 다양한 종류의 매개변수에 따라 다르게 처리해야하는 것을 관리하기 위해 사용하는 기술
오버로딩의 조건
동일한 이름을 가진 메소드의 파라미터 선언부에 매개변수의 타입, 갯수, 순서를 다르게 작성하여 한 클래스 내에 동일한 이름의 메소드를 여러 개 작성할 수 있도록 한다.
메소드의 시그니처(Signature)가 다르면 다른 메소드로 인식하기 때문이다.
즉, 시그니처 중 메소드 이름은 동일해야 하기 때문에 파라미터 선언부가 다르게 작성 되어야 오버로딩이 성립된다.
메소드의 시그니처
public void method(int num) { } 이라는 메소드의 메소드명과 파라미터 선언부 부분을 시그니처라 부른다.
접근제한자나 반환형은 오버로딩 성립요건에 해당하지 않는다.
/* 오버로딩을 이용한 메소드 작성 테스트를 위한 기준이 되는 메소드 */
public void test() {}
/* 메소드 시그니처가 동일한 겨우 Compile Error를 발생시킨다 */
//public void test() {}
/* 접근 제한자에 따른 오버로딩 성립 확인 -> 접근제한자는 메소드 시그니처에 해당하지 않는다. */
//private void test() {}
/* 반환형에 따른 오버로딩 성립 확인 -> 반환형은 메소드 시그니처에 해당하지 않는다. */
//public int test() {return 0;}
/* 매개변수 유무에 따른 오버로딩 성립 확인 -> 파라미터 선언부는 메소드 시그니처에 해당한다. */
public void test(int num) {}
final이란?
변경 불가의 의미, 메소드에서는 종단의 의미를 지닌다.
클래스 필드의 final변수는
1. 선언과 동시에 초기화 하거나
2. 생성자를 통한 초기화를 해야 한다.
/* 1. 선언과 동시에 초기화 한다. */
private final int NON_STATIC_NUM = 1;
/* 2. 생성자를 이용해서 초기화 함 */
private final String NON_STATIC_NAME;
public FinalFieldTest(String nonStaticName) {
this.NON_STATIC_NAME = nonStaticName;
}
변수의 종류
static이란?
정적 메모리 영역에 프로그램이 start될 시 할당하고자 할때 사용하는 키워드
-static필드나 메소드는 인스턴스 생성 없이 사용 가능하다.
-여러 인스턴스가 공유해서 사용할 목적으로 만드는 것
-하지만 static키워드의 남발은 유지보수와 추적이 힘든 코드를 작성하는 방식으로 명확한 목적이 존재하지 않는 이상 사용 자제.. => 의도적으로 static키워드를 사용하는 대표적인 예는 singleton 객체를 생성할 때이다.
singleton(싱글톤 패턴)
애플리케이션이 시작될 때 어떤 클래스가 최종 한 번만 메모리를 할당하고 그 메모리에 인스턴스를 만들어서 하나의 인스턴스를 공유해서 사용하며 메모리 낭비를 방지할 수 있게 한다. (매번 인스턴스 생성하지 않음)
-장점
1. 첫 번째 이용 시에는 인스턴스를 생성해야 하므로 속도 차이가 나지 않지만
두 번째 이용 시에는 인스턴스 생성 시간 없이 사용할 수 있다.
2. 인스턴스가 절대적으로 한 개만 존재하는 것을 보증할 수 있다.
-단점
1. 싱글톤 인스턴스가 너무 많은 일을 하거나 많은 데이터를 공유하면 결합도가 높아진다. (유지보수와 테스트의 문제점)
2. 동시성 문제를 고려해서 설계해야하기 때문에 난이도가 있다.
싱글톤 구현방법
-이른 초기화(Eager singleton)
/* 클래스가 초기화 되는 시점에서 인스턴스를 생성한다. */
private static EagerSingleton eagar = new EagerSingleton(); //필드 선언과 동시에 초기화
/* 싱글톤 패턴은 생성자 호출을 통해 외부에서 인스턴스를 생성하는 것을 제한한다. */
private EagerSingleton() {}
/* 만들어놓은 인스턴스를 반환한다. */
public static EagerSingleton getInstance() {
return eagar;
}
-게으른 초기화(Lazy singleton)
/* 클래스가 초기화 되는 시점에는 정적 필드를 선언해두고 null로 초기화 된다.*/
private static LazySingleton lazy;
/* 싱글톤 패턴은 생성사 호출을 통해 외부에서 인스턴스를 생성하는 것을 제한한다. */
private LazySingleton() {}
/* 인스턴스를 생성한 적이 없는 경우 인스턴스를 생성해서 반환하고
* 생성한 인스턴스가 있는 경우 만들어둔 인스턴스를 반환한다.
* */
public static LazySingleton getInstance() {
if(lazy == null) {
/* 인스턴스를 생성한 적이 없는 경우 새로운 인스턴스 생성 */
lazy = new LazySingleton();
}
return lazy;
}
-이른 초기화, 게으른 초기화 차이점
-이른 초기화를 사용하면 클래스를 로드하는 속도가 느려지지만 처음 인스턴스 반환 요청에서는 속도가 빠르다는 장점을 가지고 있다.
-게으른 초기화를 사용하면 클래스를 로드하는 속도는 빠르지만 첫 번째 요청에 대한 속도가 두 번째 요청에 대한 속도보다 느리다는 특징을 가지고 있다.