기강 자바-02
자바의 클래스
- 자바에서 클래스란,
- 자바 프로그램의 기본적인 구조를 이루는 요소이다.
- 동시에 필드와 메서드를 가지는 참조형 타입을 정의하기도 한다.
- 클래스의 기본 구성은
- 멤버 변수
- 메소드
- 생성자 함수이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Person {
private String name; // 필드 변수들
private int age;
public Person() { // 기본 생성자
}
public Person(String name, int age) { // 모든 인자를 포함한 생성자
this.name = name;
this.age = age;
}
public void sayHello() { // 메소드
sout("Hello!!! " + name);
}
}
- 가장 기본적인 구조의 클래스이다.
- 멤버 변수, 생성자 함수들, 멤버 메소드로 이뤄져있는 것을 볼 수 있다.
- 위에 정의된 생성자 함수란,
- 해당 클래스 타입의 인스턴스를 만들 때 사용하는 메소드를 말한다.
- 다른 멤버 메소드와 달리, 메소드 명을 명시하지 않는다.
- 기본 생성자의 경우 아무 생성자 함수도 정의해주지 않을 경우, 컴파일 시점에 자동으로 생성된다.
- 기본 생성자란, 아무 인자도 받지 않는 빈 인스턴스를 생성하는 생성자 함수를 말한다.
- 위 예시의 경우 name과 age를 받는 생성자 함수를 정의해줬기 때문에 따로 기본 생성자를 정의해주지 않으면 사용할 수 없다.
객체 만들기
- 객체를 만드는 방법은, 참조형 타입의 변수를 정의한 후 인스턴스를 생성하여 초기화하는 것이 가장 기본적인 방법이다.
- 인스턴스를 만드는 방법은 new 키워드를 사용해 생성자 함수를 호출하는 것이다.
- 생성자 함수의 동작 방식은 다음과 같다.
- new 키워드와 함께 참조형 타입에 정의된 생성자 함수를 호출한다.
- 생성자 함수가 호출되면, 객체를 생성한다. (JVM의 힙 메모리에 할당된다.)
- 그 다음 생성자 함수는 객체의 초기화 작업을 수행한다. (필드 변수를 초기화한다.)
- 생성자 함수가 완료되어 객체를 반환한다.
- 반환된 객체는 객체를 참조할 수 있는 변수에 저장된다. (변수에는 객체의 참조값이 할당되며, 해당 변수는 JVM의 스택 영역에 저장된다.)
1
2
3
4
5
6
7
8
class Main {
public static void main(String[] args) {
Person person1 = new Person(); // 기본 생성자를 사용
Person person2 = new Person("babo", 20); // all args 생성자를 사용
person2.sayHello(); // Hello!!! babo
}
}
- 인스턴스를 생성하여 참조할 수 있는 타입의 변수에 할당해준다.
- 변수를 통해 객체에 정의된 메소드와 필드들을 사용할 수 있다.
생성자 함수 정의하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Person {
private String name;
private int age;
private String email;
public Person() { // 기본 생성자
}
public Person(String name) { // name만 받는 생성자
this.name = name;
}
/*
public Person(String email) { // 컴파일 에러
this.email = email;
}
*/
public Person(int age) { // age만 받는 생성자
this.age = age;
}
public Person(String name, int age, String email) { // 모든 인자를 다 받는 생성자
this.name = name;
this.age = age;
this.email = email;
}
}
- 일반 멤버 메소드와 다르게 메소드 명을 기입하지 않는 것을 알 수 있다.
- 중간에 주석 처리된 email만 받는 생성자는 주석 처리를 지울 경우 컴파일 에러가 발생한다.
- 자바에서 같은 클래스 내에 똑같은 메소드 시그니처를 갖는 메소드가 2개 이상 존재할 수 없다.
- 메소드 시그니처는 메소드 이름과 매개변수의 개수, 타입 및 순서로 결정된다.
- 생성자 함수도 마찬가지인데,
- name만 갖는 생성자와 email만 갖는 생성자는 같은 메소드 시그니처를 갖기 때문에 동시에 만들 순 없다.
1
2
3
4
5
6
7
8
9
class Babo { // 아무 생성자 함수도 정의하지 않은 클래스
}
class Main {
public static void main(String[] args) {
Babo = new Babo(); // 컴파일 시점에 기본 생성자가 생성되어 정의하지 않아도 사용할 수 있다.
}
}
- 위에서 설명했듯이 아무 생성자 함수도 정의하지 않은 클래스는 기본적으로 기본 생성자를 갖는다.
메소드 정의하기
- 위에서 언급했듯이 클래스는 메소드를 가질 수 있다.
- 메소드는 다음과 같이 이뤄져 있다.
- 접근 제한자
- 리턴 타입
- 메서드 명
- 파라미터
- 메소드 블럭
- 위의 생성자 함수 부분에서 언급했듯이, 한 클래스 내에 같은 메소드 시그니처를 갖는 메소드가 두 개 이상 존재할 수 없다.
1
2
3
4
5
6
7
8
9
10
11
12
13
class Babo {
public void sayName(String name) {
System.out.println("My name is " + name);
}
}
class Main {
public static void main(String[] args) {
Babo babo = new Babo();
babo.sayName(); // 멤버 메소드의 사용
}
}
- 위의 Babo 클래스의 sayName()의 경우 다음과 같이 이뤄져 있다.
- 접근 제한자 : public
- 리턴 타입 : void
- 메서드 명 : sayName
- 파라미터 : String name
- 메소드 블럭 : { ~~~ }
- Babo 타입의 객체를 만들어 멤버 메소드를 사용할 수 있다.
오버로딩
- 한 클래스 내에서 같은 메서드를 여러 개 구현할 수 있는 것
- 이를 오버로딩이라고 한다.
- Overloading
- 오버로딩의 조건은 아래와 같다.
- 메서드 이름이 동일하다.
- 파라미터 구성이 다르다.
- 리턴 타입은 영향을 주지 않는다.
코드로 짜보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MyClass {
// 생략..
public void method() {
// ...
}
public void method(Object p1) {
// ...
}
public void method(Object p1, Object p2) {
// ...
}
}
- 위의 method()처럼 하나의 메서드를 파라미터 구성에 따라 여러 개 구성할 수 있다.
- 같은 리턴 타입, 같은 메서드 명 그러나 다른 파라미터를 가지는 메서드를 구현하는 것을 오버로딩이라 한다.
- 생성자 함수를 파라미터에 따라 여러 개 구현할 수 있는 것도 오버로딩이라고 볼 수 있다.
과제
- 오버로딩을 코드로 짜보며 체득하세요.
- 메서드 이름
- 파라미터 구성
- 리턴 타입
접근 제한자
- 접근 제한자란,
- 클래스, 변수, 메소드 등에 대한 접근 권한을 지정하는 키워드이다.
- 접근 제한자는 4가지 종류가 있다.
- public : 모든 클래스에서 접근 가능
- protected : 같은 패키지 or 상속 받은 자식 클래스 내에서만 접근 가능
- default(package-private) : 같은 패키지 내에서만 접근 가능
- private : 해당 클래스 내에서만 접근 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 여기는 java.babo 패키지
public class Babo {
public int publicInt;
protected int protectedInt;
int defaultInt;
private int privateInt;
}
class BaboChild1 extends Babo {
public void hello() {
sout(super.publicInt); // O 모든 클래스 접근 가능
sout(super.protectedInt); // O 자식 클래스 or 같은 패키지라 접근 가능
sout(super.defaultInt); // O 같은 패키지라 접근 가능
sout(super.privateInt); // X 같은 클래스가 아니라 접근 불가능
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 여기는 java.boba 패키지
class Boba {
private Babo babo;
// constructor
public void hello() {
sout(babo.publicInt); // O 모든 클래스 접근 가능
sout(babo.protectedInt); // X 자식 클래스 or 같은 패키지 아니라 접근 불가능
sout(babo.defaultInt); // X 같은 패키지 아니라 접근 불가능
sout(babo.privateInt); // X 같은 클래스가 아니라 접근 불가능
}
}
class BaboChild2 extends Babo {
public void hello() {
sout(super.publicInt); // O 모든 클래스 접근 가능
sout(super.protectedInt); // O 자식 클래스 or 같은 패키지라 접근 가능
sout(super.defaultInt); // X 다른 패키지라 접근 불가능
sout(super.privateInt); // X 같은 클래스가 아니라 접근 불가능
}
}
- 위의 코드 블럭과 아래의 코드 블럭은 서로 다른 패키지이다.
- 접근 제한자에 따라서 접근할 수 있는 것과 없는 것을 볼 수 있다.
- 얘시에는 멤버 변수만을 나타냈지만, 메소드의 접근 제한자 역시 똑같이 동작한다.
this 키워드
- 생성자 함수를 만들 때 ‘this.name = name’에서 처럼 this라는 키워드를 봤을 것이다.
- this란 자기 자신의 객체를 가리키는 키워드이다.
1
2
3
4
5
6
7
8
9
10
11
12
class Person {
private String name;
private int age;
public Person(String name) { // this가 붙지 않은 name은 매개변수로 받아온 애를 가르킨다.
this.name = name; // this가 붙은 name은 자기 자신 인스턴스의 name 즉, 해당 객체의 멤버 필드인 name을 가르킨다.
}
public void sayName(String name) {
System.out.printf("%s is my name, not %s", this.name, name); // 해당 객체의 멤버 변수인 name이 맘마,
} // 매개변수로 들어온 name이 밤바일 때
} // sayName()을 호출하면 콘솔에 어떤 문장이 찍힐까?
- 예시의 정답은
- 맘마 is my name, not 밤바
this()
- this 외에 this() 메소드도 존재한다.
- 해당 메소드는 자기 자신의 생성자 함수를 가르킨다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Person {
private String name;
private int age;
private Gender gender;
// 1
public Person(String name) {
this.name = name;
}
// 2
public Person(String name, int age) {
this(name); // 이 경우 1번 생성자 함수를 가르킴
this.age = age;
}
// 3
public Person(String name, int age, Gender gender) {
this(name, age); // 이 경우 2번 생성자 함수를 가르킴
this.gender = gender;
}
}
- this()는 같은 타입의 다른 생성자 함수를 나타내는 키워드이다.
- 사용하는 메소드의 인자의 개수, 타입 및 순서를 통해 생성자 함수를 추정하고 호출한다.
내부 클래스
- 내부 클래스란,
- 클래스 내부에 정의된 클래스를 말한다.
- 내부 클래스는 외부의 클래스에 쉽게 접근할 수 있다.
- 내부 클래스는 크게 4가지가 있다.
- 인스턴스 내부 클래스
- 지역 내부 클래스
- 정적 내부 클래스
- 익명 내부 클래스
- 이번엔 인스턴스 내부 클래스만 알아본다.
인스턴스 내부 클래스
1
2
3
4
5
6
7
8
9
10
11
12
public class OuterClass {
private int outVal = 100;
public class InnerClass {
private int inVal = 200;
public void printVals() {
sout("outVal= " + outVal);
sout("inVal= " + inVal);
}
}
}
- 이렇게 인스턴스 내부 클래스를 정의할 수 있다.
- 외부 클래스 OuterClass와
- 인스턴스 내부 클래스 InnerClass를 볼 수 있다.
- InnerClass는 외부 클래스의 멤버 필드가 private이어도 자유롭게 접근할 수 있는 것을 볼 수 있다.
- 단, this를 사용해 외부 클래스의 멤버 변수에 접근할 수는 없다. (둘은 서로 다른 인스턴스이기 때문에~)
1
2
3
4
5
6
class Main {
public static void main(String[] args) {
OuterClass o = new OuterClass(); // 외부 클래스 생성
InnerClass i = o.new InnerClass(); // 외부 클래스의 인스턴스가 생성되어야 내부 클래스의 인스턴스 생성 가능.
}
}
- 인스턴스 내부 클래스는 외부 클래스의 인스턴스가 꼭 생성되어 있어야 한다.
- 메모리 구조상 인스턴스 내부 클래스의 객체는 외부 클래스의 인스턴스를 참조하는 포인터를 갖고 있는데,
- 이 포인터를 통해 외부 클래스의 변수 등에 접근이 가능한 것이다.
- 인스턴스 내부 클래스의 객체는 외부 클래스의 객체가 소멸될 때 같이 소멸된다.
- 외부 클래스의 인스턴스가 생성되었다고, 내부 클래스의 인스턴스가 꼭 같이 생성되는 건 아니지만
- 외부 클래스의 인스턴스가 소멸된다면, 내부 클래스의 인스턴스 역시 소멸된다.
- 메모리 사용 측면에서 효율적이다~
과제
- 인스턴스 내부 클래스를 정의하고, 사용해 보세요.
- 내부 클래스에서 외부 클래스의 변수와 메소드에 접근하여 사용해 보세요.
과제
- 자바의 연산자들에 대해 알아보세요.
- 산술 연산자
- 관계 연산자
- 논리 연산자
- 비트 연산자
- 할당 연산자
- 삼항 연산자
- 자바의 연산자들의 우선 순위에 대해 알아보세요.
This post is licensed under CC BY 4.0 by the author.