함수 호출과 스택 메모리
- 함수를 호출하면 그 함수만을 위한 메모리 공간이 할당되는데, 이 메모리 공간을 스택(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 |
댓글