◻️ Java 나중에 살펴볼 자료
본 자료는 유튜브 주간컴공의 프로그래밍 언어 활용(Java)을 정리한 내용이다.
지금은 언어를 잘 몰라서 이해가 되지 않지만 나중에 돌아와서 살펴보기 위해 작성해 놓았다.
◻️ Java
클래스와 객체
1) Java에서의 클래스Java
는 모든 코드가 클래스이다main
메소드를 포함하는 클래스를 가장 먼저 실행한다멤버(member)
: 클래스에 포함되는 요소- 데이터는 객체 생성을 통하여 확보한다
1
2
3
4
5
6
7
8
9
10
11
// Circle 클래스 정의
class Circle{
...
}
// Hello World 클래스 정의(프로그램 시작지점)
public class HelloWorld{
public static void main(String[] args){
...
}
}
2) 클래스의 구성
1️⃣ 멤버 변수
- 객체가 가지는 모든 상태, 수치, 성질
- C언어에서의 구조체(사용자 정의 자료형)과 유사
- 다른 객체에서 접근할 수 없도록 정보은닉하여 사이드 이펙트 최소화
2️⃣ 멤버 메소드
- 객체에서 발생하는 모든 연산 및 제어, 요청행위
- C언어에서의 함수와 유사
1
2
3
4
5
6
7
8
9
10
11
12
// Circle 클래스 정의
class Circle{
// 멤버 변수 정의
double pi = 3.141592;
double radius;
// 멤버 메소드 정의
void volume(){
// 원의 부피 출력
System.out.println(radius * radius * pi);
}
}
Java
의 출력 메소드print
는 그냥 출력만하는print
,- 줄바꿈까지 해주는
println
이 있고 - 서식 지정이 가능한
printf
까지 총 3가지가 대표적이다
3) 접근 지정자
1️⃣ 접근 지정자의 정의
- 클래스 내 멤버들의 접근 수준을 결정하는 토큰
- 프로그램, 패키지, 하위 클래스, 자신의 순서
2️⃣ 접근 지정자의 종류
- public: 프로그램 내 모든 객체에서 접근 가능
- default(생략): 같은 패키지 안에서만 접근 가능
- protected: 자신과 하위 클래스에서만 접근 가능
- private: 자신의 클래스에서만 접근 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 접근 지정자를 생략하면 default로 인식
class Circle{
// 멤버 변수는 외부 접근 불가능
private double pi = 3.141592;
private double radius;
// 같은 패키지 안에서만 접근 가능
void volume(){
System.out.println(radius * radius * pi);
}
// private 멤버 접근을 위한 public 메소드 정의
public void set_radius(double r){
radius = r;
}
}
4) 생성자(Constructor) 메소드
1️⃣ 생성자 메소드의 정의
- 클래스 내부에 존재하며 객체 생성시 자동으로 실행
- 객체가 생성될 때 외에는 별도로 실행 불가
- 정의되어 있지 않으면 자바에서 자동 생성
- 객체 생성시 멤버 변수 초기화 처리
- 생성자 메소드명은 클래스명과 동일, 리턴 타입 없음
2️⃣ this - 클래스 자신에 포함된 멤버 변수에 접근하기 위한 토큰
- 메소드 명이 같아도, 매개변수의 개수나 타입이 다르면 사용 가능
- 이름이 동일한 다른 지역 변수와 구분을 위한 사용
3️⃣ Overloading - 동일한 이름을 가진 여러 메소드를 사용하는 기술
- 같은 메소드명으로 서로 다른 기능을 정의할 수 있는 오버로딩
- 메소드의 인수 유형과 개수의 차이로 각 메소드 구별
- 생성자 메소드 뿐 아니라 모든 메소드에 적용 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Circle{
private double pi = 3.141592;
private double radius;
// 실수 인수를 전달하여 객체 생성시 자동실행
Circle(double radius){
this.radius = radius;
System.out.println("객체가 생성되었습니다.");
}
// 인수 전달 없이 객체 생성시 자동실행
Circle(){ // 같은 메소드 명으로 서로 다른 기능을 정의하는 오버로딩
this radius = 3.0;
System.out.println("기본 객체가 생성되었습니다");
}
}
public class HelloWorld{
public static void main(String[] args){
Cicle c1 = new Cicle(5.0); // 인수를 전달하여 객체 생성시 호출
Cicle c2 = new Cicle(); // 인수 없이 객체 생성시 호출
}
}
5) 객체 생성
1️⃣ 인스턴스 생성
- 새로운 객체를 생성하여 적절한 타입의 변수에 할당
- new 키워드를 이용하여 인스턴스를 생성 ➡ 생성자 호출
- 일반적으로 인스턴스의 타입과 객체 변수의 타입이 동일함
2️⃣ 객체의 멤버 접근
- 객체변수와 점(.)을 이용
- 접근 지정자에 따라 직접 접근이 어려울 수 있음
- 멤버 변수에 static 키워드를 붙여 생성하면, 모든 객체가 공유하는 데이터 생성 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Circle{
private double pi = 3.141592;
private double radius;
private static int cnt = 0;
Circle(double radius){
this.radius = radius;
this.cnt++; // static 변수를 증가시켜줌
System.out.println(this.cnt + "번 객체가 생성되었습니다.");
}
void created_cnt(){
System.out.println("총 " + this.cnt + "개 도형이 존재합니다.");
}
}
public class Helloworld{
public static void main(String[] args){
// Cicle 인스턴스 생성
Circle c1 = new Circle(5.0); // static이기 때문에 +1
Circle c2 = new Circle(4.0); // +1
Circle c3 = new Circle(6.0); // +1 결과로 출력됨
c1.created_cnt();
}
}
상속
1) 상위 클래스
- 상위 클래스는 대부분의 속성을 하위클래스에게 상속
- 여러 하위 클래스가 사용할 공통된 속성을 구현
- 상위 클래스 단독으로 인스턴스 생성 가능
2) 하위 클래스
- 상속 받은 상위 클래스 대부분의 속성을 포함
- extends 키워드를 사용하여 상속받을 상위 클래스 지정
- 상위 클래스의 매소드를 재사용, 재정의하여 사용
3) Overriding
- 상위 클래스의 메소드를 재정의하여 사용하는 기술
- 상위 클래스와 동일한 메소드명과 매개변수 지정
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
class Espresso{
int espresso = 20;
void recipe(){
System.out.println("에스프레소 " + espresso + "ml");
}
}
class Americano extend Espresso{ //아메리카노 클래스에서 Espresso를 상속받음
int water = 80;
// water 변수밖에 없지만, 상속을 받았기 때문에 Espresso 변수 역시 사용 가능
// 따라서 recipe 메소드도 사용 가능
void recipe(){
// Espresso 클래스의 recipe 메소드를 재정의하여 사용할 수 있다
// 이렇게 하면 Espresso 인스턴스의 레시피 메소드는 에스프레소 용량만,
// 아메리카노 인스턴스의 레시피 메소드는 에스프레소와 물이 나온다!
System.out.print("에스프레소 " + espresso + "ml + 물" + water + "ml");
}
}
public class HelloWorld{
public static void main(String[] args){
Espresso e1 = new Espresso();
e1.recipe();
Americano a1 = new Americano();
a1.recipe();
}
}
4) 추상 클래스
1️⃣ 추상 클래스 개념
- 클래스의 체계적인 설계를 위해 사용하는 클래스
- 선언부만 있고 구현부가 없는 추상 메소드를 하나 이상 포함
- 반드시 하위 클래스에서 상속하여 추상 메소드를 오버라이딩 해야 인스턴스 생성 가능
- 상속된 클래스에서도 구현되지 않은 추상 메소드가 있다면 그 역시 추상 클래스이므로 인스턴스 생성 불가
- 각각의 하위 클래스에서 수행되는 유사한 기능을 하나의 이름으로 통일 가능
2️⃣ 추상 클래스 구현
- abstract 키워드를 사용하여 클래스와 매소드 구현
- 메소드의 구현부(중괄호)를 생략하여 표현
- 추상 클래스를 상속받은 후 해당 메소드를 오버라이딩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
abstract class Shape{
abstract void draw();
}
class Circle extends Shape{ //Circle과 Rectangle 클래스가 각각 상속받아 메소드 오버라이딩 진행
void draw(){
System.out.println("원을 그립니다");
}
}
class Rectangle extends Shape{
// Circle과 Rectangle은 같은 메소드명으로 각각 다른 일을 할 수 있게 됨(상속의 힘)
void draw(){
System.out.println("사각형을 그립니다")
}
}
public class HelloWorld{
public static void main(String[] args){
Circle c1 = new Circle();
Rectangle r1 = new Rectangle();
c1.draw();
r1.draw();
}
}
5) 인터페이스
Java
에서는 여러 클래스를 다중 상속 받을 수 없다. 상속관계가 복잡해지면 알 수 없는 부작용이 발생할 확률이 매우 높아지기 때문이다- 따라서 인터페이스를 사용하여 다중상속의 이점을 활용할 수 있다.
1️⃣ 다중 상속의 문제점
- 다중 상속: 둘 이상의 상위 클래스를 상속받는 것
- 상위클래스 A, B가 같은 클래스 C를 상속받는 경우와 같이 상속 관계가 복잡해지면 알 수 없는 부작용 발생할 확률 상승
2️⃣ 인터페이스의 특징
- 모든 메소드가 추상 메소드로 정의되어 있는 추상 클래스
- 상속을 받지 않기 때문에 다중 상속의 부정적 영향을 전혀 받지 않고 다중 상속의 장점 활용 가능
- 상속은 기존 클래스의 속성을 확장하는 개념을 가지지만, 인터페이스는 하나의 확장된 클래스로 기능을 제한하거나 다른 기능을 수행하도록 변경(다형성)
3️⃣ 인터페이스 구현
- class 대신 interface 키워드를 사용하여 구현하고, implements 키워드를 사용하여 상속
- 확장된 클래스의 인스턴스를 상위 인터페이스 타입의 객체 변수에 할당하여 기능을 변경하거나 제한
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
29
30
31
32
33
34
interface Coffee{
abstract void drink_coffee();
}
interface Cookie{
abstract void eat_cookie();
}
class Cafe implements Coffee, Cookie
{
public void drink_coffee(){
System.out.println("커피를 마신다.");
}
public void eat_cookie(){
System.out.println("쿠키를 먹는다.");
}
public void talk(){
System.out.println("대화를 한다.");
}
}
public class HelloWorld{
public static void main(){
Cafe k = new Cafe();
k.drink_coffee();
k.eat_cookie();
k.talk();
Coffee c = k; //커피 객체 변수에 할당
c.drink_coffee();
Cookie x = k; //쿠기 객체 변수에 할당
x.eat_cookie();
}
}
👀 위에서 Cafe
객체는 drink_coffee
, eat_cookie
, talk
까지,
3가지 메소드 사용이 가능한 상태가 된다. 따라서 객체를 생성하면 3가지 메소드 호출이 전부 가능하다
그런데 만약 3가지 기능이 가능한 카페 인스턴스를 일시적으로
drink_coffee
만 가능하도록 제한을 걸어주고 싶다면, 해당 객체를 커피 객체 변수에 할당하면 된다.
이렇게 하면 새로이 커피 객체를 만들 필요 없이
커피 객체만으로도 커피 기능을 하는 객체역할을 수행할 수 있게 된다(쿠키도 마찬가지)
하나의 확장된 객체로 모든 기능, 또는 일부 기능만을 수행할 수 있는 형태로
변형이 가능한 상태, 이게 바로 다형성의 특징이며 객체지향 기술의 궁극적인 목표가 된다.
예외처리
1) 예외처리개념
- 예외를 해결(처리)하는 코드를 구현하는 것이다
- 문법 오류(Syntax Error): 괄호를 잘못 쓰거나, 함수명 오타 등으로 발생하는 문제
- 예외: 문법이나 표현식에는 문제가 없지만 의도치 않은 작동 및 입력으로 문제가 발생하는 것
2) Java의 예외처리 방식
- 예외가 발생할 수 있는 영역을
try
블록으로 감싸고 - 예외처리를 위한 코드를
catch
블록으로 감싸둔다 catch
블록은 예외가 발생하지 않으면 실행되지 않는다finally
블록은 무조건 실행하는 부분이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class HelloWorld{
public static void main(String[] args){
// 멤버 변수 영역
try{
// 예외 감지 영역
}
catch{
// 예외 감지시 실행 영역
}
finally{
// 무조건 실행되는 영역
}
}
}