본문 바로가기
Java

Java 복습_10

by 지민재 2022. 7. 10.
반응형
SMALL

 

함수 호출과 스택 메모리

  • 함수를 호출하면 그 함수만을 위한 메모리 공간이 할당되는데, 이 메모리 공간을 스택(stack)이라고 부릅니다.

add()함수를 호출하면 메모리를 생성하는 과정

  • 함수가 호출되면 그 함수가 사용할 메모리 공간이 스택에 생성됩니다.
  • 프로그램을 시작할 때 main() 함수부터 호출하기 때문에 가장 먼저 main()함수에 포함된 변수 num1, num2, sum을 저장할 메모리 공간이 생성됩니다.
  • main()함수에서 add()함수를 호출하면 add() 함수를 저장할 메모리 공간이 스택에 새롭게 생성됩니다.

add()함수 수행이 끝나고 함수에 할당했던 메모리 공간을 해제하는 과정

  • add() 함수 수행이 끝나고 결과 값이 반환되면 add()함수가 사용하던 메모리 공간은 자동으로 사라집니다.
  • 함수를 호출한 순서대로 메모리 공간에서 만들어지고 맨 마지막에 호출한 함수부터 반환됩니다.
  • 따라서 메모리 공간도 맨 마지막에 추가된 것부터 스택에서 사라집니다.
  • 즉 A() -> B() -> C() 함수의 순서로 호출했다면 C() -> B() -> A() 순서로 반환되고 스택 메모리도 이 순서대로 소멸됩니다.
  • 그림에서 보듯 main() 함수에서 사용하는 num1, num2 변수의 add()함수에서 사용하는 n1, n2변수는 서로 다른 메모리 공간을 사용하므로 이름이 같든 다르든 상관이 없습니다.
  • 이렇게 함수 내부에서만 사용하는 변수를 지역변수라고 합니다.
  • 지역변수는 스택메모리에서 생성됩니다. 변수의 유효범위 참조

함수의 장점

  • 기능을 나누어 코드를 효율적으로 구현할 수 있다.
  • 기능을 분리해서 구현하면 프로그램 코드의 가독성이 좋아진다.
  • 기능별로 함수를 구현해 놓고 같은 기능을 매번 코드로 만들지 않고 그 기능의 함수를 편리하게 호출할 수 있다.(중복되는 코드를 막을 수 있다.)
  • 디버깅 작업을 할 때도 편리하다.(하나의 기능이 하나의 함수로 구현되어 있기 때문에 오류난 기능만 찾아서 수정하면 된다.)

클래스 기능을 구현하는 메서드

  • 메서드(method)는 멤버변수를 사용하여 클래스의 기능을 구현한다.
  • 즉, 메서드는 함수에 객체 지향개념이 포함된 용어로 이해하면 된다.
  • 함수의 스택 메모리 사용방법과 함수의 장점등도 모두 메서드에 동일하게 적용된

자바의 이름 짓기 규약

  • 클래스 이름 : 파스칼케이스 - 단어의 시작 문자는 모두 대문자, 예) OrderInfo, OrderItems
  • 메서드 및 멤버변수 : 카멜케이스 - 첫 단어를 제외 단어의 시작문자는 대문자, 예) showStudentInfo
  • 패키지 이름 : 모두 소문자
  • 상수명 : 모두 대문자, 단어와 단어 사이는 언더바(_)로 구분, 예) NO_OF_STUDENT

클래스와 인스턴스

  • 멤버변수는 클래스 속성을 나타냅니다.
  • 메서드는 멤버변수를 이용하여 클래스 기능을 구현합니다.
  • main() 함수는 자바 가상 머신(Java Virtual Machine:JVM)이 프로그램을 시작하기 위해 호출하는 함수입니다.
  • 클래스 내부에 만들지만, 클래스의 메서드드는 아닙니다.

main()함수에서 클래스를 사용하는 방법

  • 클래스 내부에 main함수를 만드는 것
package study02;

public class Student {
	int studentID; 
	String studentName;
	int grade; 
	String address; 
	

	public String getStudentName() {
		return studentName;
	}
	
	public void setStudentName(String name) {
		studentName = name;
	}
	
	// main() 함수 
	public static void main(String[] args) {
		Student studentAhn = new Student(); // Student 클래스 생성
		studentAhn.studentName = "지민재";
		
		System.out.println(studentAhn.studentName);
		System.out.println(studentAhn.getStudentName());
	}
}

 

new 예약어로 클래스 생성하기

 

  • 클래스를 사용하려면 먼저 클래스를 생성해야 합니다.
클래스형 변수이름 = new 생성자;

 

  • 클래스를 생성할 때는 new 예약어를 사용 그리고 생성자를 써줍니다.
  • 클래스 자료형 변수에 변수를 선언 후 new 예약어로 생성자를 호출하여 대입하면 새로운 클래스가 생성됩니다.
  • 클래스가 생성된다는 것은 클래스를 실제 사용할 수 있도록 메모리 공간(힙 메모리)을 할당 받는다는 뜻입니다.
  • 이렇게 실제로 사용할 수 있도록 생성된 클래스를 인스턴스라고 합니다.
  • 그리고 인스턴스를 가리키는 클래스형 변수를 참조변수라고 합니다.
Student studentAhn = new Student();
  • Student 클래스 자료형으로 studentAhn 변수를 선언하고 new Student();로 Student클래스를 생성하여 studentAhn에 대입한다는 뜻
  • studentAhn을 참조변수라고 하고, 이 변수가 생성된 인스턴스를 가리킵니다.

인스턴스와 참조 변수

객체, 클래스, 인스턴스

  • 객체란 '의사나 행위가 미치는 대상'이며 이를 코드로 구현한 것이 클래스입니다.
  • 클래스가 메모리 공간에 생성된 상태를 인스턴스라고 합니다.
  • 또한 생성된 클래스의 인스턴스 객체라고도 합니다.

  • 클래스의 생성자를 호출하면 인스턴스가 만들어집니다.
  • 클래스는 하나이지만, 이 클래스로부터 여려 개의 각기 다른 인스턴스를 생성할 수 있습니다.

인스턴스 여러개 생성하기

package study02;

public class StudentTest1 {
	public static void main(String[] args) {

		Student student1 = new Student();  // 첫 번째 학생 생성 
		student1.studentName = "지민재"; 
		System.out.println(student1.getStudentName());
		
		Student student2 = new Student();  // 두 번째 학생 생성 
		student2.studentName = "김민재"; 
		System.out.println(student2.getStudentName());
	}
}

참조변수 사용하기

  • 참조변수를 사용하면 인스턴스의 멤버변수와 메서드를 참조하여 사용할 수 있는데 이때 마침표(.)연산자를 사용합니다.
참조변수.멤버변수
참조변수.메서드

studentAhn.studentName = "지민재";  // 멤버변수 사용
System.out.println(studentAhn.getStudentName());  // 메서드 사용

인스턴스와 힙 메모리

  • new Student()를 선언하면 Student하나가 생성되는데 각 Student는 StudentID, StudentName등의 멤버변수를 가지고 있습니다.
  • 그런데 이들 변수를 저장할 공간이 있어야 합니다. 이때 사용하는 메모리가 힙 메모리(heap memory)입니다.
  • 클래스 생성자를 하나 호출하면 인스턴스가 힙 메모리에 생성되는 것입니다.
Student student1 = new Student();
Student student2 = new Student();
  • student1 변수는 지역변수 입니다. 지역변수는 스택 메모리에 생성됩니다.
  • 인스턴스는 힙 메모리에 생성됩니다.
  • 지역변수 student1에 생성된 인스턴스를 대입하는 것은 student1에 인스턴스가 생성된 힙 메모리의 주소를 대입한다는 것과 같은 의미입니다.
  • 생성된 두 인스턴스는 당연히 각각 다른 메모리 공간을 차지합니다. 따라서 student1.studentName과 student2.studentName은 서로 다른 값을 가지게 됩니다.

힙 메모리란?

힙(heap)은 프로그램에서 사용하는 동적 메모리(dynamic memory) 공간을 말합니다. 일반적으로 프로그램은 스택, 힙, 데이터 이렇게 세 영역을 사용해야 하는데, 객체가 생성될 때 사용하는 공간이 힙입니다. 힙은 동적으로 할당되며 사용이 끝나면 메모리를 해제해 주어야 합니다. C나 C++ 언어에서는 프로그래머가 직접 메모리를 해제해야 하지만 자바에서는 **가비지 콜렉터(garbage collector)**가 자동으로 메모리를 해제해줍니다.

 

생성자

 

package study02;

public class Person {
	String name;
	float height;
	float weight;
}
package study02;

public class PersonTest {
	public static void main(String[] args) {
		Person personLee = new Person(); // Person()  - 생성자
	}
	//클래스를 생성할 때 사용하는 Person()과 같은 함수를 생성자라고 합니다.
	//생성자가 하는 역할은 인스턴스의 생성과 인스턴스를 생성할 때 멤버 변수나 상수를 초기화하는 것입니다.
}

디폴트 생성자

  • 생성자는 클래스를 생성할 때만 호출합니다.
  • 생성자 이름은 클래스 이름과 같습니다.
  • 생성자는 반환값이 없습니다.
  • 상기 코드에서는 Person() 생성자가 따로 없는데 생성자가 없는 클래스는 클래스파일을 컴파일 할때 자바 컴파일러에서 자동으로 생성자를 만들어 줍니다.
  • 이렇게 자동으로 만들어 주는 생성자를 디폴트 생성자(default constructor)라고 합니다.
  • 디폴트 생성자는 매개변수가 없고 구현코드도 없습니다.
package study02;

public class Person {
	String name;
	float height;
	float weight;
	
	/** 자바 컴파일러가 자동으로 제공하는 디폴트 생성자*/
	//public Person() {} 
	
	
	/**
	 * 사람 이름을 매개변수로 입력받아서
	 * Person 클래스를 생성하는 생성자
	 */
	
	public Person(String pname) {
		name = pname;
	}
}

생성자 오버로드

  • 클래스에서 생성자가 두개 이상 제공되는 경우를 생성자 오버로드(constructor overload) 합니다.
  • 필요에 따라 매개변수가 다른 생성자를 여러 개를 만들 수 있습니다.
  • 클래스에 생성자를 여러 개 제공하면 이 클래스를 사용하는 코드에서는 원하는 생성자를 선택해 사용할 수 있습니다.
  • 경우에 따라서는 클래스에서 일부러 디폴트 생성자를 제공하지 않기도 합니다.
package study02;

public class Person {
	String name;
	float height;
	float weight;
	
	/** 자바 컴파일러가 자동으로 제공하는 디폴트 생성자 자바 컴파일러는 생성자가 하나도 없는 경우에만 디폴트 생성자를 제공 디폴트 생성자 직접 추가*/
	public Person() {} 
	
	
	/**
	 * 사람 이름을 매개변수로 입력받아서
	 * Person 클래스를 생성하는 생성자
	 */
	
	public Person(String pname) {
		name = pname;
	}
	
	//이름 키, 몸무게를 매개변수로 입력받는 생성자
		public Person(String pname, float pheight, float pweight) {
			name = pname;
			height = pheight;
			weight = pweight;
		}
}
package study02;

public class PersonTest2 {
	public static void main(String[] args) {
		Person personKim = new Person();
		personKim.name = "민재";
		personKim.weight = 73.5f; 
		personKim.height = 175.0f;
		
		Person personLee = new Person("이순신", 175, 75);
	}
}

참조 자료형

크기가 정해진 기본 자료형(int, char, float, double 등)으로 선언하는 변수가 있고, 클래스형으로 선언하는 참조 자료형 변수가 있다.

package study02;

public class Subject {
	String subjectName;
	int scorePoint;
}
package study02;

public class Subject2 {
	int studentID;
	String studentName;
	
	// Subect 참조 자료형을 사용하여 선언
	Subject korean; 
	Subject math;
	
	/** 기본자료형 : int studentID
	 *  참조자료형 : String studentgName, Subject korean, Subject math
	 */
}

정보 은닉

  • 객체 지향 프로그램에서는 예약어를 사용해 클래스 내부의 변수나 메서드, 생성자에 대한 접근 권한을 지정할 수 있습니다.
  • 이러한 예약어를 '접근 제어자(access modifier)'라고 합니다.

접근제어자 정리

접근 제어자설명

public 외부 클래스 어디에서나 접근할 수 있습니다.
protected 같은 패키지 내부와 상속 관계의 클래스에서만 접근할 수 있고 그 외 클래스에서는 접근할 수 없습니다.
아무것도 없는 경우 default이며 같은 패키지 내부에서만 접근할 수 있습니다.
private 같은 클래스 내부에서만 접근할 수 있습니다.
package study02;

public class Student2 {
	int studentID;
	// studentName 변수를 private으로 선언 
	private String studentName; 
	int grade;
	String address;
}
package study02;

public class StudentTest2 {
	public static void main(String[] args) {
		Student studentLee = new Student();
		//studentLee.studentName = "이상원";  오류발생
		
		/**
		 * tudentTest.java파일에 오류가 발생합니다. studentName 변수의 접근 제어자가 public일 때는 외부 클래스인 StudentTest.java 클래스에서 이 변수에 접근할 수 있었지만,
		 *  private으로 바뀌면서 외부 클래스의 접근이 허용되지 않기 때문입니다.
		 */
	}
}

get(), set() 메서드

  • private으로 선언한 studentName 변수를 외부 코드에서 사용하려면 public 메서드를 제공해야 한다.
  • public 메서드가 제공되지 않는다면 studentName 변수에 접근할 수 있는 방법은 없습니다.
  • 이때 사용할 수 있는 것이 get(), set()메서드 입니다.

값을 받는 get() 메서드를 getter, 값을 지정하는 set()메서드를 setter라고도 부릅니다.

package study02;

public class Student2 {
	int studentID;
	// studentName 변수를 private으로 선언 
	private String studentName; 
	int grade;
	String address;
	
	public String getStudentName() {
		return studentName;
	}
	
	public void setStudentName(String studentName) {
		this.studentName = studentName;
	}
	//학생 이름을 받아오거나 지정할 수 있도록 getStudentName()메서드와 setStudentName()메서드를 추가
}
package study02;

public class StudentTest2 {
	public static void main(String[] args) {
		Student studentLee = new Student();
		//studentLee.studentName = "이상원"; // 오류발생
		
		// setStudentName() 메서드 활용해 private 변수에 접근 가능
		studentLee.setStudentName("이상원");
		
		System.out.println(studentLee.getStudentName());
		
		/**
		 * studentName 멤버 변수에 이름 값을 직접 대입하는 것이 아니고 setStudentName()메서드를 활용하여 값을 대입할 수 있습니다.
		 * 즉 외부 클래스에서 private 변수에 직접 접근할 수는 없지만, public 메서드를 통하면 private변수에 접근할 수 있습니다.
		 */
	}
}

 

정보 은닉이란?

  • 클래스의 멤버 변수를 public으로 선언하면 접근이 제한되지 않으므로 정보의 오류가 발생할 수 있습니다.
  • 이런 경우 오류가 나더라도 그 값이 해당 변수에 대입되지 못하도록 다음과 같이 변수를 private으로 바꾸고 public 메서드를 별도로 제공해야 합니다.
package study02;

public class MyDate {
	public int day;
	public int month;
	public int year;
}
package study02;

public class MyDateTest {
	public static void main(String[] args) {
		MyDate date = new MyDate();
		date.month = 2;
		date.day = 31;
		date.year = 2018;
	}
}
package study02;

public class MyDate2 {
	/**
	 * 이처럼 클래스 내부에서 사용할 변수나 메서서드는 private으로 선언해서 외부에서 접근하지 못하도록 하는 것을 객체 지향에서는 '정보은닉(information hiding)'이라고 합니다.
	 */
	private int day;
	private int month;
	private int year;
	
	public void setDay(int day) {
		if (month == 2) {
			if (day < 1 || day > 28) {
				System.out.println("오류입니다.");
			} else {
				this.day = day;
			}
		}
	}
}
package study02;

public class MyDateTest2 {
	public static void main(String[] args) {
		MyDate2 date = new MyDate2();
		
//		date.setYear(2018);
//		date.setMonth(2);
		date.setDay(31);
	}
	/**
	 * 정보은닉은 객체지향 프로그래밍의 특징 중에 하나이며 자바에서는 접근 제어자를 사용하여 정보은닉을 구현합니다.
	 * 모든 변수를 private으로 선언해야 하는 것은 아니지만, 필요한 경우에는 private으로 선언하여 오류를 막을 수 있습니다.
	 */
}

 

'Java' 카테고리의 다른 글

static 변수 (Java)  (0) 2022.07.13
this(Java)  (0) 2022.07.12
Java 복습_09  (0) 2022.07.06
Java 복습_08  (0) 2022.07.04
Java 복습_7  (0) 2022.06.29

댓글