[JAVA] 클래스

dev_swanim·2023년 3월 26일

JAVA 문법

목록 보기
2/10
post-thumbnail

1. 객체 지향 프로그래밍

객체란?

객체(object) : 물리적으로 존재하거나 개념적인 것 중에서 다른 것과 식별 가능한 것

  • 속성, 동작으로 구성됨 → 각각 필드, 메소드라 칭함
    • ex. 사람 속성 : 이름 ,나이, 동작 : 웃다, 걷다
  • 객체 생성 시, 설계도에 해당하는 클래스가 필요
  • 클래스로부터 생성된 객체, 인스턴스. 동일한 클래스로부터 여러 개의 인스턴스 생성 가능

객체의 상호작용

  • 객체들은 메소드를 이용해 상호작용을 한다.
//메소드(매개값1, 매개값2,...);

int result = add(10, 20);

객체 간의 관계

객체는 대부분 다른 객체와 관계를 맺고 있다.

집합 관계 : 완성품과 부품의 관계. (자동차는 엔진, 타이어 등으로 구성되니 자동차-부품은 집합관계)

사용 관계 : 다른 객체의 필드를 읽고 메소드를 호출하는 관계. (사람이 자동차에게 달린다와 같은 메소드를 호출하면 사람-자동차는 사용관계)

상속 관계: 부모와 자식 관계.(자동차가 기계의 특징(필드, 메소드)를 물려받으면 기계(부모)-자동차(자식)은 상속관계)

객체 지향 프로그래밍의 특징

  1. 캡슐화(Encapsulation)

    • 객체의 데이터(필드), 동작(메소드)을 하나로 묶고 실제 구현 내용을 외부에 감추는 것
    • 사용 이유 ? 외부의 잘못된 사용으로 인해 객체가 손상되지 않기 위함
    • 접근 제한자(Access Modifier)를 사용해 캡슐화된 멤버를 드러낼 것인지 숨길 것인지 결정한다
  2. 상속(Inheritance)

    • 부모 객체는 자신이 갖고 있는 필드와 메소드를 자식 객체에게 물려줘 자식 객체가 사용할 수 있도록 하는 것
    • 사용 이유
      • 코드의 재사용성을 높임(자식 객체에서 중복 코딩 안 해도 됨)
      • 유지 보수 시간을 최소화(부모만 수정하면 자식도 수정된 필드와 메소드를 이용 가능)
  3. 다형성(Polymorphism)

    • 사용법은 동일하지만 실행 결과가 다양하게 나오는 성질
      • ex. 동물의 신체부위를 어떻게 조합하느냐에 따라 고양이, 뱀 등 다른 동물이 등장할 수 있는것
    • 자동 타입 변환과 재정의 기술을 통해 구현

2. 클래스

클래스 선언 & 객체 생성

클래스 안에 또 클래스가 있어도 된다

public class Student{
}

public class StudentEx{
	public static void main(String[] args){
		Student s1 = new Student(); //s1 변수가 Student 객체를 참조
		Student s2 - new Student();
	}
}

➕ 클래스는 하나의 실행 클래스(main)와 여러 개의 라이브러리 클래스로 이루어져 있다

  • s1, s2는 각기 다른 Student 객체를 생성해 참조한다

클래스 구성 멤버

public class ClassName{
	// 필드 : 객체의 데이터가 저장
	int fieldName;

	// 생성자 : 객체 생성할 때 초기화 역할
	ClassName(){
	}

	// 메소드 : 객체의 동작으로 호출할 때 실행
	int methodName(){
	}
}

필드 선언과 사용

  • 필드는 클래스 블록 안에서 선언. 객체 내부에 존재하고 객체 내/외부에서 필드 값 이용 가능
    • 객체의 생성자와 메소드 내부에서 사용
    • 객체 외부에서도 사용 가능(myCar.speed = 60;)
  • 필드의 데이터 타입은 기본 타입, 참조 타입 모두 가능하다
public class Car{
	String modelName = "현대";
	int speed = 300;
	boolean end = true;
	Body body = new Body(); //참조타입 사용

	Car(){
		end = false; //객체 내부(생성자)에서 필드값 이용
	}
}

public class CarMaker{
	public static void main(String[] args){
		Car car1 = new Car(); 
		
		System.out.println("modelName" + myCar.model); //객체 외부에서 필드값 이용
	}
}

3. 생성자

  • return이 없다
  • new 연산자로 생성자를 호출할 때, 매개변수 값을 생성자로 전달할 수 있다
// 클래스 변수 = new 클래스();
Car car1 = new Car();

new를 이용해 객체 주소를 리턴

new 뒤에 클래스를 적을 수 있는 건, 생성자가 기본으로 만들어지기 때문에 호출 가능한 것이다!

생성자 오버로딩

  • 매개변수 타입, 개수, 순서가 다른 여러 개의 생성자를 선언할 수 있다
  • 생성자 오버로딩이 많아지면 중복 코드 또한 늘어나므로, 다른 생성자를 호출하여 해결할 수 있다
public class People{
	String nationality;
	String name;
	int height;

	People(String nationality){ // 1
		this(nationality, "홍길동", 175);
	}
	People(String nationality, String name){ // 2
		this(nationality, name, 175);
	}
	People(String nationality, String name, int height){ // 3
		this.nationality = nationality; //this.nationality는 필드값을 가리킴
		this.name = name;
		this.height = heght;
	}
}

public class PeopleEx{
	public static void main(String[] args){
		People people1 = new People("Korean"); // 1
		People people1 = new People("Korean", "김자바"); // 2
		People people1 = new People("Korean", "김자바", 180); // 3
	}
}

4. 메소드

메소드 선언

// 리턴타입 메소드명 (매개변수, ...){}
void power(){}
double plus(int x, int y){}

가변 길이 매개변수

// 가변 길이 매개변수를 갖는 메소드 선언
int sum(int ... values){
}
public class opr{
	**int plus(int ... values){**
		int sum = 0;
		
		for (int i = 0; i < values.length; i++){
			sum += values[i];
		}
		return sum;
	}
}

public class oprEx{
	public static void main(String[] args){
		opr myOpr = new opr();
		
		**int ans1 = myOpr.plus(1, 2, 3);**
		int ans2 = myOpr.plus(new int[] {1, 2, 3});
	}
}

메소드 오버로딩

이름이 동일한 메소드를 데이터 타입, 개수, 순서가 다르게 표현할 수 있다

  • 반환 타입과는 관계없다. 매개변수의 타입이 달라야 오버로딩이 성립한다.
public class Cal{
	double rect(double width){
		return width * width
	}
	double rect(double width, double height){
		return width * height
	}
}

public class oprEx{
	public static void main(String[] args){
		Cal myCal = new Cal();
		
		double ans1 = myCal.rect(10);
		double ans2 = myCal.rect(10,20);
	}
}

5. 인스턴스 멤버

  • 필드와 메소드 분류
    • 인스턴스(instance) 멤버 : 객체를 생성해야 사용할 수 있는 멤버
    • 정적(static) 멤버 : 객체 없어도 사용할 수 있는 멤버. 클래스에 고정됨

메모리 사용

  • 인스턴스 필드는 객체마다 따로 존재
  • 인스턴스 메소드는 메소드 영역에 저장되고 공유됨. 매번 객체로 저장되면 메모리 효율이 떨어지므로

this 키워드

  • 사용 예시
    • 생성자, 메소드의 매개변수 이름이 인스턴스 멤버인 필드명하고 동일한 경우(파라미터 값과 필드값이 중복되면 헷갈리니까)
    • 인스턴스 필드 강조할 때

6. 정적 멤버

  • 메소드 영역의 클래스에 고정적으로 위치하는 멤버. 객체 생성할 필요 없이 클래스를 통해 사용 가능
  • 사용 케이스 : 공용적으로 다른 곳에서도 사용하는 멤버라면 정적 멤버로 선언
  • static 키워드를 통해 정적 멤버 선언
public class cal{
**static** int plus(int x, int y){return x + y};
**static** double pi = 3.14;
}

정적 멤버 사용

객체를 생성해서 객체 참조 변수로 접근하는 것보다 클래스 이름으로 접근하는 게 일반적이다.

double ans = 10 * 10 * **cal**.pi;
int ans2 = cal.plus(10, 5);

정적 블록

일반적으로 선언과 동시에 초기화 하지만, 복잡하면 선언만 미리 한 뒤, 정적 블록에서 초기화 해준다.

// 정적 블록 형태
static {

}

static String inf;
static {
	inf = a + "-" + b;
}

정적 멤버는 인스턴스 멤버 사용 불가

  • 정적 멤버는 객체가 없어도 실행되므로, 인스턴스 필드, 메소드를 사용하지 못한다. this도 사용 못한다.
  • 정적 메소드, 블록에서 인스턴스 멤버를 참조해야 하는 경우, 객체를 생성한 뒤 참조 변수로 접근
    • main함수도 보면 static이다. 그러니 객체를 바로 사용하지 못하고 객체를 생성한 뒤 사용하는 것이다!

7. final 필드와 상수

  • final 필드와 상수를 선언해 사용 : 값을 변경하는 것을 막고 읽기만 허용해야 하는 경우
  • 초기값을 주는 방법
    1. 필드 선언 시, 초기값 대입
    2. 생성자에서 초기값 대입
public class Korean{
	final String nation = "대한민국"; // 1
	final String ssn;

	public Korean(String ssn){ 
		this.ssn = ssn; // 2
	}
}

상수 선언

  • 불변의 값을 저장하는 필드
  • 초기값 주는 방법
    1. 필드 선언 시
    2. 정적 블록에서 초기화
// static final 타입 상수;
static final double EARTH_RADIUS = 6400;

static{
	상수 = 초기값;
}

8. 패키지

패키지 선언

package 상위패키지.하위패키지;

import 문

  • 다른 패키지에 있는 클래스를 사용할 때 이용
  • import를 이용해 어떤 패키지의 클래스를 이용할 것인지 명시
package com.mycompany;

import com.kTire.Tire;
import com.JTire.*; // 다수의 클래스를 사용하는 경우

public class Car{
	Tire tire = new Tire();
}

9. 접근 제한자

접근 제한자사용 범위제한 범위
public클래스, 필드, 생성자, 메소드x
protected필드, 생성자, 메소드같은 패키지이거나, 자식 객체만 사용가능
(default)클래스, 필드, 생성자, 메소드같은 패키지
private필드,생성자, 메소드클래스 내부
  • 객체의 무결성을 유지하기 위함
  • 클래스 선언 시, 다른 접근 제한자를 쓰지 않았다면 디폴트 값이 기본으로 설정된다
  • private는 클래스 내부에서만 사용할 수 있고 객체 선언하여 생성자 접근하거나 메소드 값 접근하는 게 안 된다

10. Getter와 Setter

  • 사용 이유 : 필드를 직접적으로 이용하면 객체의 무결성이 깨지므로 메소드를 통해 객체에 올바른 값을 할당하거나 사용할 수 있도록 하기 위함이다
  • Getter : 필드값이 외부에서 사용하기 좋은 형태가 아닐 때, 적절한 값으로 변환해 리턴하는 메소드
  • Setter : 데이터를 검증해 유효한 값만 필드에 저장할 때 사용하는 메소드
  • get/set + 필드이름으로 메소드 이름을 짓는다

Getter

public double speed;

public double getSpeed(){
	double km = speed * 1.6;
	return km;
}

Setter

private double speed;

public void setSpeed(double speed){
	if (speed < 0) {
		this.speed = 0;
		return;
	}
	else{
		this.speed = speed;
	}
}

11. 싱글톤 패턴

  • 싱글톤 패턴 : 객체 하나만 생성해서 사용하는 것
    • 여러 개의 변수가 같은 싱글톤 객체만을 가리키도록 한다
  • 싱글톤 패턴의 핵심 : 생성자를 private 접근 제한해서 외부에서 직접적으로 new 연산자로 생성자를 호출할 수 없도록 막는다
public class Singleton{
	// private 정적 필드 선언 & 초기화
	private static Singleton singleton = new Singleton();
	
	// 생성자 선언
	private Singleton(){
	}

	//public 정적 메소드 선언
	static Singleton getInstance(){
		return singleton;
	}
}

public class SinEx{
	public static void main(String[] args){
		// obj1 과 obj2는 같은 객체를 가리키고 있다
		Singleton obj1 = Singleton.getInstance();
		Singleton obj2 = Singleton.getInstance();
	}
}

📚참고 문헌

이것이 자바다(신용권, 임경균 지음)

profile
데이터와 백엔드를 공부하고 있습니다😌

0개의 댓글