본문 바로가기

개발

Java - 객체지향개념

반응형

1. 객체지향 개념
 - 코드의 재사용성이 높고 유지보수가 용이 > 빠른 변화에 대응이 가능 / 중복 코드 제거
 - 객체지향언어 = 프로그래밍 언어 + 객체지향개념(규칙)

 - 객체지향 프로그래밍(OOP)
 1) 캡슐화
 2) 상속
 3) 추상화
 4) 다형성

2. 클래스와 객체 
 클래스의 정의 : 객체를 정의해 놓은 것 
 클래스의 용도 : 객체를 생성하는데 사용
 객체의 정의 : 실제로 존재하는 것. 사물 또는 개념
 객체의 용도 : 객체가 가지고 있는 기능과 속성에 따라 다름

클래스 객체
제품 설계도 제품
TV 설계도 TV
붕어빵 기계 붕어빵

객체 : HW를 SW화 한 것 
TV를 객체화 할때
객체 = 속성(변수) + 기능(메서드)
속성 : 크기, 길이, 높이, 색상, 볼륨, 채널 등  >> 변수
기능 : 켜기, 끄기, 볼륨 높이기, 볼륨 낮추기  >> 메서드

class TV{
 String color; // 색깔
 boolean power; // 전원상태
 int channel; // 채널
 
 void power(){ power = !power;}
 void channelUp(){ channel++;}
 void channelDown(){ channel--;}

}
객체 = 인스턴스

객체 : 모든 인스턴스를 대표하는 일반적 용어 
인스턴스 : 특정 클래스로부터 생성된 객체(예 : TV 인스턴스)

클래스 --(인스턴스화)--> 인스턴스(객체)

3. 하나의 소스파일에 여러 클래스 작성 
 1) 올바른 작성 예 
  - public class가 있는 경우, 소스파일의 이름은 반드시 public class의 이름과 일치해야한다. 
   Hello2.java - public class Hello2{}
                                      class Hello3{}
  - public class가 하나도 없는 경우 소스파일의 이름은 하나의 클래스 명과 같으면 된다.
   Hello2.java - class Hello2 {}
                          class Hello3 {}
  2) 잘못된 작성 예
   - 하나의 소스파일에 둘 이상의 public class가 존재하면 안된다. 각 클래스를 별도의 소스파일에 나눠서 저장하던가 아니면 둘 중 한 클래스에 public을 붙이지 말아야 한다.
     Hello2.java - public class Hello2{}
                             public class Hello3{} - X
   - 소스파일의 이름이 public class의 이름과 일치하지 않으면 안된다. 
   Hello3.java - public class Hello2{}
                                     class Hello3{} - X
 
4. 객체의 생성
 클래스명 변수명 ; 
 변수명 = new 클래스명();

 TV = t; // 참조변수 선언
 t = new TV();   // TV인스턴스 생성 후, 생성된 인스턴스의 주소를 t에 저장 
 5. 객체의 사용 
  t.channel = 7;    // 채널 번호 설정 
  t.channelDown(); // 채널 channelDown()

 

1. 변수 : 하나의 데이터를 저장할 수 있느 ㄴ공간
2. 배열 : 같은 종류의 여러 데이터를 하나로 저장할 수 있는 공간
3. 구조체 : 서로 관련된 여러 데이터(종류 관계X)를 하나로 저장할 수 있는 공간
4. 클래스 : 관련있는 데이터와 함수의 결합(구조체 + 함수)

클래스 - 사용자 정의타입 - 원하는 타입을 직접 만들 수 있다.
class Time{
int hour;
int minute;
int second;
}
Time t = new Time();
t : 0x100 ->> 0x100 (hour / minute / second)

선언위치에 따른 변수의 종류
class Variables
{
// 클래스영역 클래스 시작부터 클래스끝
int iv; // 인스턴스 변수
static int cv; // 클래스 변수(static변수, 공유변수)
// 클래스영역 클래스 시작부터 클래스끝


void method(){ // > 메소드 선언
// 메소드 정의
// 메서드영역 메서드 시작부터 메서드 끝
int lv = 0; // 지역변수
// 메서드영역 메서드 시작부터 메서드 끝
}
// 클래스영역 클래스 시작부터 클래스끝
}

클래스 변수 (cv) - 클래스영역에 선언 - 클래스가 메모리에 올라갈 때 생성
인스턴스변수 (iv) - 클래스영역에 선언 - 인스턴스가 생성되었을 때 생성
지역변수(lv) - 클래스영역 이외의 영역(메서드 생성자, 초기화 블럭내부) - 변수 선언문이 수행되었을 때

클래스 변수와 인트턴스 변수
- 개별 속성은 인스턴스 변수
- 공통 속성은 클래스 변수
예) 카드
숫자 문늬 : 개별변수
폭 높이 : 공통변수

class Card{
String kind; // 무늬
int number; // 숫자

static int width = 100; // 폭
static int height = 250; // 높이
}

Card c = new Card();
c.kind = "HEART";
c.number = 5;
Card.width = 200; // 클래스변수는 이렇게
Card.height = 300;

메서드란
1. 문장들 묶은것(작업단위)
2. 값(입력)을 받아서 처리하고, 결과를 반환(출력)
= 선언부 + 구현부

int add(int x, int y){ // 선언부
// 구현부
int result = x + y;
return result; // 결과를 반환
}
메서드의 장점
- 코드 중복을 줄일 수 있다.
- 코드의 관리가 쉽다.
- 코드를 재사용할 수 있다.
- 코드가 간결해서 이해하기 쉬워진다.

메서드 호호출
메서드이름(값1, 값2, ...); // 메서드를 호출하는 방법


return
반환타입이 void 일때는 생략 가능, 컴파일러가 자동 추가
반환타입이 void가 아닐 경우, 반드시 return문 필요


호출 스택(call stack)
메서드가 수행에 필요한 메모리가 제공되는 공간
메서드가 호출되면 호출스택에 메모리 할당, 종료되면 해제

시작 : main()
main()이 println()을 호출 : println / main()
pirntln()이 종료 : main()

아래에 있는 메서드가 위에 메서드를 호출한 것
맨 위의 메서드 하나만 실행 중, 나머지는 대기중

기본형 매개변수 - 변수의 값을 읽기만 할 수 있다.(read only)
참조형 매개변수 - 변수의 값을 읽고 변경할 수 있다.(read & write)
기본형 매개변수
void change(int x)
x = 1000
System.out.println(x)
}
>>> 호출하는 부분에서 넘긴 x 변수와 함수 안의 x값이 바뀐다 >> 호출 할때 넘기는 변수가 아니다.
WapperClass / primitive 변수는 호출할때 넘기는 변수랑 넘기기 전이랑 다른 변수다
WapperClass에서 스려면 AtomicInteger/Atomic... 

참조형 매개변수
void change(Date d)
d.x = 1000
System.out.println(d.x)
}
>> 이 함수를 호출하는 부분의 Date.x 값이 변경된다. 참조형이니께

인스턴스 메서드
- 인스턴스 생성 후, 참조변수.메서드이름()으로 호출
- 인스턴스 멤버(iv, im)와 관련된 작업을 하는 메서드
- 메서드 내에서 인스턴스 변수(iv)사용 가능

static 메서드(클래스 메서드)
- 객체생성없이 '클래스이름.메서드이름()'으로 호출
- 인스턴스 멤버(iv, im)와 관련 없는 작업을 하는 메서드 / 사용 할 수 없다.
- 메서드 내에서 인스턴스 변수(iv)사용불가

인스턴스 멤버를 사용하지 않는 메서드에 static를 붙인다.

static 메서드에서 인스턴스 메서드를 호출할 수 없다.
인스턴스 메서드에서 static 메서드를 호출할 수 있다.

오버로딩
- 한 클래스 안에 같은 이름의 메서드를 여러 개 정의하는 것
- 매개변수는 다르지만 같은 의미의 기능수행
- 조건
1. 메서드 이름이 같아야 한다.
2. 매개변수의 개수 또는 타입이 달라야 한다.
3. 반환 타입은 영향 없다.

보기 1 - 변수 이름이 다른건 아님. 중복 정의
int add(int a, int b){ return a+b;}
int add(int x, int y){ return x+y;}
보기 2 - 반환 타입은 영향이 없음. 중복 정의
int add(int a, int b){ return a+b;}
long add(int a, int b){ return (long)a+(long)b;}
보기 3 - 가능!
int add(int a, long b){ return a+b;}
long add(int a, long b){ return a+b;}
그런데?? add(3,3)으로 하면 컴파일러가 어떤거를 실행 해야 하는지 몰라서 에러난다.
add(3,3L)하던지 해야함.

생성자
- 인스턴스가 생성될 때마다 호출되는 '인스턴스 초기화 메서드'
기본생성자
- 매개변수가 없는 생성자
- 생성자가 하나도 없을 때만, 컴파일러가 자동 추가

생성자 this()
- 생성자에서 다른 생성자 호출할 때 사용
- 다른 생성자 호출시 첫 줄에서만 사용가능
class Car2{
String color;
String gearType;
int door;
Car2(){
this("white", "auto", 4);
}
Car2(String color){
this(color, "auto", 4);
}
Car2(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
}
}

참조변수 this
- 인스턴스 자신을 가리키는 참조변수
- 인스턴스 메서드(생성자 포함)에서 사용가능
- 지역변수(lv)와 인스턴스 변수(iv)를 구별할 때 사용

Car2(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
}
>> this. ~ iv 인스턴스변수
로컬변수랑 인스턴스변수랑 이름이 같아서 this로 구별해야한다.
Car2(String a, String b, int c){
color = a;
gearType = b;
door = c;
}
>> 로컬변수랑 인스턴스변수랑 이름이 달라서this를 안써도 된다.

변수의 초기화
- 지역변수는 수동 초기화 해야함(사용전 꼭!!)
- 멤버변수는(iv, cv)는 자동 초기화 된다.
class InitTest{
int x; // 자동 0으로 초기화
int y = x;

void method1(){
int i ; // 에러 초기화 해줘야한다.
int j = i ;
}
}

1. 명시적 초기화(=)
class Car{
int door = 4; // 기본형 변수의 초기화
Engine e = new Engine(); // 참조형 변수의 초기화
}
2. 초기화 블럭 - 복잡한 초기화에 사용
- 인스턴스 초기화 블럭 : { }
- 클래스 초기화 블럭 : static { }
3. 생성자 - iv 초기화, 복잡한 초기화에 사용
Car(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
}

초기화블럭
class StaticBlockTest{
static int[] arr = new int[10]; // 명시적 초기화

static { // 클래스 초기화 블럭 - 배열 arr을 난수로 채운다.
for(int i = 0 ; i < arr.length ; i++){
arr[i] = (int)(Math.random()*10)+1;
}

}
}

멤버변수의 초기화
- 클래스 변수 초기화 시점 : 클래스가 처음 로딩될 때 단 한번
- 인스턴스 변수 초기화 시점 : 인스턴스가 생성될 때마다.

7장
1. 상속
- 기존의 클래스로 새로운 클래스를 작성하는 것.(코드의 재사용)
- 두 클래스를 부모와 자식으로 관계를 맺어주는 것.
- 자손은 조상의 모든 멤버를 상속받는다.(생성자, 초기화블럭 제외)
- 자손의 멤버 개수는 조상보다 적을 수 없다(같거나 많다.)
- 자손의 변경은 조상에 영향을 미치지 않는다.
class 자식클래스 extends 부모클래스{

}


1-1 포함관계
포함이란 : 클래스의 멤버로 참조변수를 선언하는것
- 작은 단위의 클래스를 만들고, 이 들을 조합해서 클래스를 만든다. > 복잡도를 줄일 수 있다.
class Circle{
int x, y, z;
}
class Point{
int x, y;
}
class Circle{
Point c = new Point();
int r;
}

1-2 클래스 간의 관계 결정하기
상속관계 : A는 B 이다. (is-a)
포함관계 : A는 B를 가지고 있다. (has-a)

1
class Circle{
Point c = new Point():
int r;
}
2
class Cicle extends Point{
int r;
}
1> 원은 점을 가지고 있다 O
2> 원은 점이다 X
>> 원과 점은 상속관계가 아니다 포함관계다.

단일 상속
- 자바는 단일상속만을 허용한다.(C++은 다중상속 허용)
class TvDVD extends Tv,DVD// 에러!
부모 클래스에 같은 변수, 같은 메소드가 있을때 충돌이 날 수도 있어 단일 상속만 허용한다.
- 여러개 를 같이 써야 할때
비중이 높은 클래스 하나만 상속관계로 나머지는 포함관계로 한다.
class TvDVD extends Tv{
DVD dvd = new DVD();

void play(){
dvd.play();
}
....
}
Object 클래스 - 모든 클래스의 조상
- 부모가 없는 클래스는 자동적으로 Object를 상속받게 된다.
컴파일러가 알아서 추가해준다.

오버라이딩(overriding)
- 상속받은 조상의 메서드를 자신에 맞게 변경하는 것
- 내용 변경
오버라이딩의 조건
- 선언부가 조상 클래스의 메서드와 일치해야 한다.
- 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
- 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.

오버로딩 vs 오버라이딩
오버로딩 : 기존에 없는 새로운 메서드를 이름이 같게 정의하는것(new)
오버라이딩 : 상속받은 메서드의 내용을 변경하는 것(change, modify)

참조변수 super
- 객체 자신을 가리키는 참조변수. 인스턴스 메서드(생성자)내에서만 존재
- 조상의 멤버를 자신의 멤버와 구별할 때 사용

super() - 조상의 생성자 호출
- 조상의 생성자를 호출할 때 사용
- 조상의 멤버는 조상의 생성자를 호출해서 초기화
** 자손의 생성자는 본인이 선언한 거만 초기화 해야한다.
자손의 생성자에서 부모의 변수를 선언할 경우엔 super을 호출
- 생성자의 첫 줄에 반드시 생성자를 호출해야 한다.
그렇지 않으면 컴파일러가 생성자의 첫 줄에 super();을 삽입

class Point{
int x, y;

Point(int x, int y){
this.x = x;
this.y = y;
}
}

class Point3D extends Point{
int z;

Point(int x, int y, int z){
super(x, y); // 조상의 생성자 호출 이거 없으면 아래서 에러남
this.z = z;
}
}

class PointTest {
public static void main(String args[]){
Point3D p3 = new Point3D(1,2,3);
}
}


패키지
- 서로 관련된 클래스의 묶음
- 클래스는 클래스파일(*.class), 패키지는 폴더, 하위 패키지는 하위 폴더
- 클래스의 실제 이름(full name)은 패키지를 포함

클래스패스 (classpath)
- 클래스파일(*.class)의 위치를 알려주는 경로(path)
- 환경변수 classpath로 관리하며, 경로간의 구분자는 ;를 사용
환경변수에 패키지의 루트를 등록해줘야 함.

import문
- 클래스를 사용할 때 패키지이름을 생략할 수 있다.
- 컴파일러에게 클래스가 속한 패키지를 알려준다.
- java.lang 패키지의 클래스는 import 하지 않고도 사용할 수 있다.
import java.util.*; >> 컴파일시에 처리되므로 성능에 영향없다.
- 이름이 같은 클래스가 속한 두 패키지를 import 할때는 클래스 앞에 패키지명을 붙여줘야 한다.

static import문
- static 멤버를 사용할때 클래스 이름을 생략할 수 있게 해준다.
import static java.lang.Integer.*; // Integer클래스의 모든 static 메서드
import static java.lang.Math.random; // Math.random()만. 괄호 안붙임
import static java.lang.System.out; //System.out을 out으로만 참조가능
System.out.println(Math.random()); >> System.out.println(random());

제어자(modifier)
- 클래스와 클래스 멤버(멤버 변수, 메서드)에 부가적인 의미 부여
접근 제어자 public protected, (default), private
그 외 static, final, abstract, native, transient, synchronized, volatile, strictfp
- 하나의 대상에 여러 제어자 같이 사용 가능
접근제어자만 하나
public class ModifierTest{
public static final int WIDTH = 200;

}

static - 클래스의, 공통적인
대상 멤버변수 일때
모든 인스턴스에 공통적으로 사용되는 클래스 변수가 된다.
클래스 변수는 인스턴스를 생성하지 않고도 사용 가능하다.
클래스가 메모리에 로드될 때 생성된다.
매서드 일때
인스턴스를 생성하지 않고도 호출이 가능한 static메서드가 된다.
static메서드 내에서는 인스턴스멤버들을 직접 사용할 수 없다.

final - 마지막의, 변경될 수 없는
대상 클래스 일 때
변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다.
그래서 final로 지정된 클래스는 다른 클래스의 조상이 될 수 없다.
메서드 일 때
변경할 수 없는 메서드, final로 지정된 메서드는 오버라이딩을 통해 재정의 될 수 없다.
멤버변수/지역별수 일 때
변수 앞에 final이 붙으면, 값을 변경할 수 없는 상수가 된다.

abstract - 추상의, 미완성의, 추상화
클래스 일 때
클래스 내에 추상 메서드가 선언되어 있음을 의미한다.
메서드 일때
선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알린다.
추상클래스 - 추상메서드를 가지고 있는 클래스, 설계도
추상클래스를 상속 받아서 클래스를 구현해야한다.

접근제어자
private
default
protected
public

캡슐화와 접근 제어자
접근 제어자를 사용하는 이유
- 외부로부터 데이터를 보호하기 위해서
- 외부에서는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서
get set 메소드를 이용해 외부에서 직접 접근하는 것을 막는다.

다형성(polymorphism)
- 여러 가지 형태를 가질 수 있는 능력
- 조상 타입 참조 변수로 자손 타입 객체를 다루는 것

class Tv{
..
}
class SmartTv extends Tv{

}

Tv t = new SmartTv();
- 객체와 참조변수의 타입이 일치 하지 않을 때의 차이?
Tv t = new SmartTv(); // Tv에 잇는 기능만 사용가능 SamrtTv에만 있는 기능은 사용 불가
Smart t = new SmartTv(); // SmartTV에 있는 모든 기능 사용가능
Smart t = new Tv(); // 안됨

참조변수의 형변환
- 사용할 수 있는 멤버의 갯수를 조절하는 것
- 조상 자손 관계의 참조변수는 서로 형변환 가능 ****

class Car{
..
}
class FireEngine extends Car{

}

FireEngine f = new FireEngine();
Car c = (Car)f; // OK. 조상인 Car 타입으로 형변환 // Car 에 있는 기능만 사용 가능
FireEngine f2 = (FireEngine)c; // OK. 자손인 FireEngine타입으로 형변환
// f, c, f2 모두 하나의 객체를 가리킨다. 리모콘을 변경 하는것 처럼
Ambulance a = (Ambulance)f; // 에러. 상속관계가 아닌 클래스간의 형변환 불가


instanceof 연산자
- 형변환 가능여부 확인에 사용. 가능하면 true 반환
조상<>자손
- 형변환 전에 반드시 instanceof로 확인해야 함.
void doWork(Car c){
if(c instanceof FireEngine){ // 1. 형변환이 가능한지 확인
FireEngine fe =(FireEngine)c; // 2. 형변환
fe.water();
...
}
}

매개변수의 다형성
- 다형적 매개변수
- 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다.
** 다형성
1. Tv t = new SmartTv();
2. 참조변수의 형변환
3. instanceof 연산자 : 형변환 가능 여부 체크
class Product{
int price; // 제품가격
int bonusPoint; // 보너스점수
}

calss Tv extends Product{}
calss Computer extends Product{}
calss Audio extends Product{}

void buy(Product p){ // 매개변수의 타입을 부모타입으로 하여 각각 따로 구현하지 않아도 된다.
money -= p.price;
bonusPoint -= p.bonusPoint;
}

다형성 장점
- 다형적 매개변수
- 하나의 배열에 여러 종류 객체 저장

여러 종류의 객체를 배열로 다루기
- 조상타입의 배열에 자손들의 객체를 담을 수 있다.
Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();

Product p = new Product();
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();

추상클래스(abstract class)
- 미완성 설계도. 미완성 메서드를 갖고 잇는 클래스
- 상속을 통해 추상 메서드를 완성해야 인스턴스 생성 가능
- 꼭 필요하지만 자손마다 다르게 구현될 것으로 예상되는 경우

abstract class Player { // 추상클래스(미완성 클래스)
abstract void play(int pos); // 추상메서드(몸통이 없는 미완성 메서드)
abstract void stop(); // 추상메서드
}

class AudioPlayer extends Player{
void play(int pos){};
void stop(){};
}

// 일부만 구현
// 부모에 있는 stop은 구현하지 않았으므로 추상 클래스로 만들어야 한다.
abstract class AbstractPlayer extends Player{
void play(int pos){}
}

//
abstract class Player { // 추상클래스(미완성 클래스)
boolean pause; // 일시정지 상태를 저장하기 위한 변수
int currentPos; // 현재 Play 되고 있는 위치를 저장하기 위한 변수

Player(){
  pause = false;
  currentPos = 0;

  /* 지정된 위치(pos)에서 재생을 시작하는 기능이 수행하도록 작성되어야 한다. */
  abstract void play(int pos);
  /* 재생을 즉시 멈추는 기능을 수행하도록 작성되어야 한다. */
  abstract void stop();

  void play(){
  play(currentPos); // 추상메서드를 사용할 수 있다.
  }
}

반응형

'개발' 카테고리의 다른 글

Java - 인터페이스  (0) 2021.06.05
Java - 추상클래스  (0) 2021.06.05
Java - 배열  (0) 2021.05.10
Java - 변수  (0) 2021.05.05
Java  (0) 2021.05.05