Java개념 - 후반부(접근 제어자, 인터페이스, 다형성, 예외, 참조)
이제 Java의 후반부 개념에 대해서 설명하겠다.
이 부분은 내용이 어려워 매우 기본적인 부분을 내가 이해한만큼만 적어봤다.
● Classpath
일단 Class를 작성하고 컴파일을 하면 각각의 .class파일이 생성된다. 그리고 이것을 다른 package에서 가져다 사용하고 싶을 경우, 클래스 패스를 사용한다. 이것을 환경변수에 설정해놓으면 어디에서나 사용 할 수 있다.
EX> System.out.println(1)
--> 풀이 : System이라는 class에 포함 된 멤버 out이라는 객체(변수) 안에 println메소드를 가지고있다.
● 접근 제어자
- 접근 제어자란? 다른 Class의 접근을 제한하거나 허용하기 위해 만든 것.
- 왜 사용할까? 클래스를 보호하기 위한 것. 실제 내부적으로 계산이 일어나는 부분을 private설정.
- 대표적인 접근자
- Public : 외부 객체들이 자유롭게 사용할 수 있는 메소드나 변수.
- Private : 같은 메소드내에서만 사용 할 수 있다. 아래 예시를 참고.
package org.opentutorials.javatutorials.accessmodifier;
class A {
public String y(){
return "public void y()";
}
private String z(){
return "public void z()";
}
public String x(){
return z();
}
}
public class AccessDemo1 {
public static void main(String[] args) {
A a = new A();
System.out.println(a.y());
// 아래 코드는 오류가 발생한다.
//System.out.println(a.z());
System.out.println(a.x());
}
}
● Abstract
- Abstract 란? Abstract 클래스나 메소드를 사용하기 위해서는 반드시 상속해서 사용하도록 강제하는 것.
<상위 클래스>
public abstract void sum();
public abstract void avg();
<하위 클래스>
public void sum(){
System.out.println("- sum :"+(this.left+this.right));
}
public void avg(){
System.out.println("- avg :"+(this.left+this.right)/2);
}
위와 같이 큰 프로젝트에서 상위 클래스에 선언해놓고 하위 클래스에서 오버라이딩을 통해서 사용한다.
● Final
Final은 실행되는 과정에서 한번 값이 정해진 이후에는 변수 내의 값이 바뀌지 않도록하는 규제다.
상속도 금지. 오버라이딩하는 것을 방지.
● Interface
- 인터페이스란? 하위 클래스에 특정한 메소드가 강제로 존재하게 하는 것.
- 왜 사용할까? 협업을 할 때 서로 소통하기위해서 사용한다.
interface I{
public void z();
}
class A implements I{
public void z(){}
}
기본적인 문법 예시이다.
근데 인터페이스는 특징이 여러가지가 있다.
첫 번째로 하나의 클래스가 여러가지 인터페이스를 가지는 것이 가능하다.
그래서 여러가지 멤버를 하나라도 구현하지 않으면 오류가 발생한다.
두 번째로 인터페이스도 상속이 가능하다. 예를 들면 interface i3 extends i4 이렇게 사용한다.
마지막으로 인터페이스의 멤버는 반드시 public해야한다.
● 다형성
package org.opentutorials.javatutorials.polymorphism;
class A{
public String x(){return "A.x";}
}
class B extends A{
public String x(){return "B.x";}
public String y(){return "y";}
}
public class PolymorphismDemo1 {
public static void main(String[] args) {
A obj = new B();
System.out.println(obj.x());
}
}
위의 예시는 다형성을 한 번에 설명 할 수있는 예시이다.
오버로딩이랑 헷갈릴 수 있는데 오버로딩은 다형성의 특성 중 하나이다.
위의 객체 obj은 A데이터 타입에 B클래스로 만들어져있다.
결론적으로 A클래스 멤버만 이용가능하고 B클래스에서 오버라이딩을 적용할 수 있다.
이처럼 다형성이란 하나의 클래스가 다양한 동작을 할 수 있게 만들어 주는 기능이다.
아래의 실제 사용 예시를 보자.
package org.opentutorials.javatutorials.polymorphism;
interface father{}
interface mother{}
interface programmer{
public void coding();
}
interface believer{}
class Steve implements father, programmer, believer{
public void coding(){
System.out.println("fast");
}
}
class Rachel implements mother, programmer{
public void coding(){
System.out.println("elegance");
}
}
public class Workspace{
public static void main(String[] args){
programmer employee1 = new Steve();
programmer employee2 = new Rachel();
employee1.coding();
employee2.coding();
}
}
위의 Steve와 Rachel은 다양한 인터페이스를 만족해야한다. 하지만 workplace에서는 두 명이 프로그래머다 라는 특성이 중요하므로 원하는 기능만을 구현하여 사용 할 수 있다. 그리고 그 안에 coding이라는 method를 통하여 프로그래머 특성을 알 수 있다. 이처럼 인터페이스를 데이터 타입으로 선언하면서 각 인터페이스가 가진 멤버들을 다양하게 구현 할 수 있는 특징이 있다.
● 예외
- 예외란? 비정상적인 부분을 통틀어서 말하는 것.
- 핵심 문법(try... catch...)
아래의 예시를 살펴보자.
위의 예시에서는 try내의 코드를 실행하다가 "계산결과는"까지 실행되고 catch를 찾아가서 매개변수로 받은 Exception이라는 데이터 타입의 클래스 객채인 e를 받아서 그 클래스 내의 getMessage라는 메소드를 실행시킨다.
추가적으로 e객체메소드에서 getMessage는 간단한 에러, printStackTrace는 구체적인 에러를 출력.
이 부분은 다중 try..catch..문이다. 각 에러에 따라서 다른 에러 메세지를 출력하므로 더 가독성이 뛰어나다. 그러나 여기서 주의 할 점은 catch(Exception e){}는 모든 에러를 포함하므로 제일 밑에 적어줘야 위의 catch들이 다 실행되고 마지막에 실행된다.
- Finally
try catch문에 finally를 붙이면 예외발생과는 전혀 상관없이 무조건 마지막에 실행되는 로직.
- Throw
예외처리 부분을 계속 상위 클래스로 넘겨서 처리함.
내 생각에 장점은 각 클래스에서 일어 날 수 있는 예외상황들을 모두 한 곳에 모아 처리하기 때문에 가독성이 좋음.
package org.opentutorials.javatutorials.exception;
import java.io.*;
class B{
void run() throws IOException, FileNotFoundException{
BufferedReader bReader = null;
String input = null;
bReader = new BufferedReader(new FileReader("out.txt"));
input = bReader.readLine();
System.out.println(input);
}
}
class C{
void run() throws IOException, FileNotFoundException{
B b = new B();
b.run();
}
}
public class ThrowExceptionDemo {
public static void main(String[] args) {
C c = new C();
try {
c.run();
} catch (FileNotFoundException e) {
System.out.println("out.txt 파일은 설정 파일 입니다. 이 파일이 프로잭트 루트 디렉토리에 존재해야 합니다.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Throw = B -> C -> main
- 예외의 종류
위의 도식표는 주요 예외 클래스의 관계도이다.
1. Throwable
이 클래스는 Error와 Exception의 공통된 조상 class이다. 그러나 직접적으로 우리가 사용하진 않는다.
2. Error
이 클래스는 JVM에 문제가 있을 경우 발생하는 예외이다. 예를 들면 프로세싱 중 메모리 부족 등이 있다.
그래서 해결하기 위해서는 메모리를 효율적으로 사용할 수 있도록 변경하는 방법이다.
3. Exception
하위 2가지 경우로 나뉜다.
- checked 예외 - RuntimeException을 제외한 Exception의 하위 클래스
- unchekced 예외 - RuntimeException의 하위 클래스
두 가지의 차이점은 예외 처리 필수냐 아니냐이다. checked는 예외처리 필수. unchekced는 해도 되고 안해도 된다.
따라서 잘 구분해서 예외 처리를 해줘야한다.