자바 프로그래밍 Unit 4 클래스와 객체

honeyricecake·2022년 4월 10일
0

학교 수업 - 자바

목록 보기
7/16

세상 모든 것이 객체

세상 모든 것이 객체
실세계 객체의 특징 - 객체마다 고유한 특성행동을 가짐
(여기서 고유한 특성은 멤버와 필드 변수, 행동은메소드를 뜻한다.)

필드는 다른 말로 멤버변수나 전역변수라고 불린다. 변수라는 말처럼 필드는 어떠한(객체) 데이터를 저장하기 위한 역할을 담당한다.

다른 객체들과 정보를 주고 받는 등, 상호작용하면서 존재

컴퓨터 프로그램에서 객체 사례
- 테트리스 게임의 각 블록들
- 한글 프로그램의 메뉴나 버튼들

객체 지향 특성 : 캡슐화

캡슐화

  • 객체를 캡슐로 싸서 내부를 볼 수 없게 하는 것
  • 관련된 데이터와 알고리즘(코드)이 하나의 묶음으로 정리
  • 객체의 본질적인 특징
    -외부의 접근으로부터 객체 보호 : 정보 은닉
    -객체의 실제 구현 내용을 외부에 감추는 것

외부 인터페이스는 공개되어 있고 알고리즘은 숨어져 있다.

자바의 캡슐화

클래스 : 객체를 선언한 틀(설계도)
메소드(멤버 함수)와 필드(멤버 변수)는 모두 클래스 내에 구현

객체(object) :

  • 클래스의 모양대로 생성된 실체(instance)
  • 객체 내 데이터에 대한 보호, 외부 접근 제한
    -객체 외부에서는 비공개 멤버(필드, 메소드)에 직접 접근할 수 없음
    -객체 외부에서는 공개된 메소드를 통해 비공개 멤버에 접근
class Animal{
	String name;//필드
    int age;//필드
    void eat(){...}//메소드
    void speak(){...}//메소드
    void love(){...}//메소드
}

위와 같이 클래스를 선언할 수 있다.

위와 같은 클래스를 선언한 뒤
name이 lion이고 age가 4인 Animal 클래스에 속하는 객체
name이 bear이고 age가 8인 ANimal 클래스에 속하는 객체 등을 선언할 수 있다.

객체 지향의 특성 : 상속

  • 상속
    - 상위 개체(부모)의 속성이 하위 개체(자식)에 모두 물려짐.
    - 하위 개체가 상위 객체의 속성을 모두 가지는 관계
  • 실 세계의 상속 사례
    - 유전적 상속 관계
    ex. 나무는 식물의 속성과 생물의 속성을 모두 가짐
    그러므로 나무는 식물이다, 나무는 생물이다 라고 할 수 있음.
    ex. 사람은 생물의 속성은 가지지만 식물의 속성은 가지고 있지 않음.
    그러므로 사람은 생물이다 라고 할 수 있지만, 사람은 식물이다 라고 할 수 없음.

자바의 상속

상속(inheritance)

  • 자식 클래스가 부모 클래스의 속성을 물려받고 기능을 확장
    -부모 클래스(super class)
    -하위 클래스(sub class) : 부모 클래스를 재사용하고 새로운 특성 추가

자바는 클래스 다중 상속 없음.
인터페이스 다중 상속 허용. (인터페이스는 나중에 배움)

서브 클래스 객체는 슈퍼 클래스의 멤버와 서브 클래스의 멤버를 모두 가짐.

class Animal {
	String name;
    int age;
    void eat {...}
    void sleep {...}
    void love {...}
}

//extends 가 상속한다는 뜻
class Human extends Animal {
	String hobby;
    String job;
    void work() {...}
    void cry() {...}
    void laugh() {...}
}

이렇게 상속하면 Human객체는
hobby, job 멤버 변수 뿐만 아니라, name, age 멤버 변수도 가지고
work, cry, laugh 멤버 메소드 뿐만 아니라, eat, sleep, love 멤버 메소드도 가지게 된다.

객체 지향의 특성 : 다형성

  • 다형성(Polymorphism)
    -같은 이름의 메소드가 클래스나 객체에 따라 다르게 동작하도록 구현
    -다형성 사례
    • 메소드 오버로딩 : (한 클래스에서)같은 이름이지만 다르게 작동하는 여러 메소드
    • 메소드 오버라이딩 : 부모 클래스의 메소드를 자식 클래스마다 다르게 구현

ex. Animal 클래스의 speak() 메소드는 자식 클래스 dog, cat, chicken 에서 다르게 구현될 수 있다. -> 메소드 오버라이딩
(ex. 각각 멍멍, 야옹야옹, 꼬꼬댁 을 출력하도록 구현)

객체 지향 언어의 목적

  • 소프트웨어의 생산성 향상
    - 컴퓨터 산업 발전에 따라 소프트웨어의 생명 주기 단축
    -> 소프트웨어를 빠른 속도로 생산할 필요성 증대
  • 객체 지향 언어
    - 상속, 다형성, 객체, 캡슐화 등 소프트웨어 재사용을 위한 여러 장치 내장
    • 소프트웨어 재사용과 부분 수정 빠름
    • 소프트웨어를 다시 만드는 부담 대폭 줄임
    • 소프트웨어 생산성 향상

절차 지향 프로그래밍과 객체 지향 프로그래밍

  • 절차 지향 프로그래밍
    - 작업 순서 표현
    • 작업을 함수로 작성한 함수들의 집합
  • 객체 지향 프로그래밍
    - 객체들간의 상호작용으로 표현
    • 클래스 혹은 객체들의 집합으로 프로그램 작성

클래스와 객체

  • 클래스
    -객체를 만들어내기 위한 설계도 혹은 틀
    -객체의 속성(필드)과 행동(메소드) 포함
  • 객체 (object)
    -클래스의 모양 그대로 찍어낸 실체(완성품)
    • 프로그램 실행 중에 생성
    • 메모리 공간을 갖는 구체적 실체
    • 인스턴스(instance)라고도 부름
  • 사례
    - 클래스 : 소나타 자동차 설계도(혹은 소나타 자동차의 정의), 객체 : 출고된 실재 소나타 100대

객체들은 클래스에 선언된 동일한 속성을 가지지만, 객체마다 서로 다른 고유한 값으로 구분됨.

클래스 구성

public class Circle{
	public int radius;//원의 반지름 필드
    public String name;//원의 이름 필드
    public Circle() { //원의 생성자 메소드
    }
    public double getArea() {//원의 면적 계산 메소드
    	return 3.14 * radius * radius;
    }
}

여기서
public 은 접근 권한
class 는 클래스 선언
Circle 은 클래스 이름 을 의미한다.

클래스 구성 설명

  • 클래스 선언
    -class 키워드로 선언 (class Circle)
    -클래스 접근 권한, public
    • 다른 클래스들에서 Circle 클래스를 사용하거나 접근할 수 있음을 선언
  • 필드와 메소드
    -필드 (field) : 객체 내에 값을 저장하는 멤버 변수
    -메소드 (method) : 멤버 함수이며 객체의 행동을 구현
  • 필드의 접근 지정자
    -필드나 메소드 앞에 붙어 다른 클래스의 접근 허용을 표시
    -public 접근 지정자 : 다른 모든 클래스의 접근 허용
  • 생성자
    -클래스의 이름과 동일한 특별한 메소드
    -객체가 생성될 때 자동으로 한 번 호출되는 메소드
    -개발자는 객체를 초기화하는데 필요한 코드 작성

객체 생성 및 접근

  • 객체 생성
    -반드시 new 키워드를 이용하여 생성
    -> new는 객체의 생성자 호출
  • 객체 생성 과정
    -객체에 대한 레퍼런스 변수 선언//객체의 메모리 주소를 가짐.
    -객체 생성
    • 클래스 타입 크기의 메모리 할당//malloc과 같다.
    • 객체 내 생성자 코드 실행
  • 객체의 멤버 접근
    -객체 레퍼런스.멤버 -> 구조체와 문법이 같다.

인스턴스(instance) : 메모리상에 생성된 클래스 객체
레퍼런스 변수 : 메모리 상에 생성된 인스턴스를 가리키는데 사용되는 변수

Circle Pizza; //레퍼런스 변수 선언
pizza = new Circle(); //new 연산자를 이용한 객체 생성
pizza.radius = 30;
pizza.name = "자바피자";//.을 이용한 객체 멤버 변수 접근
double area = pizza.getArea();//.을 이용한 객체 멤버 메소드 호출

예제 4 - 1

반지름과 이름을 가진 Circle 클래스를 작성하고., Circle 클래스의 객체를 생성하라.


public class Circle {
	
	int radius;
	String name;
	
	public Circle() {}
	public double getArea() {
		return 3.14 * radius * radius;
	}
}
       
	public static void main(String[] args) {
		Circle pizza = new Circle();
		pizza.radius = 10;
		pizza.name = "해운대 피자";
		double area = pizza.getArea();
		System.out.println(pizza.name + "의 면적은 " + area);
		
		Circle donut = new Circle();
		donut.radius = 2;
		donut.name = "크리스피 크림 도넛";
		area = donut.getArea();
		System.out.println(donut.name+"의 면적은 " + area);

	}

예제 4 - 2 Rectangle 클래스 만들기 연습

너비와 높이를 입력받아 사각형의 면적을 출력하는 프로그램을 작성하라.

import java.util.Scanner;

class Rectangel {
	int width;
    int height;
    public int getArea() {
    	return width * height;
    }
}

public class RectApp {
	public static void main(String[] args) {
    	Rectangle rect = new Rectangle();
        Scanner scanner = new Scanner(System.in);
        System.out.print("사각형의 너비와 높이 입력>> ");
        
        rect.width = scanner.nextInt();
        rect.height = scanner.nextInt();
        System.out.println("사각형의 면적은 " + rect.getArea());
        scanner.close();
    }
}

Tip. 메모리 낭비를 막기 위해 scanner.close() 는 필수다.

하나의 .java 파일에는 단 하나의 public class 만 존재할 수 있음.
여러 클래스를 사용할 경우, public 속성을 제외한 클래스 사용 가능.

접근 지정자가 없으면 default로 동일한 패키지 안에서만 접근이 가능함
-> 패키지를 공부한 후에 복습!!!

생성자(Constructor)

  • 생성자 개념
    -객체가 생성될 때 초기화를 위해 실행되는 메소드
  • 생성자 역할
    -필드(멤버 변수)를 초기화//생성된 클래스의 멤버 변수를 정하는 것
  • 생성자의 특징
    -생성자 이름은 클래스 이름과 반드시 동일!!!
    -생성자는 리턴 타입을 지정할 수 없음. (메소드가 아니므로 필요가 없다.)
    -생성자는 여러 개 작성이 가능
    -생성자 오버로딩
    -생성자는 new를 통해 객체를 생성할 때, 한 번 호출
    -생성자는 객체가 생성될 때 반드시 호출됨.
    • 그러므로 하나 이상 선언되어야 함.
  • 기본 생성자
    -매개 변수와 실행 코드가 없는 단순 생성자
    -개발자가 생성자를 작성하지 않았으면 컴파일러가 자동으로 기본 생성자를 추가함.

예제 4 - 3 두 개의 생성자를 가진 Circle 클래스

public class Circle {
	int radius;
    String name;
    
    public Circle() {
    	radius = 1;
        name = "";
    }
    public Circle(int r, String n) {
    	radius = r;
        name = n;
    }
    public double getArea() {
    	return 3.14 * radius * radius;
    }
    
    public static void main(String[] args) {//static은 객체 선언 없이 사용가능.
    	Circle pizza;
        pizza = new Circle(10, "자바피자");
        double area = pizza.getArea();
        System.out.println(pizza.name + " 의 면적은 " + area);
        
        Circle donut = new Circle();//매개변수 없이 생성자를 호출했으므로 반지름이 1
        donut.name = "도넛피자";
        area = donut.getArea();
        System.out.println(donut.name + "의 면적은 " + area);
    }
}

예제 4 - 4 생성자 선언 및 활용 연습

public class Book {
	String title;
    String author;
	
    public Book(String t)
    {
    	title = t;
        author = "작자미상";
    }
    
    public Book(String t, String a)
    {
    	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);
    }
}

오버로딩 vs 오버라이딩

  • 오버로딩
    -하나의 클래스 내부에서 동일한 이름의 함수 사용
    -매개변수의 타입 및 개수가 다름
    -리턴 타입 상관없음

ex.


public class Book {
	String title;
    String author;
    public Book(String t)
    {
    	title = t;
        author = "Unknown";
    }
    
    public Book(String t, String a)
    {
    	title = t;
        author = a;
    }
}
  • 오버라이딩
    -상속 관계
    -부모 클래스의 메소드를 자식 클래스에서 재정의해서 사용
    -매개변수 타입과 개수가 같음
    -리턴 타입 동일

ex.

class Shape {
	void draw(int i, int j)
    {
    	System.out.println("Shape draw");
    }
}

class Square extends Shape {
	void draw(int i, int j)
    {
    	System.out.println("Square draw");
    }
}

Square 클래스에서는 Square 클래스에서 재정의한 draw 함수를 우선시한다.

기본 생성자

  • 기본 생성자
    -매개 변수가 없고 실행 코드도 없는 단순 생성자
    -디폴트 생성자라고도 부름
  • 클래스에 생성자가 하나도 선언되지 않은 경우,
    -컴파일러에 의해 자동으로 삽입
  • 기본 생성자가 자동으로 생성되지 않는 경우
    -개발자가 클래스에 생성자를 하나라도 작성한 경우

ex.

public class Circle {
	int radius;
    void set(int r)
    {
    	radius = r;
    }
    double getArea()
    {
    	return 3.14 * radius * radius;
    }
    
    public Circle(int r) // 생성자
    {
		radius = r;
    }
}

이렇게 작성하면 Circle donut = new Circle();
이라 하면 컴파일 에러가 난다.
해당하는 생성자가 없기 때문!!
-> 개발자가 클래스에 생성자를 작성하였으므로 기본 생성자가 자동으로 생성되지 않은 것이다.

this 레퍼런스

  • this
    - 객체 자신에 대한 레퍼런스
    • 컴파일러에 의해 자동 관리, 개발자는 사용하기만 하면 됨.
    • this.멤버 형태로 멤버 사용
  • this가 필요한 경우
    - this의 필요성
    • 객체의 멤버 변수메소드의 파라미터 이름이 같은 경우
    • 다른 메소드 호출 시 객체 자신의 레퍼런스를 전달할 때
    • 메소드가 객체 자신의 레퍼런스를 반환할 때

ex.

public class Circle {
	int radius;
    public Circle() {
    	this.radius = 1;
    }
    
    public Circle(int radius) {
    	this.radius = radius; //파라미터의 이름이 클래스의 멤버 변수와 이름이 같은 경우
    }
    
    public Circle getMe()
    {
    	return this;//객체 자신의 레퍼런스 리턴
    }
}
  • 객체 속에서의 this

ex.

public class Circle {
	int radius;
    public Circle(int radius) {
    	this.radius = radius;
    }
    public void set(int radius) {
    	this.radius = radius;
    }
}
  • this로 다른 생성자 호출
    -this()
    • 클래스 내의 다른 생성자 호출
    • 생성자 내부에서만 사용 가능
    • 반드시 생성자 코드의 맨 처음에 수행
public class Circle {
	int radius;
    public Circle(int radius) {
    	this.radius = radius;
    }
    
    public Circle() {
    	this(0);//메소드랑은 다른 느낌이라 Circle()은 해서는 안된다!!
        //객체를 생성한 후 만드는 다른 메소드랑은 다르기 때문
        //나 자신을 만든다는 느낌으로 this()를 생각하면 좋을 듯!!
    }
}

this()로 다른 생성자 호출

public class Book1 {
	String title;
    String author;
    
    void show() {System.out.println(title + " " + author);}
    public Book1() {
    	this("","");//세번째 생성자를 호출한 것이다.
        System.out.println("생성자 호출됨");
    }
    public Book1(String title) {
    	this(title, "작자미상");
    }
    public Book1(String title, String author){
    	this.title = title;
        this.author = author;
    }
}

객체의 치환

객체의 치환은 객체가 복사되는 것이 아니며 레퍼런스가 복사되는 것이다.

ex.
Circle ob1 = new Circle();
Circle ob2 = new Circle();
가 있고
Circle s = ob2; 라고 하면 메모리 주소가 복사되는 것이다.

객체의 복사는
배열은 copyof, 객체는 clone()을 쓴다.

ex.

import java.util.Arrays;

public class Copy {

	public static void main(String[] args) {
		
		int[] array = new int[10];
		
		for(int i = 0; i < 10; i++)
		{
			array[i] = i;
		}
		
		int[] brray = new int[10];
		
		for(int i = 0; i < 10; i++)
		{
			brray[i] = 2 * i;
		}
		
		brray = Arrays.copyOf(array, 10);
		
		for(int i= 0; i < 10; i++)
		{
			System.out.println(brray[i]);
		}
	}

}

객체 배열

  • 객체 배열 생성 및 사용
    -객체에 대한 레퍼런스를 원소로 갖는 배열
    • 객체를 원소로 가지는 배열
  • 객체 배열 생성 2단계
    -1단계 : 배열 생성(new)
    -2단계 : 배열 원소마다 객체 생성(new)
Circle [] c;
c = new Circle[5]; //이제 레퍼런스들을 받을 준비가 된 것!1 -> C언어와의 가장 큰 차이이다.

for(int i = 0; i < c.length; i++)
{
	c[i] = new Circle();//배열의 각 원소 객체 생성
}

ex.

class Circle2
{
	int radius;
	public Circle2(int radius)
	{
		this.radius = radius;
	}
	public double getArea()
	{
		return 3.14 * radius * radius;
	}
}
public class CircleArray {

	public static void main(String[] args) {
		Circle2[] c = new Circle2[5];
		
		for(int i = 0; i < c.length; i++)
		{
			c[i] = new Circle2(i);
			System.out.println(c[i].getArea());
		}

	}

}

[출력]

0.0
3.14
12.56
28.259999999999998
50.24

객체 배열 만들기 연습

import java.util.Scanner;

class Book {
	String title, author;
	public Book(String title, String author)
	{
		this.title = title;
		this.author = author;
	}
}

public class BookArray {

	public static void main(String[] args) {
		Book[] book = new Book[2];
		
		Scanner scanner = new Scanner(System.in);
		
		for(int i = 0; i < book.length; i++)
		{
			System.out.print("제목 >> ");
			String title = scanner.nextLine();
			System.out.print("저자 >> ");
			String author = scanner.nextLine();
			
			book[i] = new Book(title, author); //배열 원소 객체 생성
		}
		
		for(int i = 0; i < book.length; i++)
		{
			System.out.println("(" + book[i].title + ", " + book[i].author + ")");
		}
		scanner.close();

	}

}

[출력]

메소드 형식

  • 메소드
    -클래스의 멤버 함수
    -자바의 모든 메소드는 반드시 클래스 안에 있어야 함(캡슐화 원칙)
  • 메소드 구성 형식
    - 접근 지정자 : public, private, protected, default(접근 지정자가 생략된 경우)
    - 리턴 타입 : 메소드가 반환하는 값의 데이터 타입

자바의 인자 전달 방식

  • 경우 1. 기본 타입의 값 전달 : Call by value
    • 값이 복사되어 전달 : 기본 타입의 자료형(byte, int, double 등)
    • 메소드의 매개변수가 변경되어도 호출한 실인자 값은 변경되지 않음
  • 경우 2. 객체 혹은 배열 전달 : Call by reference
    - 객체나 배열의 레퍼런스(객체의 주소)만 전달 : 객체 혹은 배열이 통째로 복사되는 것X
    -매개변수가 실인자 객체 공유 (변경된 값이 실인자에 적용)

레퍼런스 전달의 장점 :
큰 객체나 배열의 경우에도 정수 크기인 레퍼런스만 전달
매개변수 전달로 인한 시간이나 메모리 오버헤드가 없음.
//오버헤드 : 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 · 메모리 등을 말한다.

예제 - 객체 전달 (레퍼런스 전달)

class Circle3
{
	int radius;
    public Circle3(int radius) {
    	this.radius = radius;
    }
    public double getArea() {
    	return 3.14 * radius * radius;
    }
}

public class ReferencePassing {
	public static void increase(Circle3 m) {
    	m.radius++;
    }
    
    public static void main(String[] args) {
    	Circle3 pizza = new Circle3(10);
        
        System.out.println("Before Passing radius: " + pizza.radius);
        Increase(pizza);
        
        System.out.println("After Passing radius: " + pizza.radius);
    }
}

출력하면 10에서 11로 반지름이 증가한 것을 알 수 있다.

예제 - 참조에 의한 호출

class Pizza {
	int size;
    String topping;
    public Pizza()
    {
    	size = 10;
        topping = "기본";
    }
    public void increaseSize(Pizza pizza)
    {
    	pizza.size += 10;
    }
    public void addTopping(Pizza pizza)
    {
    	pizza.topping += "치즈, 베이컨";//이렇게 하면 문자열 뒤에 저 문자열이 추가된다.
    }
    public void printPizza(Pizza pizza)
    {
    	System.out.println("[피자 주문 내역] 크기: " + pizza.size + ", 토핑: " + pizza.topping);
    }
}

public class CallByReferenceEx {
	public static voud increaseSize(Pizza pizza)
    {
    	pizza.size += 10;
    }
    
    public static void addTopping(Pizza pizza)
    {
    	pizza.topping += "치즈, 베이컨";
    }
    
    public static void main(String[] args)
    {
    	Pizza pizza1 = new Pizza();
        pizza.printPizza(pizza1);
        
        increaseSize(pizza1);
        
        System.out.println("피자 주문 변경");
        addTopping(pizza1);
        
        pizza1.printPizza(pizza1);
    }
}

[출력]

[피자 주문 내역] 크기: 10, 토핑: 기본
피자 주문 변경
[피자 주문 내역] 크기: 20, 토핑: 기본 + 치즈, 베이컨

인자 전달 : 배열

  • 배열의 주소값(레퍼런스)만 매개 변수에 전달
    -배열 전체가 전달되지 않음
    -객체가 전달되는 경우와 동일(자바에서는 배열도 객체로 취급함)
    -매개변수가 실인자인 배열을 공유

예제 4 - 8 : 인자로 배열이 전달되는 예

public class ArrayParameterEx {
	static void replaceSpace(char a[]) { //배열의 스페이스를 콤마로 바꾸는 함수
    	for(int i = 0; i < a.length; i++)
        {
        	if(a[i] == ' ') a[i] = ',';
        }
    }
    
    static void printCharArray(char a[])//배열을 프린트하는 함수
    {
    	for(int i = 0; i < a.length; i++)
        {
        	System.out.print(a[i]);
        }
        
        System.out.println();
    }
    
    public static void main(String[] args)
    {
    	char c[] = {'T','h','i','s',' ','i','s',' ','a',' ','p','e','n','c','i','l','.'};
        
        printCharArray(c);
        replaceSpace(c);
        printCharArray(c);
    }
}

This is a pencil 이 This,is,a,pencil 로 출력된다.

메소드 오버로딩

  • 이름이 같은 메소드 작성 (아래 두 조건을 모두 만족해야 됨)
    -메소드 이름이 동일해야 함
    -매개변수의 개수나 타입이 서로 달라야 함.
    -리턴 타입은 오버로딩과 관련 없음.

//메소드 오버로딩이 성공한 사례
class MethodOverloading{
public int getsum(int i, int j)
{
return i + j;
}
public int getsum(int i, int j, int k)
{
return i + j + k;
}
}

//메소드 오버로딩이 실패한 사례
class MethodOverloading{
public int getsum(int i, int j)
{
return i + j;
}
public double getsum(int i, int j)
{
return (double)(i + j);
}
}

메소드 오버로딩이 성공했을 때,
getsum()함수 호출은 매개 변수의 개수와 매개 변수의 타입에 따라 서로 다른 함수가 호출된다.

객체의 소멸과 가비지 컬렉션

  • 객체 소멸
    -new에 의해 할당된 객체 메모리를 자바 가상 기계의 가용 메모리로 되돌려 주는 행위
  • 자바 응용프로그램에서 임의로 객체 소멸할 수 없음
    -객체 소멸은 자바 가상 기계의 고유한 역할
  • 가비지
    -자바 응용 프로그램에서 더 이상 사용되지 않는 객체나 배열 메모리
    -가리키는 레퍼런스가 하나도 없는 객체 (누구도 사용할 수 없게 된 메모리)
    //Circle pizza = new Circle(); 이라 할 때 pizza가 레퍼런스
    -당연히 많이 생기면 좋지 않다.
  • 가비지 컬렉션
    -자바에서 가비지를 자동 회수하는 과정
    -가비지 컬렉션 스레드에 의해 수행
    (예전에는 프로그램을 실행하는 흐름이 오로지 프로세스뿐이었으나, 소프트웨어가 진보하면서 하나의 프로그램에서 복잡한 동시 작업을 요구하기 시작하였다. 이를 위해서는 하나의 프로그램이 여러개의 프로세스를 만들어야 했는데 프로세스 특성상 하나의 프로그램이 이러한 동시 작업을 수월하게 할 수가 없었다. 그래서 프로세스보다 더 작은 실행 단위 개념이 만들어지게 되는데 이것이 스레드이다.)
  • 개발자에 의한 강제 가비지 컬렉션
    -System 또는 Runtime 객체의 gc()메소드 호출
    ex. Syste,m.gc(); //가비지 컬렉션 자동 요청
    -이 코드는 자바 가상 기계에 강력한 가비지 컬렉션 요청
    (그러나 자바 가상 기계가 가비지 컬렉션 시점을 전적으로 판단)

자바의 패키지 개념

패키지

  • 관련 있는 클래스 파일(컴파일된 .class)을 저장하는 디렉터리
  • 자바 응용프로그램은 하나 이상의 패키지로 구성 -> default 패키지!
    - default package 내부의 클래스는 다른 클래스에서 import 안 됨. -> 패키지 공부하고 더 확실히

접근 지정자
자바의 접근 지정자는 4가지가 있다.
public, protected, public, default(접근 지정자 생략)

  • 접근 지정자의 목적
    -클래스나 일부 멤버를 공개하여 다른 클래스에서 접근하도록 허용
    -객체 지향 언어의 캡슐화 정책은 멤버를 보호하는 것 -> 객체 지향 언어
    (접근 지정은 캡슐화에 묶인 보호를 일부 해제할 목적)

클래스 접근 지정

  • 다른 클래스에서 사용하도록 허용할 지 지정
  • public 클래스
    -다른 모든 클래스에게 접근 허용
  • 디폴트 클래스(접근 지정자 생략)
    -'package-private'라고도 함
    -같은 패키지의 클래스에만 접근 허용

멤버 접근 지정자

  • public 멤버
    -패키지에 관계 없이 모든 클래스에게 접근 허용
  • private 멤버
    -동일 클래스 내에만 접근 허용
    -상속받은 서브 클래스에서 접근 불가
  • protected 멤버
    -같은 패키지 내의 다른 모든 클래스에서 접근 허용
    -상속받은 서브 클래스는 다른 패키지에 있어도 접근 가능
  • default 멤버
    -같은 패키지 내의 다른 클래스에게 접근 허용
    (protected와의 차이점은 protected는 다른 패키지에 있어도 상속받은 서브 클래스에서는 접근이 가능하다는 것이다.)

[정리]

ex.

class Sample {
	public int a;
    private int b;
    int c;
}

public class AccessEx {
	public static void main(String[] args) {
    	Sample aClass = new Sample();
        aClass.a = 10;
        aClass.b = 10;//이건 불가능!!!!
        aClass.c = 10;
    }
}

static 변수와 non-static 변수

non-static 변수 (인스턴스 변수)의 특성

공간적 특성 - 멤버들은 객체마다 독립적으로 별도 존재
인스턴스 멤버라고도 부름
시간적 특성 - 필드와 메소드는 객체 생성 후 사용 가능
비공유 특성 - 멤버들은 다른 객체에 의해 공유되지 않고 배타적

static 변수 (정적 변수)란?

객체마다 생기는 것이 아님
클래스당 하나만 생성됨
클래스 멤버라고도 부름
객체를 생성하지 않고 사용 가능.

특성

  • 공간적 특성 : static 멤버들은 클래스당 하나만 생성
  • 시간적 특성 : static 멤버들은 클래스가 로딩될 때 공간 할당
  • 공유의 특성 : static 멤버들은 동일한 클래스의 모든 객체에 의해 공유

-> 모든 객체들이 공유하는 변수가 static 변수로 클래스들의 전역 변수 개념이다.

class StaticSample {
	int n;
    void g() {...}
    
    static int m;
    static void f() {...}
}

static 멤버는 객체가 생기기 전에도 사용가능
(Math.~~ 이 객체를 생성하지 않고도 사용가능한 이유)

static 멤버를 클래스 이름으로 접근하는 사례

class StaticSample {
	public int n;
    public void g() {
    	m = 20;
    }
    public void h() {
    	m = 30;
    }
    
    public static int m;
    public static void f()
    {
    	m = 5;
    }
}

public class Ex {
	public static void main(String[] args)
    {
    	StaticSample.m = 10;//상수는 아니다.
        
        StaticSample s1;
        s1 = new StaticSample();
        
        System.out.println(s1.m);
        
        s1.f();
        StaticSample.f();//m은 5호 변경
      	
    }
}

static의 활용

  1. 전역 변수와 전역 함수를 만들 때 활용
  2. 공유 멤버를 작성할 때

static 메소드의 제약 조건

static 메소드는 non - static 멤버에 접근할 수 없음
- 객체가 생성되지 않은 상황에서도 static 메소드는 실행될 수 있기 때문에 non-static 메소드와 필드 사용 불가.
- 반대로 non - static 메소드는 static 멤버 사용 가능.

class StaticMethod {
	int n;
    void f1(int x) {n = x;}//정상
    void f2(int x) {n = x;}//정상 
    
    static int m;
    static void s1(int x) (n = x;)//컴파일 오류 : static 메소드는 non-static 필드 사용 불가
}

객체가 생성되지 않아도 사용가능하기 때문에 non - static 변수에 접근 불가능하므로, (어떤 객체에 접근하는지 알 수가 없어짐) 당연히 this 역시 사용 불가. -> this는 현재 객체를 가리키는 레퍼런스

final 클래스와 메소드

final 클래스 - 클래스 상속 불가
final 메소드 - overriding 불가 -> 상속해서 수정 불가!!!

final 필드

final 필드 : 상수 선언

상수를 선언할 때 사용

class SharedClass {
	public static final double PI = 3.14;
}

상수 필드는 선언 시에 초기값을 지정하여야 한다.
상수 필드는 실행 중에 값을 변경할 수 없다.

내부 클래스(Inner Class)

클래스 안에 클래스를 정의함

  • 내부 클래스는 외부 클래스의 변수와 메소드를 사용할 수 있음.

형식

class OuterClass {
	private int value = 0;
    class InnerClass{...}
}

내부 클래스는 외부 클래스의 private 멤버에도 접근할 수 있음 -> 같은 클래스 안에 있잖어~

내부 클래스 예제

class OuterClass {
	private int value = 10;
    class InnerClass {
    	public void myMethod() {
        	System.out.println("OuterClass의 private 변수 값: " + value);
        }
    }
    public OuterClass() {
    	InnerCLass obj = new InnerClass();
        obj.MyMethod;
    }
}

위 예제를 통해 외부 클래스의 private 멤버 변수에 접근이 가능하다는 것을 알 수 있다.

private 클래스 선언

최상위 클래스 선언에 private 사용 안함
-접근하지 못하는 클래스를 생성할 이유가 없음.

private 클래스 선언 예
-내부 클래스(inner class) 선언에 사용

public class MyClass {
	public MyClass() {
		System.out.println("MyClass 생성자 ");
	}
	private class InnerMyClass {
		public InnerMyClass() {
			System.out.println("InnerClass 생성자");
		}
		public String getName(){
			return this.getClass().getName();
		}
	}
	public void showInnerClassName() {
		InnerMyClass ic = new InnerMyClass();
		String icName = ic.getName();
		System.out.println(icName);
	}
	public static void main(String[] args) {
		MyClass myClass = new MyClass();
		myClass.showInnerClassName();
	}
}

0개의 댓글