11 minute read




클래스와 객체 기본 개념

클래스, 객체, 인스턴스

[ 클래스(Class) ]

(1) 새로운 자료형(data type)의 정의: a complex data type, 참조 자료형
(2) 객체(objext)의 속성, 특성, 기능/행위를 정의하는 논리적 구조

• 객체지향 프로그래밍의 기반: 객체의 설계도(틀, template, design)
• 속성을 표현하는 변수들과 기능을 표현하는 메소드들을 캡슐화(encapsulation)
• 구성

분류 내용
필드 = 멤버 변수(member variables) 클래스 내부에 선언되는 데이터 저장 공간
• class var: static(선언)/class-wide-global(클래스 전체 공유), 전역
• instance var: Local (객체 안, within an object), 객체마다 따로 존재
메쏘드(methods) = 멤버 함수(member functions) • 클래스 내부의 기능(동작)을 정의
• 클래스 안에서 정의되는 함수로, 멤버 변수에 접근하거나 동작을 수행

참고 멤버변수와 메서드들은 공개(public)혹은 비공개(private)로 선언 가능

public class Player {
    private int age;       // private 멤버 변수
    public String name;    // public 멤버 변수

    public int getAge() {  // public 메서드
        return age;
    }
}


[ 인스턴스(instance) ]
• 객체 클래스 기반으로 생성된 모든 실체, 실제 메모리에 존재하는 것
• 인스턴스: 어떤 클래스의 구체적인 예

class Dog {
    String name;
}

public class Main {
    public static void main(String[] args) {
        Dog d = new Dog();
    }
}

//클래스: Dog
//객체: d
//d: Dog 클래스의 인스턴스 d


[ 객체(Object) ]

특징(속성, variable)과 동작(기능, method)의 조합체
• 메모리 할당을 받는 실체: instance(인스턴스)
• 프로그램 실행 중에 생성되는 실체



객체지향 프로그래밍(object-oriented programming (OOP))

[ 객체지향 프로그래밍의 정의 ]

특징(속성, variable)과 동작(기능, method)의 조합체
클래스집합(= program)설계하는 작업
• 컴퓨터 수행작업을 객체들 사이상호작용(msg 전달)으로 표현


[ 객체지향 프로그래밍의 특징 ]
캡슐화 (Encapsulation)

information hiding(정보은닉)
• 정보 가시성/접근 지정: 변수나 메서드의 가시성(visibility)를 제어해서 외부 객체에서 볼 수 있게 하거나, 보이지 않게 감출 수 있음
• 클래스 설계시 가능: Class design -> encapsulation of information

// 정보 공개
public variables
public functions

// 정보 은닉(information hiding)
private variables
private functions

상속 (Inheritance)

기존 클래스를 기반으로 새로운 클래스를 만들 수 있음

다형성 (Polymorphism)

같은 이름의 메서드가 다양한 동작을 할 수 있음 (오버로딩, 오버라이딩)

추상화 (Abstraction)

중요한 부분만 공개하고, 복잡한 내부는 감춤 (interface, abstract class 등)




객체 생성과 초기화

생성자(Constructor)

[ 정의 ]

객체생성과(instantiation, by new) 초기화(initialization) 수행하는 특별한 메쏘드

• 생성자 이름 = 클래스 이름
• return value/type 지정 불필요
• 초기화: 멤버 변수 선언 시 class default 지정 / 미지정 시 default = 0

double weight = 430; // soccer ball’s
int x; // = 0 by default (숫자형)

• Default Constructor(기본 생성자): 별도의 생성자가 없을 때(하나도!! 없을 때) 컴파일러가 자동 생성

public class Book {
    String title;
    String author;

    /* 컴파일러가 기본생성자를 만들어 줌
    public Book(){	
        super();	//Object 클래스의 생성자 호출
    }
    */
}

/*기능
1) 빈 객체 생성 - 값은 나중에 할당
2) 기본값을 가진 상태로 객체 생성 후 수정
3) 해당 객체 타입 배열을 생성할 때 내부적으로 기본 생성자가 필요함
*/
Book b = new Book();	//직접 멤버변수 값을 지정할 수는 없음
b.title = "어린왕자";		//객체 생성 후 수동으로 값 할당은 가능
b.author = "생택쥐페리";

[ 생성자 사용 예시 ]
생성자 체이닝

하나의 생성자 안에서 자기 클래스의 다른 생성자를 호출하는 것: by this(...)
• 생성자끼리만 호출 가능
• 반드시 생성자의 첫 줄에 있어야 함: 실행 순서상 생성자 체이닝에서 사용하는 생성자가 먼저 생성되어야 함
this()super()는 동시에 못 씀

class Box {
    double width; // 멤버 변수, (0 초기화)
    double height;
    double depth;
    default size

    Box() {
        width = height = depth = 10;
    }
    Box(int x) { 
		// 생성자 체이닝, 자동 형변환(int -> double)
		//this: 나의 참조변수 or 나의 생성자 호출(아래 box 호출-파라미터의 수를 맞춰서)
		this(x, x, x); 	
	}   
    Box(double w, double h, double d) {
        width = w; height = h; depth = d;
    }
}

// 다른 클래스
Box a = new Box();
Box b = new Box(10);
Box c = new Box(10, 20, 30);
public class Book {
    String title;
    String author;

    //생성자 중복
    public Book(String t) { // 생성자 1
        title = t; author = "작자미상"; // 변수 초기화
    }

    public Book(String t, String a) { // 생성자 2
        title = t; author = a; // 변수 초기화
    }

    public static void main(String [] args) {
        Book littlePrince = new Book("어린왕자", "생텍쥐페리");// --> 생성자 2 호출
        Book loveStory = new Book("춘향전");            // --> 생성자 1 호출
        System.out.println (littlePrince.title + " " + littlePrince.author);
        System.out.println (loveStory.title + " " + loveStory.author);
    }
    }



접근제어자

[ 정의 ]

클래스의 멤버(변수, 메서드 등)에 접근할 수 있는 권한을 제어하는 도구

접근제어자 같은 클래스 같은 패키지 하위 클래스 외부
public
protected
(defalt)
private

public
• 완전 공개
• 어디에서든 접근 가능 (같은 클래스, 패키지, 하위 클래스, 외부 클래스)
• 자주 쓰는 곳: main() 메서드, 라이브러리 API

protected
• 상속 중심 보호
• 같은 패키지 + 다른 패키지의 하위 클래스에서 접근 가능
• 주로 상속받는 클래스에서 사용함

(default)
• 패키지 전용
• 접근 제어자를 아예 안 쓰면 default로 간주
• 같은 패키지 안에서만 접근 가능
• 외부 클래스나 다른 패키지에서는 접근 불가

private
• 완전 감춤
• 같은 클래스 내부에서만 접근 가능
• 외부, 하위 클래스에서도 절대 접근 불가
• 주로 멤버 변수에 사용해서 정보 은닉



this, super

[ this 키워드 (자기 참조) ]
• this.* : 명시적 self-reference (자기 참조, 자기 지칭)
👉 어디서든 사용 가능(메서드나 생성자 내부 등)
• this(…) : 생성자 내부에서 처음(first) 에만 호출 가능
👉 다른 생성자를 호출할 때 사용

[ super 키워드 (상위 클래스 참조) ]
• super.* : parent class reference (상위 클래스 객체 참조)
• super(…) : 생성자 내부에서 처음(first) 에만 호출 가능
👉 생성자 안의 첫 문장에서만 사용 가능

// super (상위 클래스) 참조 
// - 오버라이딩(대체)된 상위 클래스의 메서드나 변수에 접근할 때 사용
// - 서브클래스 내부 어디에서든 호출 가능
super.methodname(args);   // 상위 클래스의 메서드 호출
super.studentYear;        // 상위 클래스의 변수 접근

// 상위 클래스 생성자 호출
// - 서브클래스 생성자 내부에서만 사용 가능
// - 반드시 첫 번째 줄에 위치해야 함
super(args);   // 생성자 호출
public class Balloon {
    private int diameter;
    protected int x, y; // accessible from subclasses
    public boolean bouncing;

    public Balloon(int d, int x, int y) {
        diameter = d;
        this.x = x; // 변수 이름이 같을 때 구분하기 위해
        this.y = y;
        this.changeSize(1); // “this.” 없어도 된다
    }
    public void changeSize(int deltaR) {
        diameter += deltaR;
    }
}

class SomeClass { 
	Balloon b = new Balloon(10, 0,0);
	b.diameter = 15; // ( X - error )
	b.changeSize(5); // (o)
}

public class Book {
    String title;
    String author;
    public Book(String t) { // 생성자 1
        this(t, "작자미상"); // 다른 중복 생성자 호출
    }

    public Book(String t, String a) { // 생성자 2
        title = t; author = a; // 변수 초기화
    }
    public static void main(String [] args) {

        Book littlePrince = new Book("어린왕자", "생텍쥐페리");
        Book loveStory = new Book("춘향전");
        System.out.println (littlePrince.title + " " + littlePrince.author);
        System.out.println (loveStory.title + " " + loveStory.author);
    }
}




메서드 오버로딩

[ 메서드 오버로딩(Method Overloading) 개념 ]

이름은 같지만, 매개변수의 수나 타입이 다른 두 개 이상의 메소드를 정의하는 것
• 반환형의 타입은 동일해야 함
• 다형성(polymorphism, 하나의 객체가 여러 모습으로 동작)을 실현하는 방법

public class Book {
    String title;
    String author;

    public Book(String t) {           // 생성자 1
        title = t;
        author = "작자미상";
    }

    public Book(String t, String a) { // 생성자 2 -> 오버로딩
        title = t;
        author = a;
    }
}
//Animal.java
public class Animal {
    String name, ;
    public void set (String name, String color) {
        this.name = name;  = color;
    }
    public void setName (String name) { }
    public void set (String sack) {  }
    }

Animal a = new Animal();
a.set(Micky, black);
a.set(gray);

• 생성자 오버로딩과의 차이

Box (double w, double h, double d) {}
Box () {}
Box (double lne) {}

Box a = new Box();
Box b = new Box(2.0, 3, 4);
Box c = new Box(10);




인자 전달 방식

메소드의 형식 매개변수(formal parameter)에 실제 인자(actual argument)를 전달하는 것

[ Call-by-Value ]

값에 의한 호출
• 실인자의 값을 (복사하여) 전달한다/넘긴다
• 복귀했을 때 실인자 값은 변치 않는다
• built-in type data : primitive type

public class CBV { 
    public static void main(String a[]) { 
        Value obj = new Value();
        int a = 10;
        System.out.println(a); // -> output: 10
        obj.treat(a); 			// a = 실(제)인자
        System.out.println(a); // -> output: 10
    }
}
class Value {
    void treat(int n) { // a copy is transferred
        n++; // n = 형식인자, n은 그냥 버린다
    }
}

[ Call-by-Reference ]

참조에 의한 호출
• 참조reference를 전달한다
• 실인자의 내용이 변한다/변할 수 있다

public class CBR{
    public static void main(String a[]) { 
        Ref obj = new Ref(10); 
        System.out.println(obj.x); // -> output: 10
        obj.treat(obj); // 참조를 전달
        System.out.println(obj.x); // -> output: 11
    }
}
class Ref {
    int x;
    Ref(int x) { this.x = x; } 
    void treat(Ref that) { // a copy of reference ¹ 	object
        that.x ++;
    }
}




정적 멤버 (Static)

[ static members ]

특정 객체와 무관한, 일종의 전역 변/함수
• 객체(instance)가 아니라, 클래스 자체에 속함
• variables/methods common to all objects of a class
• 종류: class variables, class methods

구분 내용
static variables 사본 없음->같은 타입의 모든 객체가 공유
• global variables, not duplicated/copied
• object instances share them
static methods 객체 없이도, 클래스 이름으로 호출가능
used without object instantiation
1) can invoke only other static methods
2) can access only static variables
3) cannot use this/super

[ 왜 static이 필요한가? ]
• 여러 객체가 같은 값을 공유해야 할 때
• 객체 없이도 사용할 수 있음: Math.PI, Math.square(5)
• 메모리 절약: 객체마다 따로 복사할 필요 없이, 딱 1개만 메모리에 존재함

[ 예시 ]

double y = Math.sqrt(2);	//-> y = 1.414…
String z = Integer.toString(255);	//-> z = “255”
System.out.println("abs value is = " + Math.abs(-5));

final 의미, extends 의미
public final class Math extends Object {
    static double E = 2.71828;
    static double PI = 3.1415;
    static double abs(double a) {  }
    static double random(double a) {  }

}
public class Calcs {
    public static int magic = 20;
    public static int sum (int x, int y) {
        return x + y;
    }
    public int getMagic() { 
        return magic; 
    }
}

int c = Calcs.sum(5, Calcs.magic);
int d = Calcs.getMagic(); // error -> ?




중첩 클래스 (Nested Class)

정의

class 안에 class를 정의한 것, 클래스 안에 선언된 또 다른 클래스
• nested class(내부)는 외부 class의 범위 안에서만 유효
• 내부클래스는 외부클래스의 모든 변수에 접근 가능
• 외부클래스는 내부클래스의 멤버에는 접근할 수 없음


중첩 클래스 사용이유(Compelling reasons)

(1) 한 곳에서만 사용되는 클래스들을 논리적으로 그룹화(logically grouping)하는 방법
• 특정 다른 클래스에만 유용하다면 논리적인 선택이다
• 일종의 “보조 클래스(helper classes)” 같은 것
• 그리고 코드를 더 간결하게 만든다
(2) 캡슐화(encapsulation)를 향상
• 외부 세계로부터 숨겨진다 (Hidden from the outside world)
(3) 더 읽기 쉽고 유지보수 가능한(readable and maintainable) 코드로 이어질 수 있다
• 관련된 작은 클래스들을 그들이 필요한 곳 근처에 배치할 수 있다


중첩 클래스의 유형

[ static nested class/interface = top-level class/interface ]

[ non-static nested class = inner class ]
• member class: 클래스 안에 선언된 내부 클래스
• local class
• anonymous class

종류 선언위치 static 여부 사용 조건
Static Nested Class 클래스 내부 ✅ static 외부 객체 없이 생성 가능
Member Class 클래스 내부 ❌ non-static 외부 객체 필요
Local Class 메서드 내부 ❌ non-static 지역 범위 내에서만 사용
Anonymous Class 메서드 내부 ❌ non-static 이름 없이 즉석에서 생성, 주로 일회용


[ Static Nested Class ]
• 외부 클래스와 덜 밀접한 관계일 때 사용
• 내부에 있지만 밖에 있어도 상관없음(외부 클래스의 인스턴스 없이 생성 가능)
• static으로 선언된 중첩 클래스

class OuterClass {

    static int num1;
    int num2;

    //정적 중첩 클래스
    static class StaticNestedClass {	
        //num1에는 접근 가능
        System.out.println(num1);

        //num2에는 불가능 > 인스턴스 생성 후 가능
        OuterClass outer = new OuterClass();  // 외부 인스턴스 생성
        System.out.println(outer.num2);       // 이제 접근 가능
    }
}

// Usage: 외부객체 없이 new로 직접 생성 가능
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

[ Member Class - 멤버 클래스 (non-static) ]
• 외부 클래스의 인스턴스가 있어야 생성 가능
• 외부 클래스의 모든 멤버(심지어 private도!) 접근 가능
• non-static 이기 때문에 외부 인스턴스에 종속됨

//(2) member class – a member
class OuterA {
    int outX = 10;

    void test() {
        InnerB in = new InnerB();	//내부 클래스 생성
        in.innerDisplay();			//내부 메서드 호출
    }
    class InnerB { // 멤버 클래스
        int inX = 11;
        void innerDisplay() {
            System.out.println(InnerB: outX =  + outX);
        }
    }
}

//
OuterA outerObject = new OuterA();
OuterA.InnerB innerObject = outerObject.new InnerB();

[ Local Class - 지역 클래스 (메서드 안에서 선언) ]
• 메서드 내부에서 선언되는 클래스
• 클래스 정의와 사용이 지역적으로 이뤄짐
• 주로 임시로 필요한 클래스, 캡슐화 강화

class Outer {
    int i = 100; // 비-정적 멤버 변수
    static void classMethod() { // 정적 메쏘드
        final int el = 200;
        class LocalInStaticContext { // local
            int k = i; // compile-time error
            //i는 인스턴스 변수로 객체가 있어야 접근 가능
            //int k = outer.i;
            int m = el; // ok

    }
    }
    // 지역 클래스
    void foo() {
        class LocalNonStatic { // a local class
            int j = i;
        }
    }
}

/*
javac--
Outer.class
Outer$1LocalInStaticContext.class
Outer$1.LocalNonStatic.class
*/

[ Anonymous Class — 익명 클래스 ]
• 이름 없는 일회용 클래스
• 인터페이스나 추상 클래스를 즉석에서 구현할 때 사용
• 자바 GUI나 이벤트 리스너에서 많이 사용됨

//(4) Anonymous class – 익명
interface ActionListener {// 인터페이스
    public void actionPerformed(ActionEvent e);
}
ActionListener aL = new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println(Q!);
    }
}

[ Deep Nesting – 중첩 클래스 안의 중첩 클래스 ]
• 클래스가 클래스 안에 또 있는 구조
• 내부 클래스는 바깥 클래스의 인스턴스 변수에 자유롭게 접근 가능
• 객체 생성 시 바깥 객체가 먼저 생성되어야 함

//Deep nesting – member classes

class WithDeepNesting {
    boolean toBe;
    WithDeepNesting(boolean b) { toBe = b;}
    class NestedC {
        boolean theQuestion;
        class DeeplyNesteD {
            DeeplyNesteD() { 
                theQuestion = toBe || !toBe; 
            }
        }
    }
}
//Enclosing class instance is necessary (먼저,‘감싼 객체’가 필요하다
//Free reference to encloser’s instance variables (바깥 변수를 쓸 수 있다)