참고 강의 : https://wikidocs.net/book/31
클래스
클래스는 객체를 생성하는 기능이 있다.
객체의 생성
Animal cat = new Animal();
cs
객체와 인스턴스의 차이
인스턴스 : 클래스에 의해서 만들어진 객체 이며, 위에서 cat은 객체.
cat이라는 객체는 Animal의 인스턴스(instance).
즉, "cat은 인스턴스" 보다는 "cat은 객체" 이며, Animal의 객체가 아닌 "cat은 Animal의 인스턴스" 라고 표현한다.
붕어빵 틀은 클래스, 붕어빵 틀에 의해 만들어진 붕어빵 들은 객체
또는 Animal은 클래스이고 고양이와 개, 말 등은 객체
아래와 같이 Animal 클래스에서 무수히 많은 동물 객체들이 생성될 수 있다.
Animal cat = new Animal();
Animal dog = new Animal();
Animal horse = new Animal();
...
cs
Animal 클래스에 인스턴스 변수(또는 멤버변수나 속성) name을 추가
인스턴스 변수에 접근하려면 인스턴스.변수 와 같이 접근한다. (cat.name)
package jump2java;
public class Animal {
String name;
public static void main(String [] args){
Animal cat = new Animal();
System .out .println (cat.name);
}
}
cs
Output :
null
값이 할당되지 않았기에 null이 출력된다.
특정 클래스가 있는 자바 파일 내에 또 다른 클래스 정의 가능 * - 단, 원래 클래스가 아닌 다른 클래스들은 public 키워드를 붙일 수 없다!
Java의 메소드
Java에서 클래스 내에 구현된 함수를 메소드라고 한다.
(함수라는 용어를 쓰지 않으며, 클래스 내에서만 사용가능)
아래와 같이 return값이 없는 void 메소드를 정의해준다.
return값이 없다는 거에 당황할 수 있지만 setName의 name은 메소드 내에서 할당되며 돌려주는 값은 없다.
this 키워드
아래의 코드에서 Animal 클래스의 인스턴스 변수명도 name, SetName 메소드의 인수도 name이다. (String name)
아래 예제에서 this는 Animal 클래스에 의해서 생성된 인스턴스를 가리키며, cat을 가리킨다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package jump2java;
public class Animal {
String name ;
public void setName(String name ) {
this .name = name ;
}
public static void main(String [] args){
Animal cat = new Animal();
cat.setName("Ludwig" );
System .out .println (cat.name );
}
}
cs
Output :
Ludwig
메소드 내에서만 쓰이는 지역 변수 (local variable)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package jump2java;
public class Test {
String name;
public void vartest(int a) {
a+ + ;
}
public static void main(String [] args) {
int a = 1 ;
Test myTest = new Test();
myTest.vartest(a);
System .out .println (a);
}
}
cs
Output :
1
vartest 메소드의 인수 a는 메소드 안에서만 쓰이는 변수이며, 메소드 밖(main함수)의 변수 a가 아니다.
메소드에서 쓰이는 변수는 지역변수 로 밖의 변수와는 상관없다 .
위에서 vartest 메소드를 이용해 값을 증가시키려면 다음과 같이 쓴다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package jump2java;
public class Test {
String name;
public int vartest(int a) {
a+ + ;
return a;
}
public static void main(String [] args) {
int a = 1 ;
Test myTest = new Test();
a = myTest.vartest(a);
System .out .println (a);
}
}
cs
입력으로 들어온 값이 1만큼 증가해 return되며 2가 출력된다.
주의할 점은, 이 역시 vartest 메소드 안의 a 변수와 메소드 밖의 a 변수는 다른 것 이다!
Call by value
메소드에 값 을 전달하는 것과 객체 를 전달하는 것의 차이 를 알 수 있는 예제이다.
다음은 메소드에 값을 전달하는 예제이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package jump2java;
class updator {
void update(int cnt) {
cnt+ + ;
}
}
public class Counter {
int count = 0 ;
public static void main(String [] args) {
Counter myCounter = new Counter();
System .out .println (" 초기 값 " + myCounter.count);
updator myUpdator = new updator();
myUpdator.update(myCounter.count);
System .out .println (" update 값 " + myCounter.count);
}
}
cs
Output :
초기 값 0
update 값 0
위의 예제는 값이 바뀌지 않음을 알 수 있다. update 메소드는 값을 전달받았으며, cnt 변수는 메소드 안에서만 쓰이는 변수이기 때문이다.
아래 예제는 객체를 전달해서 객체의 속성 값을 변경하도록 한 예제이다.
위와 같이 int cnt로 값을 전달받는 것이 아니라 Counter cnt 와 같이 객체를 전달받도록 했다. (Counter 자료형 변수 cnt를 입력받아 증가시킴)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package jump2java;
class updator {
void update(Counter cnt ) {
cnt.count+ + ;
}
}
public class Counter {
int count = 0 ;
public static void main(String [] args) {
Counter myCounter = new Counter();
System .out .println (" 초기 값 " + myCounter.count);
updator myUpdator = new updator();
myUpdator.update(myCounter );
System .out .println (" update 값 " + myCounter.count);
}
}
cs
Output:
초기 값 0
update 값 1
자바에서의 상속
자바에서는 클래스 상속을 위해서 extends 키워드를 사용한다. Dog 클래스가 Animal 클래스를 상속함 (물려받음)
public class Dog extends Animal {
}
cs
먼저 프로젝트에서 Animal 클래스와 Dog 클래스를 생성한다.
Animal.java
1
2
3
4
5
6
7
8
9
10
11
12
13
package jump2java;
public class Animal {
String name;
public void setName(String name) {
this .name = name;
}
public static void main(String [] args) {
}
}
cs
Dog.java
package jump2java;
public class Dog extends Animal {
public static void main(String [] args) {
Dog dog = new Dog();
dog.setName("Ludwig" );
System .out .println (dog.name);
}
}
cs
Output :
Ludwig
Dog 클래스에서는 setName 메소드를 정의하지 않았지만, Animal 클래스를 상속했으므로 setName 메소드를 그대로 사용할 수 있다.
Dog.java에 bark 메소드를 하나 추가해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package jump2java;
public class Dog extends Animal {
public void bark() {
System .out .println (this .name + "은 멍 멍! 하고 짖었다!" );
}
public static void main(String [] args) {
Dog dog = new Dog();
dog.setName("Ludwig" );
System .out .println (dog.name);
dog.bark();
}
}
cs
Output :
Ludwig
Ludwig은 멍 멍! 하고 짖었다!
메소드 오버라이딩
HouseDog.java
아래와 같이 HouseDog 클래스에 Dog 클래스와 동일한 원형의 bark 메소드를 구현하였다.
1
2
3
4
5
6
7
8
9
10
11
12
13
package jump2java;
public class HouseDog extends Dog {
public void bark() {
System .out .println (this .name + "는 도둑을 보면 짖는다" );
}
public static void main(String [] args) {
HouseDog houseDog = new HouseDog();
houseDog.setName("Toni" );
houseDog.bark();
}
}
cs
Output (HouseDog.java에서 실행결과) :
Toni는 도둑을 보면 짖는다
부모클래스의 메소드를 자식클래스가 동일한 원형으로 정의했지만, HouseDog 클래스에서 bark 메소드는 Dog 클래스의 bark 메소드보다 더 높은 우선순위를 갖게 된다. 그 결과, HouseDog 클래스의 bark 메소드가 호출되고 위와 같은 결과가 나온다.
이렇게 부모 클래스의 메소드를 자식 클래스가 동일한 원형을 가지고 재정의 하는 행위를 Method Overriding(메소드 덮어씌우기)이라고 한다.
자바는 다중상속을 지원하지 않는다
다중상속의 모호함 때문에 자바는 일반 클래스의 다중상속을 지원하지 않는다.
생성자
HouseDog클래스로 만든 인스턴스에 setName 메소드를 생성하지 않으면, name 인스턴스 변수에 값이 할당되지 않았기에 null이 출력된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package jump2java;
public class HouseDog extends Dog {
public void bark() {
System .out .println (this .name + "은(는) 도둑을 보면 짖는다" );
}
public static void main(String [] args) {
HouseDog houseDog = new HouseDog();
//houseDog.setName("Toni");
houseDog.bark();
}
}
cs
Output :
null은(는) 도둑을 보면 짖는다
생성자(Constructor)를 이용하면 name 이라는 인스턴스 변수를 무조건 초기화하도록 강제할 수 있다.
아래 소스에서 public HouseDog(String name) { ... 과 같이 메소드명이 클래스명과 동일하고 반환형이 없는 메소드가 생성자이다.
1
2
3
4
5
6
7
8
9
10
11
12
package jump2java;
public class HouseDog extends Dog {
public HouseDog( String name) {
this .setName(name);
}
public static void main(String [] args) {
HouseDog houseDog = new HouseDog();
System .out .println (houseDog.name);
}
}
cs
Output :
Exception in thread "main" java.lang.Error: 분석되지 않는 컴파일 문제점:
생성자 HouseDog()이(가) 정의되지 않았습니다.
at jump2java.HouseDog.main(HouseDog.java:9)
생성자의 규칙대로 객체를 선언하지 않았기 때문에 컴파일 오류가 발생한다. (String변수로 값을 전달해 setName메소드 호출)
위의 소스 9번째 줄을 다음과 같이 변경해주면 정상적으로 컴파일되고 실행결과를 출력한다.
HouseDog houseDog = new HouseDog("Toni" );
cs
Output :
Toni
생성자의 규칙
클래스명과 메소드명이 동일하다.
리턴타입을 정의하지 않는다.
default 생성자
public class Dog extends Animal {
public Dog() {
}
public void sleep() {
System .out .println (this .name + " zzz" );
}
}
cs
만약 생성자를 정의하지 않았다면 public Dog() { } 와 같은 default 생성자를 컴파일러가 자동 생성한다.
생성자를 정의한다면 컴파일러는 따로 생성자를 만들지 않고, 그 생성자의 정의대로만 객체를 선언할 수 있다.
생성자 오버로딩
하나의 클래스에 다음과 같이 입력항목(인수)이 다른 여러개의 생성자를 만들 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package jump2java;
public class HouseDog extends Dog {
public HouseDog(String name) {
this .setName(name);
}
public HouseDog(char type) {
if (type = = 'm' ) {
this .setName("Steve" );
} else if (type = = 'f' ) {
this .setName("Stephanie" );
}
}
public static void main(String [] args) {
HouseDog houseDog = new HouseDog("Toni" );
System .out .println (houseDog.name);
HouseDog male = new HouseDog('m' );
HouseDog female = new HouseDog('f' );
System .out .println (male.name);
System .out .println (female.name);
}
}
cs
Output :
Toni
Steve
Stephanie
위의 소스에서 HouseDog 클래스는 두 개의 생성자를 갖는다. 하나는 String type, 하나는 char type을 입력으로 받는 생성자이다.
메소드 오버로딩과도 비슷한 개념이다. 단, 메소드 오버로딩은 반환형은 반드시 일치해야 함 에 유의!
오버로딩 시 시그니처가 같다면 오버로딩할 수 없다.
시그니처란 매개변수의 리스트를 가리키며 매개변수의 개수와 타입, 그 순서 까지 모두 같다면 시그니처가 같다.
리턴값만 다를 경우 오버로딩이 성립되지 않는다.
그리고 오버로딩과 오버라이딩은 완전히 다른 개념 이다.