본문 바로가기
BACK-END/Java

[Java] 객체지향의 활용

by 로햐 2021. 11. 21.

Ⅰ. 객체

1-1. 객체란?

다른 것과 구별할 수 있는 속성을 가져 개개별로 식별할 수 있는 독립적인 형태.

자바에서는 new 연산자를 이용해 메모리의 Heap 영역에 생성한다.

자바는 객체지향 언어로 클래스라는 객체를 통해 프로그래밍한다.

 

Student st = new Student();

1-2. 객체지향

1-2-1. 객체지향이란?

현실의 개체처럼 객체들을 조립하여 프로그래밍 하는 개발 방법을 말한다.

(Object-Oriented OOP 객체지향 프로그래밍 OOA 객체지향 분석 OOD 객체지향 설계)

 

1-2-2. 구성요소

Object : 데이터나 함수들의 묶음

Class : 유사한 속성을 가진 객체를 각 구분하게 만들어주는 개별화. 이렇게 된걸 인스턴스라고 한다.

Message : 객체들 상호작용에서 발생하는 요구사항

 

1-2-3. 특징 

Encapsulation : 외부에서 직접 접근할 수 없도록 접근제한자를 걸어 보호하는 것. 정보은닉.

Inheritance : 부모클래스의 요소들을 자식클래스가 물려받는것.

Polymorphism : 하나의 객체를 다양한 형태와 방법으로 사용할 수 있게 만들어주는 성질.

//추상화

//관계


1-3. 객체배열

객체를 사용자가 정의하는 자료형으로 취급하여, 같은 자료형을 가진 배열을 생성하는 것.

Student[] st = new Student[5];
//클래스명(사용자정의 자료형)[] 배열이름 = new 클래스명[배열길이];

Ⅱ. 클래스

클래스란?

객체를 필드+생성자+메소드의 형태로 기술한 것.

public class Student{//외부 접근 가능
	//코드들
}
/*default*/ class Person{//현재 패키지 내에서만 접근 가능
	//코드들
}

※접근제한자

해당 요소에 접근 가능한 구역을 제한한다. 표의 위에서부터 아래로, 넓은 범위에서 좁은 범위로 축소된다.

접근제한자 명 가능한 구역
public 외부에서도 접근 가능
protected 후손 클래스에서도 접근 가능
default(생략 가능) 동일 패키지 내부에서 접근 가능
private 해당 클래스 내부에서만 가능

※예약어

예약어 의미 활용
static 프로그램이 시작할 때 메모리의 static 영역에 생성.  private static int age;
final 해당 속성을 변경할 수 없게 막은 예약어.  final은 변경이 불가능 클래스는 상속이 불가능한 클래스.
변수는 상수 필드.
메소드는 오버라이딩이 불가능.

2-1. 필드란?

변수를 클래스에 선언하면서 "접근제한자 자료형 필드명;"의 형태로 나타낸 것.

public String name;//모든 외부에서 접근 가능
protected int age;//후손 클래스까지는 접근 가능
/*default*/ char gender;//같은 패키지 내에서는 접근 가능
private String club;//현재 클래스 내부에서만 접근 가능

2-2. 생성자란?

객체가 new 연산자를 통해 heap 메모리 영역에 할당될 때, 객체 안에서 만들어지는 필드를 초기화하는 것.

일종의 메소드로, 전달된 초기값을 받아 객체의 필드에 기록할 수 있다.

 

매개변수가 있는 생성자가 없는 경우 JVM에서 자동으로 기본생성자를 만들어 처리하므로 따로 기술할 필요가 없지만,

매개변수가 있는 생성자가 있는 경우 JVM에서 기본생성자를 생성하지 않으므로 반드시 기술해야한다.

public class Student{
    public Student(){
    }//기본생성자
    
    public Student(String name, int age, char gender){
    this.name=name;
    this.age=age;
    this.gender=gender;
    }//매개변수가 있는 생성자
}

2-3. 메소드란?

메소드 : 함수 내에 작성된 연산 수행

메소드는 부를때마다 새로운 메소드이므로, 껍데기는 같아보여도 그 안의 내용물은 전혀 다르다.

 

오버로딩 : 한 클래스 내에 동일한 이름의 메소드를 여러개 작성하는 기법.

              매개변수의 순서, 개수, 종류를 다르게하면 다른 메소드로 인식한다.

public void searchStudent(){
	System.out.println("학생을 찾습니다.");
}
/*public String searchStudent(){
	return "학생을 찾습니다.";
}
//리턴 타입이 달라도 자료형이 같으면 동일한 메소드로 보고 중복 오류메세지를 띄운다.
*/
public void searchStudent(String name){
	System.out.println(name+"학생을 찾습니다.");
}
public void searchStudent(String name, int age){
	System.out.println(name+"학생은 "+age+"살입니까?");
}
public void searchStudent(int age, String name){
	System.out.println(age+"살인 "+name+"학생을 찾습니다.");
}

getter / setter : 캡슐화로 private한 필드들을 외부에서 접근하기 위해 값을 호출, 값을 지정하는 방법. 

public void Student(){
    private String name;//캡슐화 필드
    
    public Student(){//기본생성자
    }
    public Student(String name){//매개변수 생성자
    this.name=name;
    }
    
    public void setName(String name){//setter
    this.name=name;
    }
    public String getName(){//getter
    return name;
    }
}

toString()

보통 필드들의 정보를 한눈에 보기 쉽게 정리하여, 필드값을 개발자가 확인하는 용도로 사용한다.

Object의 메소드를 상속받는 형태. @Override를 붙여준다.

@Override
public String toString(){
 	return "Student [name=" + name + ", age=" + age + "]";
}

 

메소드 가변인자 : 메소드의 매개변수에 (자료형... 변수명)을 넣어서 정하지 않은 수의 값을 받게하는 것. 가변 매개변수는 매개변수의 마지막에 설정한다.

가변인자를 사용하면 JVM에서 자동으로 해당 매개변수를 배열로 변경하여 인식하고, for each 등 배열과 동일하게 사용할 수 있다. 값을 받지 않아도 배열의 크기가 0인 것처럼 작동한다.

public void searchStudent(String name, int age, char gender, int ... grade){
	//코드들
}

Ⅲ. 상속

3-1. 상속이란?

다른 클래스가 가지고있는 요소들을 직접 만들지않고 자신의 요소처럼 사용하는 방법.

클래스는 한번에 한개의 클래스만 상속받을 수 있다. 다중상속은 자바에서는 불가능하고, c++에서는 가능하다.

자바의 모든 클래스는 Object 클래스를 상속받은 것으로 간주하여, Object의 메소드를 오버라이드 할 수 있다.

public class Student extends Person{
    //자식클래스 extends 부모클래스
    //Person 클래스를 상속받은 Student 클래스
    //상속받은 요소들은 해당 클래스에 포함되어있지 않더라도 가진 것으로 취급한다.
    //메소드의 경우, 오버라이드할 수도 있다.
}

오버라이딩 : 자식 클래스에서 부모클래스에서 상속받은 같은 메소드명을 가진 메소드를 재정의하여 사용하는 것.

자식이 우선권을 가진다. Annotation은 @Override을 표시한다.

 

※바인딩

바인딩은 메소드를 결과로 연결하는 것으로, 정적 바인딩과 동적 바인딩이 있다.

//정적 바인딩 : static으로 프로그램 실행 시 고정
class Child extends Parent {
	public static void walk() {
		System.out.println("eat lunch");
	}
}
class Parent {
	public static void walk() {
		System.out.println("eat breakfast");
	}
}
class Main {
	public static void main(String[] args) {
	Parent ch = new Child();
	ch.walk();//결과 : eat breakfast
	}
}
//동적 바인딩 : 오버라이딩 된 메소드를 호출
class Child extends Parent {
	@Override
	public void walk() {
		System.out.println("eat lunch");
	}
}
class Parent {
	public void walk() {
		System.out.println("eat breakfast");
	}
}
class Main {
	public static void main(String[] args) {
	Parent ch = new Child();
	ch.walk();//결과 : eat lunch
	}
}

정적 바인딩은 컴파일 시점에 결과가 정해지므로 그대로 호출되지만,

동적 바인딩은 컴파일이 지나고 런타임 시점에 결과가 정해지므로 결과가 달라진다.

 

상속의 오버라이드는 동적 바인딩이 적용된 상태이다. 

컴파일 시점에서는 부모 클래스의 메소드를 호출하지만,

런타임 시점에는 다형성에서 동적바인딩이 적용되었으므로 자식 클래스의 오버라이드 된 메소드를 호출한다.


3-2. Annotation이란?

주석을 의미하며, 해당 메소드가 어떤 상태인지 확인할 수 있는 기능이다.

 

※자주 쓰이는 Annotation들

@Override : 상속받은 객체의 동일 이름, 반환형, 매개변수인 메소드를 재정의, 오버라이드 했다고 표시.

@Deprecated : 사용하지 않는 메소드를 표시. 해당 메소드가 사용된다면 컴파일 에러가 뜬다.


3-3. this / super

3-3-1. this

현재 클래스를 가리킨다. 주소를 자동으로 받아 참조하거나 생성자를 호출한다.

this. : 같은 클래스의 필드를 가리킨다. 생성자의 경우 같은 변수명이 겹치는 경우에 둘을 구분하기 위해 쓰인다.

this() : 같은 클래스의 다른 생성자를 호출할 때 사용. 생성자 내부의 호출은 반드시 첫 줄에서 수행해야한다.

public Student(){
}

public Student(String name) {
    this(20,'M',"클럽없음");
    this.name=name;
}

public Student(int age, char gender, String club) {
    this.age = age;
    this.gender = gender;
    this.club = club;
}

 

3-3-2. super

부모의 클래스를 가리킬 때 사용한다.

super. 로 부모의 값을 참조하여 사용할 때 사용한다.

super()은 자식 클래스의 매개변수 생성자 안에서 부모 클래스의 필드값을 받아올 때 사용한다.

super()은 반드시 첫 번째 줄에 선언해야 한다.

public Student(String club){
    super(name, age);//super() 활용
    this.club=club;
}

@Override
public String toString(){
    return super/*.toString()*/+"club="+club;//toString 안에서 부모의 .toString을 받아오기
}

Ⅳ. 다형성

4-1. 다형성이란?

상속 관계에서 부모 타입을 활용하여 자식 객체들을 묶음으로 다룰 수 있는 방법.


4-2. 다형성의 활용

다형성은 객체의 형변환으로 이해하면 쉽다. 

 

업캐스팅 : 자식 타입 객체를 부모 타입 객체에 선언하여 자동으로 형변환 하는 방법.

다운캐스팅 : 업캐스팅된 객체를 다시 자식 타입으로 형변환하여, 자식 메소드를 사용하는 방법.

class Person {
	// 코드들...
}

class Student extends Person {
	// 코드들...
	public void study() {
		System.out.println("공부중");
	}
}

public class Inheritance {
	public void method() {
		Person ps = new Student();//업캐스팅 : 부모 타입으로 자식 타입 받기. 자동형변환
		((Student)ps).study();//다운캐스팅 : 자식 메소드를 사용하려면 형변환이 필요하다.
	}
}

Ⅴ. 추상클래스와 인터페이스

5-1. 추상클래스

현재 클래스가 미완성임을 명시하는 방법. 추상메소드를 포함하지 않아도 추상 클래스로 생성할 수 잇다.

하지만 추상 메소드를 포함하는 클래스는 무조건 추상클래스로 작성해야한다.

자식 메소드가 추상메소드 상속 시 반드시 추상 메소드를 구현해야한다.

 

선언할 때, 접근제한자와 class 사이에 abstract를 기술한다.

public abstract class Student{
	//코드들
}

5-1-1. 추상메소드

미완성 메소드. 선언할 때 abstract를 기술한다.

{} 사이에 코드를 기술하던 것과 달리, 바디 부분 없이 ;로 변수처럼 끝맺음한다.

public abstract void studyMath();

5-1-2. 주의사항

추상은 외부에서 상속받아 수정해야하므로 다음과 같은 제약조건이 있다.

  1. 추상 클래스의 경우 해당 자료형으로는 객체를 생성할 수 없다.
  2. 클래스에 final이 붙은 경우 클래스를 상속-수정할 수 없으므로, 추상 클래스가 될 수 없다.
  3. 메소드의 접근 제한자에 private가 있는 경우 외부에서 받을 수 없으므로, 추상메소드가 될 수 없다.
  4. static이 있는 경우 프로그램 시작과 동시에 static에 생성되므로, abstract는 static을 사용할 수 없다.

 


5-2. 인터페이스

인터페이스 = 상수 필드 + 추상 메소드

 

추상 메소드만을 모아놓기 위해 만드는 것으로 다중 상속이 가능하다. 

인터페이스를 적용하는 경우, implements로 표현한다.

인터페이스의 모든 메소드는 public abstract, 모든 변수는 public static final임을 약속했다.

이를 JVM이 자동 계산하므로, 생략 가능하다.

public interface InterfaceTest {
	public static final int weight = 10;
	/* public static final */ int height = 10;

	public abstract int calcArea();

	/* public abstract */int calcPerimeter();
}

interface InterTest {
	//코드들...
}

class Complete implements InterfaceTest, InterTest {
	public int calcArea() {
		return weight * height;
	}

	public int calcPerimeter() {
		return (weight + height) * 2;
	}
}

※주의사항

상속 시 인터페이스 내에 정의된 모든 추상메소드를 구현해야한다.

객체를 생성할 수는 없지만, 다형성을 적용한 참조형 변수(자료형)로는 가능하다.


Ⅵ. 예외처리

6-1. 예외처리란?

에러가 발생할 때, 개발자가 코드로 오류를 잡을 수 있는 경우를 예외라고 한다.

이 때 코드 수정으로 예외를 배제하는 것을 예외처리라고 한다.

에러 종류 오류 사항 처리 방법
컴파일 에러 문법 에러 예외 (Exception) 처리
런타임 에러 예상 가능한 에러
시스템 에러 컴퓨터 오작동 수리가 필요.

6-2. 예외처리 방법

6-2-1. try catch

try{
	//예외가 생길수도 있는 코드들 
}catch(Exception e){
	//예외가 생겼을 경우 처리하는 코드들
}finally{//finally는 생략 가능하다.
	//예외가 생기든 안생기든 무조건 실행해야하는 코드들
}

※주의사항 : 오버라이딩하는 자식클래스의 예외처리 범위는 부모클래스보다 작아야한다.

try 에서 오류가 발생하면 그 아래 코드들은 전부 패스하고 catch문으로 넘어가므로, .close() 등 반드시 필요해야하는 메소드는 finally에 넣어준다.

 

6-2-2. throws

throws IOException을 클래스 명 뒤에 붙여, 이 메소드를 호출하는 메소드에서 처리하도록 넘기기.

public class searchMem throws IOException{
	//코드들 입력
}

 

'BACK-END > Java' 카테고리의 다른 글

[JAVA] API-JDBC  (1) 2021.12.07
[Java] API-Stream(Input & Output)  (0) 2021.11.25
[Java] API-Collection과 Map  (0) 2021.11.23
[Java] API 기초와 java.lang  (1) 2021.11.22
[Java] Java의 기초 사용  (0) 2021.11.20