객체지향프로그래밍(OOP) 기본 개념은 프로그램들이 길어지고 복잡해지면 변수도 많아지게 되고, 코드 또한 길어져서 해석을 할 때 시간이 오래 걸린다.
그래서 동일한 목적이나 기능을 하는 변수와 함수들을 각각 하나로 묶어서 객체를 만들고, 그 객체들끼리 상호 통신을 하면서 프로그램 전체가 잘 돌아갈 수 있도록 코드를 구성하는데 이것을 바로 객체지향 프로그래밍이다. 다시 말해 “객체를 각각의 기능으로 나눠서 필요할 때 객체를 생성하여 사용한다.” 라고 보면 된다.
절차지향프로그래밍은 수차적인 처리를 중요시 하며, 프로그램 전체가 유기적으로 연결이 되도록 만든 프로그래밍이다. 절차적 프로그래밍 언어는 시간에 흐름에 따라 코드를 작성한다.
차이점을 보자 하면, 객체지향은 말 그대로 객체 중심으로 프로그래밍 하고, 절차지향은 순차적인 중점인 프로그래밍인 것이라고 할 수 있다.
class Car{
String name;
String color;
int speed;
public void speedUp(){
speed++;
}
public void speedDown(){
speed--;
}
}
pubilc class CarTest{
public static void main(String[] args){
Car car=new Car();
}
}
❗️파일이름과 동일한 이름의 클래스선언에만 public 접근 제한자를 붙일 수 있다.
데이터와 함수의 결합
사용자 정의 타입(User-defined type)
프로그래머가 서로 관련된 변수들을 묶어서 하나의 타입으로 새롭게 정의하는 것을 의미한다.
class Time{
int hour;
int minute;
int second;
}
위와 같은 Time 클래스가 있다.
int hour1, hour2, hour3;
int minute1, minute2, minute3;
int second1, second2, second3;
Time time1=new Time();
Time time2=new Time();
Time time3=new Time();
3개의 시간을 다뤄야할 때 시간, 분, 초 변수를 각각 3개씩 총 9개의 변수를 사용하지 않고 Time 클래스를 이용하면 3개의 참조형 변수만 사용하면 된다.
클래스에 의해 만들어진 객체를 인스턴스라고 한다.
Car car = new Car();
객체는 속성과 기능으로 구성된다. 속성과 기능을 객체의 멤버(member)라고 한다.
클래스를 정의할 때 객체의 속성은 변수(variable), 기능은 메서드(method)로 정의한다.
class Car{
String name;
String color;
int speed;
public void speedUp(){
speed++;
}
public void speedDown(){
speed--;
}
}
➡️ 속성은 name, color, speed이고 기능은 speedUp과 speedDown이다.
인스턴스 생성방법
클래스명 참조변수명; //객체를 다루기 위한 참조변수 선언
참조변수명 = new 클래스명(); //객체 생성 후, 생성된 객체의 주소를 참조변수에 저장
Car car;
car = new Car();
Car car=new Car();
➡️ new에 의해 Car 클래스의 인스턴스가 메모리의 빈 공간에 생성된다. 이 때, 멤버변수는 각 자료형의 해당하는 기본값으로 초기화된다. 참조변수 car를 이용해 Car 인스턴스에 접근할 수 있다.
❗️참조형 변수
인스턴스 사용
Car car=new Car();
car.name="자동차"; //참조변수 car에 저장된 주소에 있는 인스턴스의 멤버변수 name에 자동차 저장한다.
car.speed=60; //참조변수 car에 저장된 주소에 있는 인스턴스의 멤버변수 speed에 60을 저장한다.
car.speedUp(); //참조변수 car가 참조하고 있는 인스턴스의 speedUp 메소드 호출한다.
Car car1=new Car();
Car car2=new Car();
car2=car1; //car1의 주소를 car2에 저장
car1.name="자동차";
car1.speed=60;
System.out.println("car2의 speed는 "+car2.speed);
System.out.println("car1의 speed는 "+car1.speed);
car1.speedUp();
System.out.println("car2의 speed는 "+car2.speed);
System.out.println("car1의 speed는 "+car1.speed);
car2.speedDown();
System.out.println("car2의 speed는 "+car2.speed);
System.out.println("car1의 speed는 "+car1.speed);
[출력]
car2의 speed는 60
car1의 speed는 60
car2의 speed는 61
car1의 speed는 61
car2의 speed는 60
car1의 speed는 60
메서드
란, 작업을 수행하기 위한 명령문의 집합. 어떤 값을 입력받아서 처리하고 그 결과를 반환한다. 경우에 따라서는 입력받는 값이 없을 수도 있으며 결과를 반환하지 않을 수도 있다.
반환타입 메서드이름 (타입 변수명, 타입 변수명, ... ) //선언부
{ //구현부
// 메서드 호출 시 수행될 코드
}
int add (int a, int b) //선언부
{ //구현부
int result = a + b;
return result; //호출한 메서드로 결과를 반환한다.
메서드의 선언부는
메서드의 이름
과매개변수 선언
, 그리고반환타입
으로 구성되어 있다.
,
를 사용한다. int add(int x, int y { ... }
int add(int x, y). { ... } //에러. 매개변수 y의 타입이 없다.
반환값(return value)
의 타입을 적는다. 단, 반환값이 없는 경우 반환타입으로 void
를 적어야 한다.메서드의 선언부 다음에 오는 괄호
{ }
를 ‘메서드의 구현부’라고 하는데, 여기에 메서드를 호출했을 때 수행될 문장들을 넣는다.
현재 실행 중인 메서드를 종료하고 호출한 메서드로 되돌아간다
반환타입과 일치하거나 적어도 자동 형변환이 가능한 것
이어야 한다.반환값이 있는 메서드는 모든 경우에 return문이 있어야 한다
return문의 개수는 최소화시키는 것이 좋다
메서드 내에 선언된 변수
- 메서드 내에 선언된 변수들은 그 메서드 내에서만 사용할 수 있으므로 서로 다른 메서드라면 같은 이름의 변수를 선언해도 된다.
- 매개변수도 메서드 내에 선언된 것으로 간주되므로 지역변수이다.
int add (int x, int y) {
int result = x + y;
return result;
}
int multiply (int x, int y) {
int result = x * y;
return result;
}
메서드를 구현 해도
호출
되지 않으면 아무 일도 일어나지 않는다. 메서드를 호출해야만 구현부 { } 의 문장들이 수행된다. (main 메서드는 프로그램 실행 시 os에 의해 자동적으로 호출됨)
- 메서드의 호출 방법
참조변수 . 메서드 이름 (); // 메서드에 선언된 매개변수가 없는 경우
참조변수 . 메서드 이름 (값1, 값2, ... ); // 메서드에 선언된 매개변수가 있는 경우
print99danA11(); // void print99danA11()을 호출
int result = add(3, 5); // int add(int x, int y)를 호출하고, 결과를 result에 저장
( )
안에 지정해준 값들을 의미한다. 인수의 개수와 순서는 호출된 메서드에 선언된 매개변수
와 일치해야 한다.타입과 일치
하거나 자동 형변환
이 가능해야 한다.int result = add(1, 2, 3); // 컴파일 에러. 메서드에 선언된 매개변수의 개수가 다름
int result = add(1.0, 2.0); // 메서드에 선언된 매개변수의 타입이 다름
아래는 두 개의 값을 매개변수로 받아서 사칙연산을 수행하는 4개의 메서드를 가진 MyMath 클래스를 정의한 것이다
class MyMath {
long add(long a, long b) {
long result = a + b;
return result;
// return a + b; // 위의 두줄을 이와 같이 한 줄로 간단하게 할 수 있다.
}
long subtract(long a, long b) { return a - b; }
long multiply(long a, long b) { return a * b; }
long divide(double a, double b) { retrun a / b; }
}
가장 쉬운 예로 자바에는 System.out.println() 이라는 출력 메소드가 존재한다.
➡️ 위 메소드에 int 타입을 매개변수로 주든, String 타입을 매개변수로 주든 모두 동일하게 System.out.println() 이라는 메소드를 호출
public class Example {
public static void main(String[] args) {
Example ex = new Example();
ex.overloadingEx();
ex.overloadingEx(10);
ex.overloadingEx(10, 20);
ex.overloadingEx(10, 3.14);
}
void overloadingEx() {
System.out.println("컬러풀 라이언");
}
void overloadingEx(int i) {
System.out.println(i);
}
void overloadingEx(int x, int y) {
System.out.println(x+y);
}
void overloadingEx(int i, double d) {
System.out.println(i+d);
}
}
overloadingEx()
라는 이름의 메소드가 4개를 사용한다.//생성자 예제
class Pizza{
int size;
String type;
public Pizza() {
size = 12;
type = "슈퍼슈프림";
}
public Pizza(int s, String t) {
size = s;
type = t;
}
}
public class PizzaTest {
public static void main(String[] args) {
Pizza obj1 = new Pizza();
System.out.println("("+obj1.type+", " + obj1.size+ ",)");
Pizza obj2 = new Pizza(24, "포테이토");
System.out.println("("+obj2.type+", " + obj2.size+ ",)");
}
}
class Car{
String color;
String gearType;
int door;
Car(){
this("white", "auto", 4); // 순서대로 각 변수의 값을 입력하는 것과 같습니다.
}
Car(String c, String g, int d){
color = c;
gearType = g;
door = d;
}
}
class BankAccount{
int balance;
public BankAccount() { // 컴파일러에 의해 자동 삽입되는 디폴트 생성자입니다.
//empty
}
public int deposit(int amount) {...}
public int withdraw(int amount) {...}
public int checkMyBalance(int amount) {...}
}
class Car{
String color;
String gearType;
int door;
Car() {
this("white", "auto", 4);
}
Car(String color, String gearType, int door){
this.color = color; // 인스턴스 변수와 지역변수를 구별하기 위해 참조변수 this를 사용합니다.
this.gearType = gearType;
this.door = door;
}
}
✅ 멤버변수 vs 지역변수
변수는 선언 위치에 따라 나누면 지역변수와 멤버변수로 구분할 수 있다.
‣ **멤버변수** : 클래스 영역에 선언
‣ **지역변수** : 메소드나 생성자 내부 선언, 메소드가 종료되면 자동으로 소멸
**멤버변수**는 다시 **클래스 변수**와 **인스턴스 변수**로 나눌 수 있다.
‣ **클래스 변수** : 모든 객체가 공통적으로 똑같은 속성을 가질 때 사용한다.
‣ **인스턴스 변수** : 각각의 객체(=인스턴스)마다 개별적인 속성을 가져야 할 때 사용한다.
class InitClasee{
int x; //**멤버변수**-인스턴스 변수
int y = x; //**멤버변수**-인스턴스 변수
void method(){
int i; //**지역변수**
int j = i; //**컴파일 에러!** -> 지역변수가 초기화되지 않음!
}
}
1. 명시적 초기화 (explicit initialization)
class Car {
int door = 4; //기본형 변수의 초기화
Engine e = new Engine(); //참조형 변수의 초기화
}
2. 생성자 (constructor)
Car(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
}
3. 초기화 블럭 (initialization block)
class InitBlock {
static {/* **클래스 초기화블럭** */}
{/* **인스턴스 초기화블럭** */}
}
class StaticBlockTest {
static int[] arr = new int[10]; // **명시적 초기화**
static { // **클래스 초기화블럭**
for (int i=0; i<arr.length; i++){
arr[i] = (int)(Math.random() * 10) + 1;
}
}
}
[출처]
자바의 정석-https://www.youtube.com/playlist?list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp