객체(Object)

일반적으로 사물은 속성과 기능을 갖는다. 속성은 정적인 정보를, 기능은 동적으로 수행할 수 있는 역할, 움직임을 가르킨다.

연관성이 있는 사물은 분류할 수 있다. 공통적으로 가지고 있는 특성을 묶고 그 관계를 코드로 구현하는 것이 자바 객체지향이라고 본다. 사물이 가진 어떤 속성이나 기능이 프로그래밍에서 속성은 맴버 변수, 기능은 메서드(함수)로 대응할 수 있다.

사물을 생산하기 위해 설계하는 것이 클래스, 생산이 된 결과를 인스턴스로 볼 수 있다.(사전이나 서적에 따라 인스턴스 자체를 객체로 보기도 한다.)

 

 

클래스

은행의 계좌에서 일어나는 여러가지 속성과 기능을 나누어 구현해보자.

public class BankAccount {
	//맴버 변수
	int bankCode;
    int accountNo;
    String owner;
    int balance;
    boolean isDormant;
    int passward;
    
    //메서드
    void inquiry() {}
    void deposit() {}
    void withdraw() {}
    void heldInDormant() {}
}

맴버 변수와 메서드를 작성한다.

클래스를 작성할 때, 현실세계의 사물을 어떤 식으로 일반화 시킬지, 공통적인 속성이 무엇인지 파악하는 것이 중요하다.

실제 프로그램을 구현할 때에도 전체적인 업무를 하나하나 개별적으로 구현하는 것이 아니라 공통적인 속성과 기능을 분리한 후, 클래스로 나타내는 것이 좋다.

 

 

생성자

생성자는 클래스 내부에 정의되어야 하며, 생성자 메서드명은 클래스명과 일치해야한다.

BankAccount(
		int bankCode,
        int accountNo,
        String owner,
        int balance,
        int passward,
        boolean isDormant
) {
	this.bankCode = bankCode;
    this.accountNo = accountNo;
    this.owner = owner;
    this.balance = balance;
    this.passward = passward;
    this.isDormant = isDormant;
}

전체적인 코드를 구성하는 클래스명이 BankAccount이기 때문에 생성자 또한 BankAccount로 한다. 생성자는 new 연산자와 함께 사용해야한다. 클래스 내부에 생성자가 없는 경우, 자바에서 생성자 내부에 값이 없는 빈생성자를 자동으로 추가한다. 사용자가 어떤 파라미터를 받는 생성자 함수를 만들어주면 더이상 생성자를 자동으로 만들어주지 않는다.

생성에 필요한 정보들은 생성자 함수 옆 괄호 안에 넣어주어야한다.

중괄호는 데이터를 할당해서 실제적으로 의미있는 값을 가지는 인스턴스를 만드는 과정이다. this는 인스턴스 자기자신을 가르키는 특수한 변수이다. this 뒤에는 클래스에 정의된 맴버 변수가 온다. 맴버 변수를 통해 인스턴스 자기자신에 입력받은 값, 인자로써 입력받은 값을 전달받게 된다. 즉, 왼쪽의 bankCode는 클래스에 정의된 맴버 변수의 의미를 가지며, 오른쪽의 bankCode는 사용자로부터 혹은 프로그램으로부터 입력받은 값을 의미한다.

 

생성자를 사용해서 만드는 것은 다른 곳에서 진행하는 것이 일반적이다. 지금까지 만든 것이 설계도라면 실제로 사용하는 것들은 로직이 구현된 파일에서 진행된다.

public static void main(String[] args) {

    BankAccount bankAccount = new BankAccount();
    System.out.println(account);
    System.out.println(account.bankCode); // 0
    System.out.println(account.isDormant);  // false
}

main 함수에서 실행할 수 있는 상태로 만들어준 뒤, BankAccount라고 입력하면 우리가 기존에 만들었던 클래스를 불러오게 된다.

위에서 만들었던 생성자 중, 기본 빈생성자를 불러오면 인스턴스의 맴버 변수를 출력했을 때 데이터가 아무것도 할당되어 있지 않기 때문에 객체는 존재하지만 기본값이 출력된다.

 

 

상속

객체지향에서는 상속이라는 개념이 존재한다.

상속을 받는 클래스를 자식 클래스라고 하고 상속의 대상이 되는 클래스를 부모 클래스라고 한다.

객체지향은 재사용과 범주화가 핵심이다. 공통 속성에 수정사항이 생기면 코드 하나하나를 수정하는 것은 비효율적이다.

public class SavingsAccount extends BankAccount {
	boolean isOverdraft;
    void transfer() {};
}

부모 클래스 BankAccount를 재활용하기 위해 자식 클래스인 extends 키워드를 사용한다. 이렇게하면 SavingsAccount 클래스는 부모 클래스인 BankAccount가 가진 모든 것들을 가지고 시작한다. 그리고 맴버 변수를 정의하여 추가하면 된다.

public class DollarAccount extends BankAccount {

    void transfer() {}
}
public class SubscriptionAccount extends BankAccount {

    int numOfSubscription;
}

위처럼 부모 클래스를 상속받아 재활용할 수 있다.

상속을 할 때에는 하나의 클래스만 상속받을 수 있다. 이것을 단일상속이라고 한다. 자바 언어는 단일상속 언어이며, 다른 언어에서는 다중상속을 하는 경우도 있다. 다중상속에는 장단점이 있는데 어떤 부모클래스에서 온 속성인지 파악하기 어렵기 때문에 모호성을 제거하기 위해 자바에서는 단일상속을 지원한다.

 

오버로딩과 오버라이딩

오버로딩과 오버라이딩은 부모 자식관계의 클래스들을 효과적으로 정의하고 활용하기 위해 나온 개념이다.

오버로딩은 부모 클래스에서 상속받은 메서드에서 파라미터를 변경하는 것이다. 이것을 통해 새로운 메서드를 정의한다.

inquiry는 부모 클래스에서는 계좌를 조회하는 메서드이다. 다른 파라미터를 넘겨받고 싶거나 다른 형태의 인자를 넘겨받고 싶다면 인자를 추가할 수 있다.

오버라이딩은 덮어쓰기라는 뜻이다. 부모 클래스에서 상속받은 메서드의 내용을 자식 클래스의 상황에 맞게 변경한다.

오버로딩은 파라미터가 바뀌는 것이고 오버라이딩은 중괄호, 메서드의 코드블락이 변경되는 것이다.

public class DollarAccount extends BankAccount {

    void inquiry(double currencyRate) {}

    void deposit() {

    }
}

위 코드는 double로 달러 환율을 추가해서 함수를 재정의 했다. 잔액을 조회했을 때, 환율을 계산해서 미화로 결과를 확인할 수 있는 오버로딩된 메서드이다.

deposit의 경우, 원화와 달러 입금방식이 다르기 때문에 부모 클래스 BankAccount에 정의된 내용을 쓰지 않고 DollarAccount만의 고유한 입금방식을 취하기 위해 재정의 한다. 오버라이딩이 된 메서드는 부모 클래스의 파라미터 설정을 그대로 따른다.

즉, 파라미터 설정은 오버로딩을 통해 만들고 오버라이딩 된 것은 파라미터는 그대로고 중괄호 안의 내용을 바꿔주는 것이다.

 

 

접근제어자

클래스, 멤버 변수, 메서드, 생성자 등의 접근을 제어한다. 그 중 가장 많이 쓰이는 멤버 변수의 접근제어자에 대해 알아보자.

접근제어자는 일반적으로 타입 앞에 나타내게 되는데 타입 앞에 접근제어자가 없이 선언이 된 경우, 아무나 이 클래스에서 생성된 인스턴스의 코드를 임의로 변경할 수 있다. 즉, 객체 멤버 변수를 무분별하게 접근하고 수정할 수 있다. 보안과 안정성에 큰 문제를 야기할 수 있다.

public static void main(String[] args) {

    BankAccount bankAccount = new BankAccount();
    bankAccount.password = 123456;
    System.out.println(bankAccount.password());

}

bankAccount의 password를 임의로 지정한 뒤, 출력하면 그대로 덮어씌워져서 출력된다. 비밀번호를 임의로 바꾸는 것도 문제지만 비밀번호를 바꾸는 일정한 규칙이 있다면 그 규칙에 맞지 않는 데이터가 들어갈 수 있다. 그렇기 때문에 하나의 클래스에 정의된 멤버 변수, 그리고 인스턴스에 저장된 속성을 각각 역할에 맞는 함수를 만들어서 변경시켜야한다. 이렇게 마음대로 활용할 수 없도록 하는 것이 접근제어자이다.

 

public class BankAccount {

    // 멤버변수
    private int bankCode;
    private int accountNo;
    private String owner;
    private int balance;
    private boolean isDormant;
    private int password;
    
    // 메서드
    public void inquiry() {}
    public void deposit() {}
    public void withdraw() {}
    public void heldInDormant() {}
    public void changePassword(int password) {
        this.password = password;
    }
 }

 

접근제어자 private은 동일한 클래스에서만 수정과 참조가 가능하다. this를 통해 비밀번호를 대입해준다. 메서드는 접근제어자 public을 통해 외부에서 활용 가능한 형태로 만들어준다.

private은 값을 수정하는 것 뿐만 아니라 조회도 불가능하게 만든다. 그렇기 때문에 멤버 변수의 값을 조회하고 수정하기 위해 GetterSetter를 활용한다.

우클릭을 하여 Generate를 누르면 Getter와 Setter를 지정할 수 있다.

이렇게 하면 기존의 함수에 get과 set이 붙은 형태로 만들어진다.

public int getBankCode() {
        return bankCode;
}

public void setBankCode(int bankCode) {
    this.bankCode = bankCode;
}

public int getAccountNo() {
    return accountNo;
}

public void setAccountNo(int accountNo) {
    this.accountNo = accountNo;
}

public String getOwner() {
    return owner;
}

public void setOwner(String owner) {
    this.owner = owner;
}

public int getBalance() {
    return balance;
}

public void setBalance(int balance) {
    this.balance = balance;
}

public boolean isDormant() {
    return isDormant;
}

public void setDormant(boolean dormant) {
    isDormant = dormant;
}

public int getPassword() {
    return password;
}

public void setPassword(int password) {
	this.password = password;
}

getter와 setter가 만들어졌기 때문에 passward를 .으로 직접 조회하는 것이 아니라

public static void main(String[] args) {

    BankAccount bankAccount = new BankAccount();
    bankAccount.changePassword(123456);
    System.out.println(bankAccount.getPassword());

}

getPassward를 통해 바뀐 비밀번호를 조회한다.

 

 

인터페이스

클래스와 인터페이스는 다르다. 클래스가 상세한 설계도라면 인터페이스는 스케치 수준의 설계도이다. 파라미터, 반환, 타입만 가질 수 있으며 실제 코드를 구현할 수 있는 중괄호로 어떤 작업이 실행되는지는 정의할 수 없다.

인터페이스는 기능의 표준화를 달성하기 위한 도구이다. 공통적인 기능을 일정한 단위와 범주로 묶어 처리하고 그것을 구현할 클래스에서 각 업무 로직에 맞게 구현할 수 있도록 한 것이다. 그렇기 때문에 클래스에 신규 기능이 생기거나 삭제되는 기능이 생긴다면 인터페이스를 통해 효율적인 작업을 할 수 있다.

우클릭을 하면 New - Java Class에서 인터페이스를 생성할 수 있다.

public interface Withdrawable {
    void withdraw();
}

 

public class SavingsAccount extends BankAccount implements Withdrawable {

    boolean isOverdraft;

    void transfer() {};
    public void withdraw() {
    	System.out.println("Withdraw");
    };
}

추가한 인터페이스를 가져다 활용하려면 클래스 옆에 implements라는 키워드와 인터페이스명을 입력한다. 인터페이스를 명시하면 구현한 인터페이스의 함수를 반드시 클래스에서 구현해야한다. 인터페이스에서 함수를 가져와 재정의 할 때에는 접근제어자 public을 붙여주어야한다.

 

 

'Back-End > Java' 카테고리의 다른 글

Web - 클라이언트와 서버  (0) 2023.05.22
예외 - 예외 처리  (0) 2023.05.19
회원가입 프로그램 실습 - 자바(Java) 편  (1) 2023.05.16
함수  (0) 2023.05.15
자료구조 - 배열, 리스트, 맵  (0) 2023.05.12

지금까지 공부한 내용을 바탕으로 회원가입 프로그램을 만들어보자.

import java.util.Scanner;

public class UserRegister {

    public static void main(String[] args) {

        System.out.println("======================");
        System.out.println("회원등록");
        System.out.println("======================");

        boolean register = false;
        Scanner sc = new Scanner(System.in);

        while (!register) {

            System.out.println("회원가입을 하시겠습니까?\ny: 진행    n:취소");
            System.out.print(">> ");
            String register_input = sc.nextLine();

            if (register_input.equalsIgnoreCase("y")) {
                register = true;
                System.out.println("======================");
                System.out.println("회원가입이 진행됩니다.");
                System.out.println("======================");
            } else if (register_input.equalsIgnoreCase("n")) {
                System.out.println("======================");
                System.out.println("회원가입이 종료됩니다.");
                System.out.println("======================");
                System.exit(0);
            } else {
                System.out.println("입력 값을 확인해주세요.");
            }
        }

다른 것과 혼동할 수 있기 때문에 구분할 수 있도록 꾸민다. 사용자에게 입력 받기 위해 Scanner를 자바 라이브러리에서 불러온다.(ctrl + space를 눌러 java.util 스캐너 객체를 불러온다.) in 인자를 통해 외부의 입력을 받도록 한다.

사용자로 하여금 올바르지 않은 값을 입력했거나 값을 다시 입력해야할 때, 프롬프트(입력창)를 띄우는 반복작업을 위해 반목문을 작성한다. println은 무조건 문자를 출력하고 개행한다. 개행하지 않고 사용자가 입력하는 커서가 되기 위해 print 함수를 쓴다. nextLine 함수는 문자열을 입력 받았을 때, 사용자의 입력을 대기하고 값을 입력한 뒤 엔터를 치면 변수에 값이 할당되며 다음 로직으로 이어진다.

if 문을 통해 문자를 입력 받았을 때, while 문의 불리언 값을 true로 만들어 반복문을 빠져나오도록 한다. y를 입력 받았을 때는 다음 로직이 실행되고, n을 입력 받았을 때는 프로그램이 종료되도록 한다. 만약 y와 n이 아닌 다른 문자를 입력 받았을 경우, 다시 처음으로 돌아가도록 한다.

 

ArrayList users = new ArrayList();

while (true) {

    HashMap user = new HashMap();

    // ID
    System.out.print("ID: ");
    String username = sc.nextLine();

	// PW
	String password = "";
	while (true) {
		System.out.print("PW: ");
		password = sc.nextLine();
		System.out.print("PW 확인: ");
		String password_confirm = sc.nextLine();

        if (password.equals(password_confirm)) {
            break;
		} else {
            System.out.println("======================");
            System.out.println("패스워드가 일치하지 않습니다.");
            System.out.println("패스워드를 다시 입력해주세요.");
	        System.out.println("======================");
        }
    }

	// 이름
	System.out.print("성명: ");
	String name = sc.nextLine();

	// 생년월일(6자리)
	String birth_date = "";
	while (true) {
		System.out.print("생년월일(6자리): ");
		birth_date = sc.nextLine();
		if (birth_date.length() == 6) {
			break;
		} else {
			System.out.println("======================");
			System.out.println("생년월일 자릿수가 올바르지 않습니다.");
	        System.out.println("생년월일을 다시 입력해주세요.");
         	System.out.println("======================");                    
		}
	}

	// 이메일
	System.out.print("이메일: ");
	String email = sc.nextLine();

가입된 회원정보를 저장하기 위해 ArrayList를 만들어준다. 회원가입을 진행할 것인지 묻기 위해 while 문을 작성해준다. while 문이 무조건 실행되도록 true를 입력한다. 각각의 유저 한 명씩을 담아 항목별로 관리할 수 있도록 HashMap으로 변수를 선언한다.

입력받는 값이 아이디라는 것을 알려주고 값을 입력 받은 뒤 엔터를 치면 다음으로 넘어가도록 한다.

변수를 선언한 뒤, while 문으로 입력받은 비밀번호와 확인칸의 비밀번호 값을 비교한다. if 문을 통해 값이 같다면 while 문을 break를 통해 빠져나오고, 값이 다르면 다시 입력받도록 돌아간다.

이름과 생년월일, 이메일을 입력받는다. 생년월일은 6자리로 제한한다. 6자리가 아닌 경우, 처음부터 다시 입력받도록 while 문을 쓴다. 변수는 밖에서 참조해야하는 데이터이기 때문에 외부에서 변수를 선언한다. length 함수로 6자리인지 확인한다.

 

user.put("username", username);
user.put("password", password);
user.put("name", name);
user.put("birth_date", birth_date);
user.put("email", email);

users.add(user);

System.out.println("------------------------");
System.out.println(user.get("name") + " 님, 가입을 환영합니다.");
System.out.println("ID는 " + user.get("username") + " 입니다.");
System.out.println("------------------------");

System.out.println("회원가입을 이어서 진행하시겠습니까?\ny: 진행    N:취소");
System.out.print(">> ");
String register_again = sc.nextLine();

if (register_again.equalsIgnoreCase("y")) {
	;
} else if (register_again.equalsIgnoreCase("n")) {
    System.exit(0);
}

put을 통해 HashMap에 각각 키-값 쌍으로 데이터를 구성하여 추가한다.

모든 회원이 저장되는 ArrayList에 우리가 지금까지 만든 user라는 HashMap 객체를 추가하여 전체 회원장부에 가입한 회원정보를 등록한다.

 

 

'Back-End > Java' 카테고리의 다른 글

예외 - 예외 처리  (0) 2023.05.19
객체지향 - 객체지향 프로그래밍  (0) 2023.05.18
함수  (0) 2023.05.15
자료구조 - 배열, 리스트, 맵  (0) 2023.05.12
제어문 - 조건문과 반복문  (0) 2023.05.11
함수(Methods)

프로그래밍에서는 한줄의 코드가 아니라 여러 줄의 코드를 조합해서 작업을 수행한다. 그런데 반복적으로 어떤 작업을 처리해야 할 때, 동일한 코드를 여러 번 작성하는 것은 비효율적이다. 그렇기 때문에 어떠한 하나의 작업단위를 이루는 여러가지 코드를 한 묶음으로 만들어서 재사용 할 수 있도록 만든 것이 바로 함수, 또는 메서드라고 한다.

일반적으로 메서드(Method)는 클래스(class)의 기능적인 부분을 나타내는 함수(function)를 나타내는데, 자바에서는 모든게 클래스로 관리되기 때문에 메서드라는 이름으로 통용하고 있다.

 

1. 입력과 출력이 모두 있는 경우

출력은 콘솔의 문자 출력이 아닌 데이터 반환을 뜻한다.

static int mod (int a, int b) {
    int result = a % b;
    return result;
}

반환할 데이터 타입을 정한 후, 메서드의 이름을 정의한다. 괄호 안에는 매개변수, 즉 파라미터(parameter)로 정의한다. 그리고 매개 변수로 받은 값을 함수에서 어떤 식으로 사용할지에 대해 코드로 표현한다. 다시 데이터를 반환해서 사용할 수 있도록 하기 위해 return함수를 사용한다.

 

2. 입력은 있는데 출력은 없는 경우

static void printNum (int a) {
    System.out.println(a);
}

출력이 없다는 것은 아무런 데이터형으로도 만들 필요가 없다는 뜻이기 때문에 void라는 키워드를 작성한다. 서로 다른 메소드에서 쓰이는 변수들은 함수 내에서만 공유되므로 이름이 같아도 서로 공유되지 않는다. 위의 코드는 콘솔에서 출력될 뿐, a로 입력받은 데이터를 이후에 활용할 수 있도록 메모리에 저장해주지 않는다. 즉, 콘솔로 출력 후, a라는 데이터는 시스템에서 휘발된다.

 

3. 입력은 없는데 출력이 있는 경우

static String greeting() {
    return "Hello!";
}

입력값이 없기 때문에 파라미터 자리에는 아무 것도 입력하지 않는다. 그리고 위에서 지정한 데이터 타입인 문자열(String)을 리턴할 수 있도록 String 값을 넣어준다.

 

4. 입력과 출력이 모두 없는 경우

static void greeting_2() {
    System.out.println("Hello!");
}

위 코드는 콘솔로 출력만 하고 데이터 자체는 휘발된다.

 

static 안에서 실행되기 위해서는 함수에도 static이 붙어있어야한다.

 

이제 위의 모든 경우의 함수를 main에서 실행해보자.

public static void main(String[] args) {
	int mod_result = mod(3, 2); // 1번의 경우
	System.out.println(mod_result); // 1

	printNum(10); // 2번의 경우 // 10

	String str = greeting(); // 3번의 경우
	System.out.println(str); // Hello!

	greeting_2(); // 4번의 경우 // Hello!
}

 

 

'Back-End > Java' 카테고리의 다른 글

객체지향 - 객체지향 프로그래밍  (0) 2023.05.18
회원가입 프로그램 실습 - 자바(Java) 편  (1) 2023.05.16
자료구조 - 배열, 리스트, 맵  (0) 2023.05.12
제어문 - 조건문과 반복문  (0) 2023.05.11
연산자  (0) 2023.05.10
배열(Arrays)

어떤 특정한 자료형에 대해 그 자료형을 모아놓은 자료구조

 int[] price = {10000, 9000, 40000, 7000};
String[] mbti = {"INFP", "ENFP", "ISTJ", "ESTP"};

System.out.println(price[0]); // 10000
System.out.println(mbti[0]); // INFP

대괄호 [ ] 앞의 int나 String은 뒤에 올 변수에 들어가는 자료형을 지정해준다. 변수를 선언할 때 작성했던 타입의 자료열로만 구성된 배열을 선언한다. 변수에 들어있는 값을 꺼내고 싶다면 호출하고 싶은 값의 인덱스를 대괄호에 넣어준다.

배열 인덱스의 값을 임의의 값을 수정하는 방법은 간단하다.

price[1] = 8000
System.out.println(price[1]); // 8000

값을 가져온 뒤, 대입 연산자를 통해 값을 새롭게 대입하면 기존의 값에 덮어씌워진다.

배열을 확인하고 싶다고 아래처럼 직접 배열의 변수를 함수에 전달하면 아마 이상한 값이 나올 것이다.

System.out.println(price);

변수 역시 객체이기 때문에 값 자체를 드러내지 않고 주소값이 나온다.

 

for 반복문을 통한 배열의 조작

 int[] price = {10000, 9000, 40000, 7000};
String[] mbti = {"INFP", "ENFP", "ISTJ", "ESTP"};

for (int i = 0; i < mbti.length; i++) {
    System.out.println(mbti[i]);
}

for 문에 초기화식, 조건식, 증감식을 써준다. length 함수는 배열의 크기를 구해준다. 결과를 출력하려면 배열의 이름과 변수를 써주면 된다.

 

 

리스트(Lists)

순서를 구분하고 중복을 허용하는 자료구조

리스트의 종류에는 Vector, ArrayList, LinkedList가 있다. 그 중 가장 대중적으로 많이 쓰이는 ArrayList에 대해 알아보자.

ArrayList는 배열보다 폭넓은 메서드, 각종 확장된 기능을 제공한다.

ArrayList list = new ArrayList(10);
list.add(100);
	list.add("INFP");

for (int i = 0; i < list.size(); i++) {
	System.out.println(list.get(i));
}

ArrayList라는 객체 자료형을 선언한 뒤, 변수와 new 연산자를 사용하여 인자로 길이를 정해준다. add 메서드는 타입을 지정하지 않아도 리스트에 추가할 수 있다.  데이터 타입을 제한하고 싶다면 ArrayList 뒤에 꺽쇠< >에 제한하고 싶은 자료형의 객체타입(Integer, String 등)을 쓰면 된다. 자료형을 제한할 때는 기본형 데이터(int 등)를 쓸 수 없다.

 

 

맵(Map)

키-값 쌍을 요소로 가지는 데이터의 모음

맵은 순서를 구분하지 않는다. 키는 중복이 불가능하고, 값은 중복이 가능하다.

맵에도 여러가지 종류가 있지만 가장 많이 쓰이는 HashMap에 대해 알아보자.

HashMap<String, String> map = new HashMap();
map.put("age", "30");
map.put("mbti", "INFP");

System.out.println(map.get("age"));

HashMap은 선언한 뒤, 인자를 넣지 않아도 된다. put 메서드로 키-값을 넣는다.

결과를 출력할 때는 리스트와 똑같이 get 메서드를 사용하는데 인덱스 값이 아닌 키를 넣어야 그에 대응되는 값을 출력한다. 데이터 타입을 제한하고 싶다면 리스트와 마찬가지로 꺽쇠를 이용하여 객체타입을 지정해주면 된다.

 

 

'Back-End > Java' 카테고리의 다른 글

회원가입 프로그램 실습 - 자바(Java) 편  (1) 2023.05.16
함수  (0) 2023.05.15
제어문 - 조건문과 반복문  (0) 2023.05.11
연산자  (0) 2023.05.10
콘솔 입출력  (0) 2023.05.09

+ Recent posts