package hiding;
public class Student {
public int studentID;
public String studentName;
public int grade;
public String address;
}
package hiding;
public class StudentTest {
public static void main(String[] args) {
Student student = new Student();
student.studentName="홍길동";
System.out.println(student.studentName);
}
}
그리고 두번째 예시를 보자.
getter, setter 함수를 이용해 private 멤버변수를 접근하도록 했다.
package hiding;
public class Student {
public int studentID;
private String studentName;
public int grade;
public String address;
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
}
package hiding;
public class StudentTest {
public static void main(String[] args) {
Student student = new Student();
//student.studentName="홍길동";
student.setStudentName("홍길동");
System.out.println(student.getStudentName());
}
}
접근 제어자를 private으로 선언하면 외부 클래스에서 사용할 수 없다.
그리고 위 1, 2예시 모두 결국엔 변수를 사용할 수 있다.
그렇다면 굳이 왜 접근제어자를 private으로 써서 귀찮게 메서드를 만들어 사용하는게 바람직한걸까?
메서드에 조건문을 달아주면 오류가 나더라도 그 값이 해당 변수에 대입되지 않아 정보의 오류를 막을 수 있다
package hiding;
public class Student {
private int studentID;
public String studentName;
public int grade;
public String address;
public int getStudentID() {
return studentID;
}
public void setStudentID(int studentID) {
if(studentID >32) {
System.out.println("오류, 다시 입력하시오");
}else {
this.studentID = studentID;
}
}
}
package hiding;
public class StudentTest {
public static void main(String[] args) {
Student student = new Student();
student.setStudentID(33);
}
}
이치럼 클래스 내부에 사용할 변수나 메서드는 private으로 선언해서 외부에서 접근하지 못하도록 하는 것을 정보 은닉이라고 한다
package test;
class Book {
private String title;
public int price;
public String company;
public String author;
public String getTitle(){
return title;
}
public void getTitle(String title){
this.title= title;
}
}
public class Test {
public static void main(String[] args) {
Book science = new Book();
science.getTitle("안녕");
System.out.println(science.getTitle());
Book english = new Book();
english.getTitle("안녕안녕");
System.out.println(english.getTitle());
}
}
1-1) 생성자에서 다른 생성자를 호출하는 this
아래와 같이 클래스에 생성자가 여러 개 있을 때 this라는 예약어를 통해 이 클래스의 다른 생성자를 호출할 수 있다
Book()생성자에서 this("1번째 책")을 사용해 Book(String title) 생성자를 호출한 것이다
package test;
class Book {
public String title;
public int price;
public String company;
public String author;
public Book(){
this("1번째책");
}
public Book(String title){
this.title= title;
}
}
public class Test {
public static void main(String[] args) {
Book science = new Book();
System.out.println(science.title);
}
}
1-2) 자신의 주소를 반환하는 this도 있는데 이 부분은 생략한다
2. static 변수
static 변수는 C언어에서 봤던 개념과 거의 똑같다.
프로그램이 실행되어 메모리에 올라갔을 때 딱 한번만 메모리 공간이 할당되며 그 값은 모든 인스턴스가 공유한다
아래 예문의 결과값을 예상해보자.
package test;
class Book {
public int a=2;
static public int b=3;
}
public class Test {
public static void main(String[] args) {
Book science = new Book();
Book english = new Book();
english.a++;
System.out.println(science.a);
english.b++;
System.out.println(science.b);
science.a++;
System.out.println(english.a);
science.b++;
System.out.println(english.b);
}
}
*이 게시글에서는 속성=필드=객체변수=인스턴스 변수=멤버변수라고 불리는 것을 객체 변수라고 통일하겠다.
1. 객체 생성
앞선 2탄에서 클래스, 객체, 메서드, 메모리 구조에 대해 살펴 보았다.
클래스는 책을 예를 들어 책이라는 자료형을 만들기 위해 구성요소(제목, 가격, 출판사, 저자등)를 하나로 합쳐놓은 것이다.
책이라는 객체의 구성요소를 사용하기 위해 책이라는 자료형을 클래스로 만들었다면 그 구성요소를 이용해서 다양한 책(객체)을 만들어야 하지 않겠는가
자바에서는 Book science = new Book(); 이런 형태로 객체를 만들 수 있다.
이렇게 클래스를 이용해서 만든 객체 여기서는 science를 인스턴스라고 한다.
클래스는 붕어빵 틀, 객체는 붕어빵1,2 ... 이라고 생각하면 된다
package test;
class Book {
public String title;
public int price;
public String company;
public String author;
public String getTitle(){
return title;
}
}
public class Test {
public static void main(String[] args) {
Book science = new Book();
Book english = new Book();
}
}
science앞에 붙은 Book은 int, String처럼 Book이라는 자료형이라는 표시이므로
Book자료형 science를 선언한다는 의미이다.
Book science는 int a와 동일한 형태이다
뒤에 붙은 new Book()에서 new는 새로만들어진다는 예약어이고 뒤에 나오는 Book()은 생성자(Constructor)라고 불리는 녀석이다.
Book science = new Book()은 즉 science라는 책 객체를 만든다는 의미인 것이다.
생성자얘기는 나중에 하고 우선 객체를 생성할 때 메모리에 어떻게 동작되는지 알아보자.
2. 객체 생성시 메모리 구조(heap영역)
살짝 복습하면 static이라고 붙은 메서드를 로딩하는데 거기서 제일 먼저 로딩되는 것이 main메서드이다. 위의 코드를 예를 들어 Test class의 main메서드가 제일 먼저 메모리에 로드돼서 호출된다.
호출되면 stack 영역에 들어가는데 이 메인메서드 안에는 Book science라는 변수가 선언돼있다.
이때 science라는 변수를 참조변수라고 한다.(참조변수이긴 하지만 동시에 지역변수이기도 하다)
Book science를 선언하고 new 예약어와 함께 Book()이라는 생성자를 호출하면 Heap영역이라는 메모리 공간에 science라는 객체가 하나 생성된다.
science라는 참조변수는 Heap 영역에 있는 science객체의 주소를 가리킨다.
science 객체 안에는 이런식으로 객체가 만들어져있고 science라는 참조변수는 Book객체(science)의 주소를 가리킨다.
여기서 getTitle()이라는 메서드는 실제 위치는 method 영역에 들어있지만 getName() 메서드의 주소로 메서드 영역의 getTitle()과 연결돼있다.
최종적으로 정리하면 Book science = new Book()이라고 하면 heap영역에 science객체(인스턴스)가 생성되고 science라는 참조변수는 heap영역의 science 객체(인스턴스)의 주소를 가리킨다
이렇게 객체를 생성하고 나면 그 객체의 이름인 참조변수를 이용해 객체 변수와 메서드를 사용할 수 있다
위의 예문 처럼 science.title 이렇게 도트 연산자를 이용해 각 객체의 객체변수와 메서드에 접근할 수 있게 된다
package test;
class Book {
public String title;
public int price;
public String company;
public String author;
public String getTitle(){
return title;
}
}
public class Test {
public static void main(String[] args) {
Book science = new Book();
Book english = new Book();
science.title="개미와배짱이";
System.out.println(science.title); //개미와배짱이 출력
System.out.println(science.getTitle()); //개미와배짱이 출력
}
}
앞에서 봤던 아래 예문도 객체를 이용하면 hello메서드를 static 예약어 없이 호출가능하다
*static 포함한 경우
package test;
public class Test {
public static void main(String[] args) {
int a=3;
System.out.println(hello(a));
System.out.println(a);
}
public static int hello(int a) {
a=7;
return a;
}
}
*static을 사용하지 않은 경우
package test;
public class Test {
public static void main(String[] args) {
int a=3;
Test test1 = new Test();
System.out.println(test1.hello(a));
System.out.println(a);
}
public int hello(int a) {
a=7;
return a;
}
}
3. 생성자(Constructor)
Book science = new Book();에서
new 예약어 뒤에 붙은 Book()을 생성자라고 한다
생성자가 하는 일은 객체(인스턴스)를 heap영역에 생성하고 클래스 안에 Book() 생성자의 {}중괄호를 호출하는 역할을 하는데 객체가 생성될 때 객체 변수 값들을 초기화하는 역할도 한다
즉, science의 title과 english의 title은 다르게 설정된다는 것이다
package test;
class Book {
public String title;
public int price;
public String company;
public String author;
public String getTitle(){
return title;
}
public Book() {} //기본 생성자
public class Test {
public static void main(String[] args) {
Book science = new Book();
Book english = new Book();
}
}
생성자는 객체를 생성할 때만 호출되는데 생성자 이름은 클래스 이름과 같고 반환값이 없다
생성자가 없는 클래스는 클래스 파일을 컴파일할 때 자바 컴파일러에서 자동으로 생성자를 만들어주는데 이렇게 자동으로 생성되는 생성자를 기본 생성자(default constructor)이라고 한다
개발자가 매개변수가 있는 생성자를 따로 만들면 자동으로 기본 생성자가 생성이 되지 않아 기본생성자를 만들어줘야 한다
아래에 public Book(String title){}이 바로 매개변수가 있는 생성자이다
이렇게 클래스에 생성자가 두 개 이상 제공되는 경우를 생성자 오버로딩이라고 한다
자바의 한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메소드가 있더라도 매개변수의 개수 또는 타입이 다르면, 같은 이름을 사용해서 메소드를 정의할 수 있는데 이를 오버로딩이라고 한다
아래에 나오는 this라는 예약어는 객체 자신을 가리키는 예약어인데 우선 이런게 있다고 알고 넘어가자.
아무튼 자바의 한 클래스내에 생성자가 두 개 이상이 있으면 인스턴스를 생성할 때 원하는 생성자를 골라서 만들 수 있다
package test;
class Book {
public String title;
public int price;
public String company;
public String author;
public String getTitle(){
return title;
}
public Book() {} //기본 생성자
public Book(String title) {
this.title=title;
}
public class Test {
public static void main(String[] args) {
Book science = new Book();
Book english = new Book();
}
}
4. 접근제어자(access modifier)
자바에서는 예약어를 사용해서 클래스 내부의 변수, 메서드, 생성자에 대한 접근 권한을 지정할 수 있다.
이런 예약어를 접근 제어자라고 한다
접근제어자에는 private, protected, default, public 이렇게 4종류가 있다
위 코드의 객체 변수 String title에 접근 제어자를 private으로 바꾸면 동일한 클래스를 제외하고는 이 변수에 직접적으로 접근할 수 없다
그래서 이를 접근하기 위해서는 메서드를 만들면 된다.
직접적으로 접근을 할 수 없으니 Book 제목을 받아오거나 지정할 수 있도록 메서드를 사용한다.
package test;
class Book {
private String title;
public int price;
public String company;
public String author;
public String getTitle(){
return title;
}
public void getTitle(String title){
this.title= title;
}
}
public class Test {
public static void main(String[] args) {
Book science = new Book();
//science.title="바보"; //오류발생 //접근 불가
science.getTitle("안녕");
System.out.println(science.getTitle());
}
}
정보처리기사 실기에서는 어차피 거의 대부분이 동일한 클래스로 나오므로 사실 잘 몰라도 상관없다
위의 코드는 getTitle이라는 메서드가 오버로딩돼있는 것인데
getTitle을 호출할 때 매개변수가 없으면 public String getTitle()을 호출하는 것이고
매개변수가 있으면 public String getTitle(String title)을 호출하는 것이다
각 요소들을 객체(Object)로 만든 후, 객체들을 조립해서 소프트웨어를 개발하는 기법이다. 쉽게 생각해서 컴퓨터로 예를 들면 컴퓨터의 모든 부품을 적절히 연결하고 조립해서 컴퓨터가 제대로 작동하도록 만드는 것이라고 볼 수 있다.
"학생이 밥을 먹는다"라는 예문을 생각해보자. 학생이라는 객체와 밥이라는 객체가 협력해서 문장이 구현이 된다. 객체 지향 프로그래밍도 마찬가지로 각 객체가 어떤 기능을 제공하고 객체 간 협력을 어떻게 구현할 것인지 생각해야한다.
출처 : Do it! 자바 프로그래밍 입문-박은종
2. 클래스
앞서 1탄에서 자바 프로그램은 클래스 단위이기 때문에 자바 프로그램을 만드는 것은 자바 클래스를 만드는 것과 같다고 하였다. 그렇다면 클래스는 뭘까
클래스는 공통된 연산을 갖는 객체의 집합이다
C언어에서 구조체랑 비슷하다.
C언어에서 구조체는 여러가지 자료형을 한번에 관리하기 위해 사용한 것이라면 Java에서 클래스는 여러가지 자료형과 함수(자바에서는 메서드라고 부름)를 한번에 관리하기 위해서 사용한다.
간단하게 예를 들어 생각해보자.10이라는 자료를 변수로 저장하고 싶다면 자료형을 뭘로 해야할까?int형 같은 정수형 자료형을 사용하면 될 것이다.그렇다면 책이라는 것을 변수로 저장하려면 자료형을 뭘로 해야할까?그럴때 나오는 개념이 바로 클래스이다.
책이라는 객체안에는 제목, 가격, 출판사, 저자등의 다양한 자료들이 들어가 있다.
자바에서는 아래와 같이 클래스라는 녀석을 이용해서 서로 다른 자료형들과 함수(자바에서는 메서드)를 한꺼번에 담는다.
public class Book{
public String title;
public int price;
public String company;
public String author;
}
위의 예시에서 title, price, company, author같이 클래스안에 들어있는 변수를 필드 또는 멤버변수 또는 객체변수 또는 속성 또는 인스턴스 변수라고 한다
<Book>
String title
int price
String company
String author
위와 같은 느낌으로 생성된다.
3. 메서드
클래스에 포함되는 함수를 메서드라고 한다
일단 함수는 C언어에서도 봤었다.
형태는 거의 동일하다
아래 예시에서
int는 반환값
add는 메서드 이름
int a, int b는 매개변수이다.
int add(int a,int b) {
return a+b;
}
4. 자바의 메모리 구조와 변수
아래 예문의 출력 결과를 예상해보자.
package test;
public class Test {
public static void main(String[] args) {
int a=3;
System.out.println(hello(a));
System.out.println(a);
}
public static int hello(int a) {
a=7;
return a;
}
}
// 클래스 블록
public class 클래스명 {
// 메서드 블록
public static void main(String[] args) {
System.out.println("Hello java");
}
//public이 접근제어자
//static이 정적메서드와 변수
//void가 리턴자료형
//main은 메서드명
//String[] arg는 메서드의 매개 변수
}
소스코드의 가장 바깥쪽 영역은 클래스 블록이다. 클래스명은 원하는 이름으로 지을 수 있다. 단, 클래스명은 소스파일의 이름(클래스명.java)과 동일하게 사용해야 한다.
자바 프로그램은 클래스 단위이기 때문에 자바 프로그램을 만드는 것은 자바 클래스를 만드는 것과 같다.
이제 메서드블록을 살펴보자.
1) 접근 제어자
메서드 블록 부분에서 public이라고 되어 있는 부분은 접근제어자라고 하는데 이 자리에는 public, private, protected 또는 아무것도 오지 않을 수 있는데 지금은 이런게 있다고만 알고 넘어가자.
2) 정적메서드와 변수
그 다음은 static 키워드가 올수도 있고 오지 않을 수도 있다는 의미이다. static 이라는 키워드가 붙게 되면 static 메서드가 되는데 이것도 일단 이런게 있다고 알고 넘어가자.
3) 리턴자료형
그 다음 void는 메서드가 실행된 후 리턴되는 값의 자료형을 의미한다.
리턴값이 있을 경우에는 반드시 리턴 자료형을 표기해야 하며 만약 리턴값이 없는 경우라면 void 로 표기해야 한다. 이 항목은 둘 다 생략할 수는 없고 void 또는 리턴자료형이 반드시 있어야만 한다.
4) 메서드
메서드는 클래스에 포함되는 함수를 말하며 메서드명은 원하는 이름으로 지을수 있다.
메서드 명 이후의 괄호() 안의 값들은 메서드의 입력 인자를 뜻한다.
입력 인자의 갯수는 제한이 없으며 입력 인자는 "입력자료형"+"매개변수명" 형태로 이루어 진다.
String[] args는 메서드의 매개 변수이다. String[]은 배열 자료형이란 의미이고, args는 String[]자료형에 대한 변수명이다. args라는 이름은 인수를 의미하는 arguments의 약어로 관례적인 이름이다. args 대신 다른 이름을 사용해도 상관없다.