[자바 객체지향] 클래스와 객체
클래스와 객체 기본 개념
클래스, 객체, 인스턴스
[ 클래스(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 (바깥 변수를 쓸 수 있다)