외부 패키지의 클래스를 불러 사용하고자 할 경우 원래는 클래스명 앞에 패키지를 명시해야 한다. 예를 들어서 Random이라는 클래스가 java.util 패키지에 속해 있다. 이것을 불러 사용하려면 다음과 같이 해야 한다.


java.util.Random rand = new java.util.Random();


즉, Random 클래스 앞에 java.util 이라는 소속 패키지의 이름을 명시해야 하는데 여러 군데에서 Random클래스가 사용된다면 패키지 이름이 중복되어 불편한다. 그래서 import 명령을 사용하면 클래스가 속한 패키지 명을 생략할 수 있다.


package tut_20;

import java.util.Random;

public class Tut_20 {
   public static void main(String[] args) {
       Random rand = new Random();
   }
}


이와 같이 import 뒤에 패키지명을 포함한 클래스의 전체 경로를 명시해 주면 코드에서는 클래스 이름만 써주면 된다.


 만약 java.util.Data 라는 클래스를 사용하고 싶다면 import 문을 하나 더 추가하면 된다.


package tut_20;

import java.util.Random;
import java.util.Date;

public class Tut_20 {
   public static void main(String[] args) {
       Random rand = new Random();
       Date dt = new Date();
   }
}


이런 식으로 현재 파일에서 사용하는 외부 클래스는 얼마든지 import문으로 불러와서 사용할 수 있다.


 동일한 패키지의 모든 클래스를 불러오고 싶다면 와일드카드(*)문자를 사용하면 된다. 예를 들어서 java.util 패지키의 모든 클래스를 불러오고 싶다면 다음과 같이 하면 된다.


import java.util.*;


이렇게 하면 java.util 패키지의 모든 클래스를 사용할 수 있다.


package tut_20;

import java.util.*;

public class Tut_20 {
   public static void main(String[] args) {
       Random rand = new Random();
       Date dt = new Date();
       List<Long> al = new List<>();
   }
}


이 예에서 Random, Data, List 클래스는 모두 java.util 패키지에 속해 있으르모 하나의 import 문으로 충분하다. 하지만 와일드카드를 사용한 import 가 하위 패키지의 클래스까지는 포함하지 않는다는 점에 유의해야 한다.


 같은 패키지 내의 클래스는 import를 할 필요가 없이 바로 사용 가능하다. 그리고 java.lang 패키지의 클래스도 import할 필요가 없다. 따라서 String 클래스는 java.lang 패키지 내에 있지만 import하지 않아도 바도 사용할 수 있는 것이다.



Posted by 살레시오
,

 조건문을 처리하는 두 번째 방법은 switch-case구문을 사용하는 것이다. if문과는 달리 swtich-case구문은 하나의 변수에 대해서 여러 가지 경우를 처리해야 되는 경우에 좀 더 유용하다. 문법은 다음과 같다.


switch 표현식
   case 대조값1
       명령집합1
   case 대조값2
       명령집합2
   ː
   otherwise
       명령집합m
end


동작 순서는 다음과 같다. switch문 다음에 오는 표현식의 값을 계산한 후에 그 값이 대조값1 과 같으면 명령집합1을 수행한 후 end 다음으로 이동한다. 대조값1과 다르면 대조값2와 비교하여 같으면 명령집합2를 수행한 후 end 다음으로 이동한다. 모든 case문 뒤의 대조값들과 다른 경우 otherwise뒤의 명령집합m을 수행하게 된다.


 이 swtich-case구문을 사용하여 이전 포스트의 2차 방정식 근의 종류를 판별하는 프로그램을 작성해 보자. 여기서 switch문 뒤의 표현식에서 sign()함수를 사용할 것인데 sign(D) 함수는 입력 D값이 음수이면 -1을, 0이면 0을 그리고 양수이면 +1을 반환하는 함수이다. 즉 부호(sign)를 판별하는 함수인 것이다. 다른 부분은 앞의 경우와 크게 다른 것은 없고 다만 8번줄에서 시작되는 switch-case구문의 사용법에 유의하라.


clear all
a=input('x^2의 계수:')
b=input('x의 계수:')
c=input('상수 계수:')
D = b^2-4*a*c;
s = roots([a b c]);
sprintf('방정식 %.2fx^2+%.2fx+%.2f=0은 ',a,b,c)
switch sign(D)
   case 1
       sprintf('서로 다른 실근') %(1)
   case 0
       sprintf('중근') %(2)
   otherwise
       sprintf('허근')%(3)
end
s


switch문에서 sign(D)값을 계산한 후 그 값이 1이면 (1)을 수행하고 제어 흐름이 end 밖으로 이동한다. sign(D)값이 0이면 (2)를 수행하고 제어 흐름이 end 밖으로 이동한다. sign(D)값이 0도 아니고 1도 아니면 (3)을d 수행한 후 end 밖으로 이동한다.



Posted by 살레시오
,

 많은 경우에 있어서 명령어들은 어떤 관계의 참, 거짓 여부를 따져서 조건부로 실행시켜야 되는 경우들이 있다. 여기에서는 이런 경우에 사용되는 if문과 switch문에 대해서 살펴보겠다.

 if문의 가장 간단한 사용법은 다음과 같다.


if 조건문
   명령집합
end


여기서 조건문이 참(0이 아닌값)이면 if명령어와 end 사이의 명령집합을 실행시키고 거짓(0)이면 명령집합을 실행시키지 않는다. 간단한 예제를 작성해 보자. 사과를 구입하는데 사과 하나에 500원이고 만약 사과를 10개 이상 구입을 하면 가격의 20%를 깎아준다고 한다. 사과의 개수를 입력받아서 가격을 구하는 프로그램은 다음과 같이 작성할 수 있다.


clear all
n = input('사과의 개수는?');
cost = n*500;
if (n>=10)
   cost = 0.8*cost;
end
sprintf('사과의 개수는 %d개이고 가격은 %d입니다.',n,cost)


둘째 줄에서 input()함수를 이용하여 사과의 개수를 입력받아 변수 n에 저장하였고 네째 줄에서 입력받은 개수가 10보다 크거나 같은지를 조건검사한다. 그래서 10이상이면 계산된 가격에 0.8을 곱해서 가격을 다시 계산한 후 일곱 번째 줄에서 가격을 화면에 표시하게 된다.


 위의 프로그램에 대해서 한번만 더 생각하면 더 간단하게 작성할 수 있다. 조건문 (n>=10)을 생각해보면 이 조건은 변수 n이 10이상이면 1값을 가지고 10보다 작으면 0을 갖는다. 이 사실을 이용해서 다음과 같이 간단하게 줄일 수 있다.


clear all
n = input('사과의 개수는?');
cost = (1-0.2*(n>=10))*n*500;
sprintf('사과의 개수는 %d개이고 가격은 %d입니다.',n,cost)


여기서 세 번째 줄에서 사용된 조건식 (1-0.2*(n>=10))를 살펴보면 만약 변수n이 10이상이면 (n>=10)이 1값을 가지므로 (1-0.2*(n>=10))는 0.8의 값을 가지게 되고 변수n이 10보다 작으면 (n>=10)이 0값을 가지므로 (1-0.2*(n>=10))는 1.0의 값을 가지게 된다. 이 예제는 앞의 프로그램과 완전히 동일한 결과를 생성하며 if문을 사용한 예는 아니지만 조금만 생각해 보면 프로그램을 훨씬 간결하고 효율적으로 작성할 수 있음을 보여준다.

 여러 가지 조건을 한꺼번에 검사하기 위해서는 else명령어나 elseif명령어를 if문에 사용한다. if 뒤의 조건이 참(0 이외의 값)이면 뒤에 따라오는 명령문을 수행하고, 거짓(0)이면, 뒤에 나오는 나 elsief문 뒤의 조건을 판별하여 명령문을 수행한다. 문법은 다음과 같다.


if (조건1) %조건 1이 참이면 명령집합1을 수행하고 끝냄
   명령집합1
elseif (조건2) %조건2가 참이면 명령집합2를 수행
   명령집합2
else % 조건1,2 모두 거짓이면 명령집합 3을 수행
   명령집합3
end


예를 들면 다음과 같다.


if (a>1)
   k = 1;
elseif (a<-1)
   k = 100;
else
   k = 1000;
end


이 예제를 실행하고 나면 a>1 이면 k=1, a<-1 이면 k=100, -1≤a≤1 이면 k=1000 의 값을 갖게 된다. 이 예제의 경우도 다음과 같이 작성할 수 있다.


k = (a>1) + 100*(a<-1) + 1000*(a>=-1 & a<=1)


 이제 if-else-end문을 이용하여 2차 방정식의 해를 구하는 프로그램 예제를 작성해 보자. 2차 다항식 ax2+bx+c 의 세 계수를 입력받아서 판별식 D=b2-4ac를 계산한 후 이 판별식의 부호에 따라서 각각 다른 메시지를 출력하는 프로그램을 작성해보도록 하겠다. 다항식의 근을 구하기 위해 앞에서도 소개되었던 roots()함수를 이용하도록 한다. 판별식의 부호에 따라서 두 개의 실근을 가지는지, 중근을 가지는지 그리고 허근을 가지는지를 화면에 출력해보도록 하겠다.


clear all
a=input('x^2의 계수:')
b=input('x의 계수:')
c=input('상수 계수:')
D = b^2-4*a*c;
s = roots([a b c]);
if (D>0)
   sprintf('서로 다른 실근')
elseif (D==0)
   sprintf('중근')
else
   sprintf('허근')
end
s


여기에서 if-elseif-else문이 사용되었다. D가 양수냐, 음수냐, 0이냐에 따라서 다른 명령이 실행이 된다는 것을 알 수 있다.



Posted by 살레시오
,

 가상 머신(virtual machine)이라는 것은 소프트웨어로 작성된 기계 (영어권에서는 컴퓨터 하드웨어를 machine이라고 지칭하기도 한다.) 즉, 코드로 작성된 가상의 물리적인 하드웨어라는 의미이다. 가상 머신은 컴퓨터 안에 존재하는 소프트웨어로 구현된 컴퓨터를 의미하며 광범위하게 사용되고 있는 기술 분야이다.


[그림 1] 윈도 머신에서 가상 머신으로 데비안 리눅스를 실행하고 있는 모습


 자바 가상 머신 (java virtual machine, JVM)은 자바 애플리케이션을 수행하기 위한 가상 머신이다. 일반적으로 보통의 응용 프로그램은 운영 체제를 거쳐서 물리적인 머신(machine)에서 수행된다.


[그림 1] 일반적인 응용 프로그램의 수행 단계


하지만 자바 애플리케이션은 운영 체제와 물리적인 머신이 아니라 JVM 위에서만 수행되고 그 밑단의 모든 동작은 JVM이 알아서 처리하는 방식으로 동작한다. 따라서 자바로 작성된 프로그램은 윈도우즈용 JVM이 설치된 윈도 머신에서도 동작하며 맥용 JVM에 설치된 맥 머신에서도 동일한 코드가 동일하게 수행된다.(Write once, run everywhere.)


[그림 2] 자바 가상 머신에서의 자바 프로그램 동작 단계


윈도만을 혹은 맥만을 주로 사용하는 일반 사용자들은 JVM을 별도로 설치해야 하는 번거로움이 있기 때문에 별 의미가 없을 수 있다. 하지만 개발자 입장에서는 이것은 커다란 장점이다. 자바로 한 번 작성해 놓은 코드는 OS와 피지컬 머신에 상관없이 어디에서나 동일하게 수행되기 때문이다.


 이런 동작 방식의 단점은 JVM이라는 단계를 하나 더 거치기 때문에 성능은 일반적인 프로그램(예를 들어서 컴파일된 C/C++ 프로그램)에 비해서 떨어진다는 점이다. 컴파일된 자바 프로그램은 JVM에서 수행되는 바이트 코드(byte code)로 구성되고 이것을 JVM이 하나씩 해석하여 수행하는 방식으로 동작하기 때문이다. 하지만 요즈음에는 JVM 자체의 성능도 상당히 향상되어 네이티브 프로그램의 수행 속도와 거의 동등한 결과를 보여주고 있다. 이는 바이트 코드를 수행하기 전에 컴파일하는 JIT (just-in-time) 컴파일링과 자바 바이트 코드를 피지컬 머신에 최적화된 네이티브 기계어 코드로 변환하는 핫스팟(hotspot) 기능이 JVM에 도입되었기 때문이다.



Posted by 살레시오
,

 자바의 패키지(package)는 클래스(interface, enum..)의 묶음으로서 하나의 디렉토리(폴더)이다. 패키지의 이름과 같은 디렉토리 내에 클래스 파일들을 포함하며 하위 패키지도 포함하는 중첩된 구조도 가능하다. ( C/C++에 비해서 무척 단순한 구조를 가지고 있다.)


[그림 1] 자바의 패키지 구조. 패키지는 디렉토리임.


퍼블릭 클래스(퍼블릭 인터페이스, 퍼블릭 이넘..)가 물리적으로 하나의 파일인 것과 유사하게 패키지는 물리적으로 하나의 디렉토리이다. 즉, 같은 폴더 내의 이러한 파일들이 패키지를 구성한다. 예를 들어서 java.lang.System 클래스는 java패키지의 하위 패키지인 lang에 속한다. 따라서 물리적으로 java디렉토리 밑의 lang디렉토리 밑의 System.class 파일이다.


 예를 들어서 netbean에서 tut01이라는 프로젝트를 생성하면 처음에 다음과 같으 구조를 가진다. tut01이라는 프로젝트 폴더 밑에 src/tut01 폴더가 tut01 패키지가 된다. 그리고 그 안에 Tut01.java파일이 자동으로 생성되며 맨 첫 줄에 패지지가 명시되어 있다.


[그림 2] tut01 프로젝트 생성


클래스 파일의 (주석과 공백을 제외한) 맨 처음에는 소속 패키지를 선언하는 단일문이 위치해야 한다. [그림 2]에서도 맨 첫 줄에 ‘package tut01;’이라고 소속 패키지가 명시되어 있다.


 하나의 프로젝트는 일반적으로 하나 이상의 패키지를 포함한다. <프로젝트 디렉토리>/src 디렉토리 안에 패키지를 생성할 수도 있고 특정 패키지 안에도 하위 패키지를 생성할 수 있다.


[그림 3] 새로운 패지키들의 생성


해당 폴더에 들어가서 확인해 보면 새로운 패키지를 생성하면 같은 이름의 폴더가 생성된 것을 알 수 있다.


[그림 4] 생성된 폴더


위 그림에는 안 보이지만 tut01 폴더 하위에 sub01 패키지(폴더)가 생성되어 있고 src 밑에는 tut02, tut03 이라는 폴더가 생성된 것을 알 수 있다.


 그리고 자바 프로젝트를 빌드하면 <프로젝트디렉토리>/dist 디렉토리 밑에 jar 파일이 생성되는데 이것은 프로젝트 내의 모든 컴파일된 패키지를 포함한 압축파일이다. 예를 들어서 위의 프로젝트를 빌드하면 tut01/dist/tut01.jar 파일이 생성된다. 이 파일을 열어보면 이 프로젝트에 포함된 패키지들이 생성되어 있음을 알 수 있다.


[그림 5] winrar로 본 tut01.jar의 내용. tut01, tut02, tut03 패키지(디렉토리)가 보인다.


이것을 실행하려면 명령창에서 다음과 같이 하면 된다.


java -jar tut01.jar


[그림 6] 일반적인 자바 프로젝트(jar파일) 구조


 이와 같이 프로젝트는 패키지의 모음이며 패키지는 클래스 파일들의 묶음이라는 자바 디렉토리의 구조를 이해해야 한다.



Posted by 살레시오
,

 자바 인터페이스(interface)는 추상 클래스와 비슷한 점이 있지만 한 단계 더 추상화된 클래스이다. 기본적으로 다음과 같이 정의한다.


interface 인터페이스명 {
   public static final 자료형 변수명 = 변수값;
   public abstract 반환자료형 함수명(입력인자들);
}


인터페이스의 멤버 변수는 public static final 로만 지정 가능하고 이것은 생략할 수 있다. 인터페이스 변수는 final 이므로 반드시 변수값을 선언부에 지정해 주어야한다.  멤버는 public abstract 가 기본형으로서 이것도 생략할 수 있다. 예를 들면 다음과 같다.


interface IA {
   int ia = 11; // 앞에 public static final 이 생략됨
   void fun();  // 앞에 public abstract 가 생략됨
}


인터페이스도 추상 클래스와 마찬가지로 직접 객체를 생성할 수 없으며 이것을 구현하는 클래스는 객체화 할 수 있다.


class CA implements IA {
   public void fun() {
       int ib = ia + 11; // ia는 인터페이스에서 정의된 정적 변수이다.
       System.out.println(“fun() redefined.”);
   }
}


추상클래스와 다르게 인터페이스는 이를 구체화하기 위해 implements 라는 키워드를 사용하고 그 뒤에 구현할 인터페이스 명을 써야한다. IA를 구체화하기 위해서는 반드시 추상 메소드인 fun()의 본체를 위와 같이 정의하여야 한다. 그리고 fun()의 접근 지정자는 반드시 public이어야 한다. 그 이유는 인터페이스에서 (생략되었다 할 지라도) public abstract 으로 정의되었기 때문이다.


 실행 가능한 예를 들면 다음과 같다.


package tut03;

public class Tut03 {
   public static void main(String[] args) {
       Violin v1 = new Violin();
       v1.ready();
       v1.play();

       Guitar g1 = new Guitar();
       g1.ready();
       g1.play();
   }
}

interface Playable {
   String player = "살레시오";
   void ready();
   void play();   
}

class Violin implements Playable {
   public void ready() {
       System.out.println(player+"의 바이올린이 준비되었다.");
   }
   public void play() {
       System.out.println("낑~깡~낑~깡~");
   }
}

class Guitar implements Playable {
   public void ready() {
       System.out.println(player+"의 기타가 준비되었다.");
   }
   public void play() {
       System.out.println("디리링~디리링~");
   }    
}


이 예에서는 Playable 이라는 인터페이스를 구현한 Violin과 Guitar 클래스를 작성하였다. 인터페이스의 이름은 관례적으로 ~able 로 끝나는 것들이 많다.


 이와 같이 인터페이스는 구현하고자하는 여러 클래스의 공통적인 부분(정적 변수와 public 함수)만 기술해 놓은 기초 설계도와 같고 인터페이스를 구현하는 클래스에서 추상 메소드의 몸체를 모두 정의하도록 강요한다. 만약 인터페이스 구현하는 어떤 클래스가 모든 추상 메소드를 구현하지 않는다면 그 클래스는 추상 클래스가 되어야 한다는 점도 알아두어야 한다. JAVA8에서는 인터페이스에 대한 규약이 좀 더 확장되었는데 이것은 다른 포스트에서 다루도록 하겠다.



Posted by 살레시오
,

 넘파이(numpy)를 사용하기 위해서는 다음과 같이 import 해야 한다. winpython, python(x,y)에는 기본적으로 포함되어 있으므로 바로 사용할 수 있다. import 명령을 이용하면 되는데 다음과 같이 몇 가지 방법이 있다.


>>> import numpy # 넘파이의 모든 객체를 numpy.obj 형식으로 불러 사용할 수 있다.
>>> import numpy as np  # 넘파이의 모든 객체를 np.obj 형식으로 불러 사용할 수 있다.
>>> from numpy import * # 넘파이의 모든 객체를 내장 함수 (객체) 처럼 사용 가능.

 

넘파이는 ndarray (n-dimensional array 의 약어, 이후 배열) 라는 객체를 사용하는데 이는 리스트와 유사하지만 다차원 데이터의 연산에 좀 더 효율적이라고 한다. 리스트는 모든 형식의 객체를 저장할 수 있지만 배열은 한 행의 요소는 모두 같은 자료형어야 한다.

배열 생성

 배열을 입력하는 가장 기본적인 함수는 array() 이다. 첫 번째 인자로 리스트를 받는데 이것으로 array객체를 생성한다.

>>> np.array( [1, 2, 3] ) #1차 배열 (벡터) 생성
>>> np.array( [ [1, 2, 3], [4, 5, 6] ) # 2x3 크기의 2차원 배열 (행렬) 생성

일반적으로 3차원, 4차원, ... , n차원 배열도 중첩리스트를 이용하여 유사하게 생성할 수 잇다.

 파이썬의 내장 함수인 range()와 유사하게 배열 객체를 반환해주는 arange() 함수가 있다.

>>> np.arange(10) # 1차원 배얼 [0,1,2, ... ,9] 생성


그리고 시작점과 끝점을 균일 간격으로 나눈 점들을 생성해주는 linspace()함수도 있다.


>>> c = np.linspace(0, 1, 6)   # start, end, num-points
>>> c
    array([ 0. , 0.2, 0.4, 0.6, 0.8, 1. ])

>>> d = np.linspace(0, 1, 5, endpoint=False)
>>> d
    array([ 0. , 0.2, 0.4, 0.6, 0.8])

생성된 배열은 reshape() 함수를 이용하여 행수와 열수를 조절할 수 있다.

>>> a = np.arange(10) # 1차원 배열 [0,1,2, ... ,9] 생성
>>> a = a.reshape(2,5) # 같은 요소를 가지고 2x5 배열로 변형


특수 행렬 생성

 넘파이에는 특수 행렬을 생성하기 위한 함수들이 있다. zeros(), ones() 라는 함수들은 각각 0과 1로 채원진 배열을 생성하는데 차수를 정수 혹은 튜플로 받는다. 예를 들어서 0으로 채워진 5x5 배열을 만들고 싶다면 다음과 같이 한다.

>>> b1 = np.ones( 10 ) # 1로 채원진 10 크기의 (1차원) 배열 생성
>>> b2 = np.zeros( (5,5) ) # 0으로 채원진 5x5 크기의 배열 생성


대각행렬을 생성하기 위한 eye() 함수와 diag() 함수도 있다. eye() 함수는 항등행렬을 생성하고 diag()는 주어진 정방행렬에서 대각요소만 뽑아내서 벡터를 만들거나 반대로 벡터요소를 대각요소로 하는 정방행렬을 만들어 준다..

  

         정의 : eye(N, M=, k=, dtype=), M은 열 수, k는 대각 위치(대각일 때가 0), dtype은 데이터형


>>> np.eye(2, dtype=int)
    array([[1, 0],
           [0, 1]])

>>> np.eye(3, k=1)
    array([[ 0.,  1.,  0.],
           [ 0.,  0.,  1.],
           [ 0.,  0.,  0.]])


         정의:  diag(v, k=0), v는 array_like, k는 대각 위치


>>> x = np.arange(9).reshape((3,3))
>>> x
    array([[0, 1, 2],
           [3, 4, 5],
           [6, 7, 8]])
>>> np.diag(x)
    array([0, 4, 8])
>>> np.diag(x, k=1)
    array([1, 5])
>>> np.diag(x, k=-1)
    array([3, 7])
>>> np.diag(np.diag(x))
    array([[0, 0, 0],
           [0, 4, 0],
           [0, 0, 8]])

 

이에 반해서 empty() 라는 함수는 크기만 지정해 두고 각각의 요소는 초기화 시키지 않는다. 따라서 이 함수로 생성된 배열의 요소는 가비지값이 채워져 있다.


>>> c = np.empty( (2,2) ) # 가비지 값으로 채원진 2x2 크기의 배열 생성



Posted by 살레시오
,

 자바도 클래스의 멤버 각각에 외부에서 접근할 수 있는 범위를 지정하는 접근 지정자(access modifier)를 둘 수 있다. 다음과 같은 네 가지가 있다.



접근 지정자

접근 범위

동일
클래스

동일
패키지

다른
패키지의
자식
클래스

다른
패키지

public

접근 제한 업음

O

O

O

O

protected

동일 패키지와 상속 받은 클래스 내부

O

O

O


default

동일 패지키 내에서만

O

O



private

동일 클래스 내에서만

O





public

 공개 정도가 가장 높고 어디에서든 자유롭게 접근할 수 있다.

protected

 같은 패키지 내에서 접근이 가능하고 다른 패키지에서도 상속을 받은 클래스 내부에서는 사용 가능하다. public과 다른 점은 다른 패키지의 자식 클래스 외부에서는 접근할 수 없다는 것이다.

default (package private)

 같은 패키지 내에서만 접근이 가능하다. 아무런 접근 지정자도 없을 경우 이 옵션이 자동으로 적용된다.

private

 동일 클래스 내에서만 접근이 가능한 가장 낮은 단계의 자유도를 갖는다.


다음과 같이 tut02 패키지의 CA클래스와 이를 상속받은 CB클래스가 있다고 하자.


package tut02;
public class CA {
   public int ia;
   protected int ib;
   int ic;
   private int id;
   
   public static int ie;
   protected static  int ig;
   static int ih;
   private static int ii;
}


같은 패키지(즉 tut02 패키지) 내에서는 클래스 외부에서 변수 ia, ib, ic를 자유롭게 접근할 수 있고 id는 외부에서는 접근이 안된다. 이 클래스가 같은 패키지 내에서는 public, protected, default 가 같은 효과를 갖는다. 이것을 상속받은 자식 클래스에서도 ia,ib,ic는 접근 가능하다.


 만약 외부에서 tut02패키지의 CA 클래스를 불러서 사용하는 경우를 보자.


package tut03;
import tut02.CA;

public class Tut03 {
   public static void main(String[] args) {
       CA a = new CA();// ia만 접근 가능
       CC c = new CC();// ia만
   }   
}

class CC extends CA {
   //ia, ib, ie, ig 접근 가능
}


객체 a와 c는 외부에서 ia 멤버만 접근할 수 있다. 즉 클래스 외부에서 접근할 수 있는 멤버는 public으로 지정된 것만이다. protected로 선언된 멤버들은 CA를 상속하는 CC 내부에서만 사용 가능하다. 즉, protected로 선언된 멤버는 다른 패키지에서 이것을 상속받은 자식 클래스의 private 멤버가 되는 것이다. 클래스 CC내부에서도 CA의 ic, id는 접근할 수 없는데 default, private 멤버는 다른 패키지에서는 접근이 안 되기 때문이다.




Posted by 살레시오
,

 추상 클래스(abstract class)란 하나 이상의 추상 메소드(abstract method)를 포함하는 클래스이다. 추상 메소드는 선언만 있고 본체는 없는 함수이며 선언부에 ‘abstract’ 라는 키워드를 붙인다. 추상 메소드가 포함되었다면 클래스도 추상 클래스이므로 클래스명 앞에도 ‘abstract’키워드를 붙여야 한다.


abstract class Animal {
   public String sName; //일반 멤버 변수
   ….
   public void move() { …} // 일반 메소드
   abstract void howl(); //추상 메소드
   …
}


추상 클래스는 추상 메서드를 포함하고 객체화 할 수 없다는 점만 제외하고 일반 클래스와 다르지 않으며 생성자, 멤버변수와 일반 메서드도 가질 수 있다. 추상 클래스 자체로는 클래스로의 역할을 하지 못하며 객체를 생성할 수 없지만 새로운 클래스를 작성하는데 있어서 부모 클래스로서 중요한 역할을 갖는다. 위의 예에서 Animal 클래스는 직접 객체를 생성하지 못하고 이를 상속받는 자식 클래스에서는 추상 메소드의 구체적인 본체를 가질 수 있다.


package tut02;

abstract class Animal {
   public String sName;
   public void move() {
       System.out.println("어슬렁 어슬렁");
   }
   abstract void howl();
}

class Dog extends Animal {
   public void move() {
       System.out.println("팔짝 팔짝");
   }

   void howl() {
           System.out.println("멍멍");
   }
}

class Cat extends Animal {
   void howl() {
           System.out.println("냐옹");
   }
}

public class Tut02 {

   public static void main(String[] args) {
       Dog happy = new Dog();
       Cat julia = new Cat();
       happy.move(); // 오버라이드된 멤버함수 호출
       happy.howl(); // 구현된 멤버함수 호출
       jular.move(); // 일반 멤버함수 호출
       julia.howl(); // 구현된 멤버함수 호출
   }
}
실행 결과
팔짝 팔짝
멍멍

어슬렁 어슬렁

냐옹


추상 메소드의 접근 지정자로 private는 사용할 수 없는데 이는 자식 클래스에서 받아서 구현되어야 하므로 당연하다. 다른 접근 지정자(public, protected)는 사용할 수 있고 생략되면 default (즉, 같은 패키지 안에서만 접근 가능)인 것은 일반 클래스와 동일하다.


 위의 예에서 처럼 추상 클래스는 다른 클래스들에게서 공통으로 가져야하는 메소드들의 원형을 정의하고 그것을 상속받아서 구현토록 하는데 사용된다. 메소드 오버라이드(override)와 유사해서 혼동하기 쉬우나 오버라이드는 안해도 상관없지만 추상 메소드는 자식 클래스에게 그 구현을 강요하는 기능을 한다. 위 예에서도 Dog 클래스는 move()메소드를 오버라이드 했지만 Cat클래스는 그러지 않았다. 하지만 howl()메소드는 반드시 구현해야 한다. 그리고 만약 어떤 추상클래스를 상속 받은 자식 클래스에서 추상 메소드를 구현하지 않았다면 자식 클래스도 추상 클래스가 되어야 한다는 점도 알아 두자.



Posted by 살레시오
,

 오픈소스 프로그래밍 언어 중에 줄리아(Julia)라는 과학 계산용 언어가 있는데 아직 초기 버전이고 인터프리터 언어임에도 불구하고 C 컴파일된 것과 필적하는 성능을 보여주고 있어서 요즘 주목을 받고 있다. (요새는 JIT컴파일링은 아예 기본이 된 느낌이다.) 튜토리얼 동영상을 잠깐 봤는데 첫 인상은 파이썬과 matlab을 합쳐놓은 듯한 문법을 가지고 있다. (과학 계산용 언어에서 matlab의 영향은 무시할 수 없나 보다.) 아래 그림은 줄리아 홈메이지에서 캡쳐한 것이다.



위 표에 기록된 숫자들은 C프로그램의 성능을 1로 보았을 때 해당 언언의 성능 수치들이다 (낮은 수록 더 높은 성능임) 다음과 같은 몇 가지를 확인해 볼 수 있다.


  • octave의 성능은 matlab에 훨씬 못 미친다. octave는 그냥 matlab문법 연습용으로나 사용하고 실제 프로젝트에서 사용은 신중히 고려해보야야 할 것 같다.

  • 그리고 자바가 성능이 의외로 높다는 점이다. 여기에서는 JDK7으로 테스트했는데 JDK8 이상으로 하면 더 올라갈 것 같다.


파이썬과 matlab을 알고 있다면 줄리아를 익히는데 시간이 많이 걸릴 것 같지 않다. 그런데 이 그림을 보고 새삼 느끼는 점은 ‘자바를 더 공부해야겠다’ 였다. 줄리아도 판올림을 하고 정식 버전이 가까이 되면 훨씬 더 발전할 것 같긴 하다..




'프로그래밍언어.Lib' 카테고리의 다른 글

스크래치로 AI를 구현할 수 있다고?  (0) 2020.06.10
Posted by 살레시오
,