자바란?
- 프로그래밍 언어
- 컴퓨터 프로그램(애플리케이션)을 만드는데 사용
- 실행환경(JRE) + 개발도구(JDK) + 라이브러리(API)
어디에 쓰일까?
- PC 애플리케이션 <- 인텔리제이, 이클립스
- 웹 애플리케이션 <- 웹사이트, 스프링
- 모바일 애플리케이션(안드로이드)
- 빅데이터
- 게임, 과학, 소형기기 등
왜 자바일까?
- 다양한 분야에서 활발히 사용
- 20년 동안 프로그래밍 언어 1,2 위(현재는 파이썬, 자바 스크립트)
- 자바를 배우면 컴퓨터에 대한 일반적인 지식
- 모던 프로그래밍 언어(객체지향 + 자바8. 함수형)
- 넓은 생태계
- JAVA SE -> 일반적인
- JAVA ME -> 소형
- JAVA EE -> 대기업
자바의 특징
- 배우기 쉬운 객체지향 언어 = 프로그래밍 언어 + 객체지향개념(C++, JAVA, PYTHON, JS)
- 자동 메모리 관리(GC)
- 멀티 쓰레드 지원(채팅 + 문서 보내기)
- 풍부한 라이브러리로 쉽게 개발가능
- 운영체제에 독립적(WINDOWS, LINUX)
자바 가상 머신(JVM)
- 자바 프로그램이 실행되는 가상 컴퓨터(VM)
- 한번 작성하면 어디서든 실행
객체지향 언어
- 80년대 초 소프트웨어의 위기 - 빠른 변화를 쫒아가기 힘듬
- 해결책으로 객체지향 언어를 도입(절차적 -> 객체지향)
- 코드의 재사용성이 높고, 유지보수 용이(빠른 변화에 쫒아갈 수 있음), 중복 코드 제거
- 객체지향 언어 = 프로그래밍 언어 + 객체지향개념(개념, 규칙) <-규칙은 외우자
OOP의 핵심개념
- 캡술화
- 상속
- 추상화
- 다형성 <- 제일 중요!!
클래스와 객체
- 클래스 정의: 클래스란 객체를 정의해 놓은 것
- 클래스의 용도: 클래스는 객체를 생성하는데 사용
- 객체의 정의: 실제로 존재하는 것, 사물 또는 개념
- 객체의 용도: 객체가 가지고 있는 기능과 속성에 따라 다름
객체의 구성요소 - 속성과 기능
객체 = 속성(변수) + 기능(메서드)
하드웨어 -> 소프트웨어화
TV
- 속성: 크기, 길이, 높이, 색상, 볼륨, 채널 등
- 기능: 켜기, 끄기, 볼륨 높이기, 볼륨 낮추기, 채널 변경하기 등
객체: 모든 인스턴스를 대표하는 일반적 용어
인스턴스: 특정 클래스로부터 생성된 객체(TV 인스턴스)
(설계도) (인스턴스화) (제품) - 사용
클래스 ---------------------> 인스턴스(객체)
Q. 클래스(설계도)가 왜 필요할까?
A. 객체(제품)를 생성하기 위해서
Q. 객체가 왜 필요한가?
A. (제품)우리가 사용하기 위해서
Q. 객체를 사용한다는 것은?
A. 객체가 가진 속성(변수)과 기능(메서드)을 사용하려고!
클래스
- 설계도
- 데이터 + 함수 - 관련 있는 서로 다른 타입을 묶어둘 수 있다.
- 사용자 정의 타입 - 원하는 타입을 직접 만들 수 있다.
- 변수: 하나의 데이터를 저장할 수 있는 공간
- 배열: 같은 종류의 여러 데이터를 하나로 저장할 수 있는 공간
- 구조체: 서로 연관된 여러 데이터(종류 관계X) 를 하나로 저장할 수 있는 공간
- 클래스: 데이터와 함수의 결합(구조체 + 함수)
선언 위치에 따른 변수의 종류
- 영역:
- 클래스 영역
- 메서드 영역
{
1.int iv; // 인스턴스 변수 ] (선언문만 가능)
2.static int cv; // 클래스 변수(static 변수, 공유 변수) ] 클래스 영역
void method() {
3. int lv = 0; // 지역 변수 ] 메서드 영역 (메서드 선언문)
}
}
변수의 종류 |
선언 위치 |
생성시기 |
클래스 변수 |
클래스 영역 |
클래스가
|
인스턴스 변수 |
클래스 영역 |
인스턴스(객체)가
|
지역 변수 |
클래스 영역 이외의 영역 |
변수 선언문이
|
차이점
- CV(static)는 자동 아무때나 사용가능(객체 생성X ram (로딩) -> cpu)
- IV는 객체를 만들어야 사용가능(객체 생성O)
- LV는 메서드 호출되서 메서드가 끝날 때까지 후에는 자동제거
정리
- 객체는 iv 변수의 묶음
- iv는 참조변수가 없어지면 GC에 의하여 사라짐
클래스 변수와 인스턴스 변수의 차이점
속성 - 예시: 포커 카드
- 무늬, 숫자(개별 속성) - 인스턴스 변수(인스턴스 속성이 개별적인 것)
- 카드폭, 높이 (공통 속성) - 클래스 변수(모든 인스턴스가 가지는 속성)
class Card {
String kind; // 무늬 >
int number; // 숫자 > 개별 iv
static int width = 100; // 폭 >
static int height = 250; // 높이 > 공통 cv
}
Card 객체 사용
Card c = new Card(); // 객체 생성
c.kind = "HEART" ]
c.number = 5; ] 객체 사용
c.width = 200; 권장 x] Card.width = 200;
c.height = 300; 권장 x] 객체 사용 -> Card.height = 300;
static <- 인스턴스 변수와 같은 공간에 있으면 메모리 낭비
왜? -> 어차피 같은 모든 객체에 같은 값이 들어있을텐데 ?
-> 그래서 클래스 변수를 건들지 말라고 final로 막는 것 같음
어떻게? -> final static -> cv(클래스 변수)는 다른 공간에 한개만 만들어진다!
- + 객체는 힙영역에 저장되는 것 같다.
- + static은 클래스 영역
-> static을 바꾼다면 굳이 cv로 만들필요가 없을 것 같다. 걍 인스턴스 변수로 만들지..
모든 객체가 공유하는 것이 클래스 변수(static 변수)
return문
- 실행 중인 메서드를 종료하고 호출한 곳으로 되돌아간다.
- 반환타입이 void가 아닌 경우, 반드시 return문 필요
- 메서드가 작업을 마쳤을 때 반환 타입이 void이면 생략 가능(컴파일 자동추가)
호출 스택(call stack)
- 스택(stack): 밑이 막힌 상자. 위에 차곡차곡 쌓인다.
- 메서드가 수행에 필요한 메모리가 제공되는 공간
- 메서드가 호출되면 호출스택에 메모리 할당, 종료되면 해제
아래 있는 메서드가 위의 메서드를 호출한 것
맨 위의 메서드 하나만 실행 중, 나머지는 대기중
static 메서드와 인스턴스 메서드
인스턴스 메서드
- 인스턴스 생성후, '참조변수. 메서드이름( )' 으로 호출
- 인스턴스 멤버(iv, im)와 관련된 작업을 하는 메서드
- 메서드 내에서 인스턴스 변수(iv) 사용가능
static 메서드(클래스 메서드)
- 객체 생성없이 '클래스이름.메서드이름( )' 으로 호출
- 인스턴스 멤버(iv, im)와 관련없는 작업을 하는 메서드
- 메서드 내에서 인스턴스 변수(iv) 사용불가
그렇다면 메서드를 생성할 때 static 키워드를 사용유무를 정할까?
- 메서드 내에서 인스턴스 변수(iv) 사용여부
- 이건 전에 공부하다 놓친 것 같다.
- 리터럴 값을 넣어도 마찬가지
- ★ ★ ★ ★ ★ static 메서드는 인스턴스 변수, 메서드를 쓸 수 없다! ★ ★ ★ ★ ★
- 공통 속성이여서 static을 붙이는게 아니다.
- 인스턴스 변수를 안 쓸때 (im은 iv를 사용하는 메서드) static을 사용한다.
인스턴스 메서드도 사용하지 못한다. 멤버(iv, im)를 사용하지 못한다.
그럼 어떻게 쓸 수 있을까? =====> 이런 식으로 인스턴스 변수가 아닌 지역 변수로 사용할 수 있다.
public class isUseIv {
int iv; // 인스턴스 변수
static int cv; // 클래스 변수
void instanceMethod() { // 인스턴스 메서드
System.out.println(iv);
System.out.println(cv);
}
static void staticMethod() { // static 메서드
System.out.println(iv); // 에러!!! 인스턴스 변수를 사용할 수 없다.
System.out.println(cv); // 클래스 변수는 사용할 수 있다.
}
}
그렇다면 왜 인스턴스 변수를 사용할 수 없을까?
- 클래스(static) 변수는 객체 생성 없이 호출이 가능하다. (항상 호출 ok)
- 인스턴스 변수는 객체 생성 후 호출이 가능하기 때문이다.
- 마찬가지로 인스턴스 메서드도 호출할 수 없다. => (인스턴스로 작업하는 메서드 이기 때문에)
- 물론 객체를 생성후에 접근해서 호출할 수는 있다.
public class isUseIv {
int iv; // 인스턴스 변수
static int cv; // 클래스 변수
void instanceMethod() { // 인스턴스 메서드
System.out.println(iv);
System.out.println(cv);
}
static void staticMethod() { // static 메서드
isUseIv useIv = new isUseIv(); // 객체 생성
System.out.println(useIv.iv); // 객체 생성 후에는 호출할 수 있다.
System.out.println(cv); // 클래스 변수는 사용할 수 있다.
}
}
Q. static 메서드는 static 메서드 호출가능?
A. OK
Q. static 메서드는 인스턴스 변수 사용가능?
A. NO (인스턴스 변수는 객체 생성해야 사용가능) 객체 = 인스턴스 변수 묶음
Q. static 메서드는 인스턴스 메서드 사용가능?
A. NO (인스턴스 메서드는 인스턴스 메서드를 필요로 하기 때문에)
Q. static 메서드는 인스턴스 멤버를 쓸 수 없나요?
A. static 메서드 호출시 객체(iv 묶음)가 없을 수도 있어서 <- static 메서드는 항상 호출 가능하기 때문에
정리
인스턴스 변수를 호출하기 위해서는 객체가 생성되어야 하는데 static 메서드는 항상 호출이 가능하기 때문에
객체(인스턴스 변수 묶음)가 없을 수 도 있다. => 생성시기가 다르기 때문에
메서드 오버로딩(과적)
한 클래스 안에 같은 이름의 메서드 여러 개를 정의하는 것
예시
- 만약 오버로딩을 지원하지 않는다면.. 이름이 다 달라졌을거다.. 과연 다 외울 수 있었을까?
오버로딩이 성립하기 위한 조건 3가지
- 메서드 이름이 같아야 한다.
- 매개변수의 개수 또는 타입이 달라야 한다.
- 반환 타입은 영향없다.
생성자
- 인스턴스가 생성될 때마다 호출되는 '인스턴스 초기화 메서드'
- 인스턴스 생성시 수행할 작업(iv 초기화)에 사용
Time t = new Time(); // new: 객체생성(참조값), Time(): 기본생성자 호출
t.hour = 12;
t.minute = 34;
t.second = 56;
↓
Time t = new Time(12, 34, 56); // 생성자 호출
생성자 규칙
- 이름이 클래스 이름과 같아야 한다.
- 리턴 값이 없다. (void 안 붙임)
- 모든 클래스는 반드시 한개 이상의 생성자를 가져야 한다.
기본 생성자
- 매개변수가 없는 생성자
- 생성자가 하나도 없을 때만, 컴파일러가 자동 추가
생성자 this
- 생성자에서 다른 생성자 호출할 때 사용
- 다른 생성자 호출시 첫 줄에서만 사용가능
public class Human {
String name;
String job;
int age;
Human() {
/*name = "홍길동";
job = "취준생"; <----- 코드 중복 제거
age = 0;
*/
this("홍길동", "취준생", 0); // Human(String name, String job, int age)를 호출
}
public Human(String job) {
this("홍길동", job, 0); // Human(String name, String job, int age)를 호출
}
Human(String name, String job, int age) {
name = name;
job = job;
age = age;
}
}
참조 변수 this
- 인스턴스 자신을 가리키는 참조 변수
- 인스턴스 메서드(생성자 포함) 에서 사용가능
- 클래스 메서드 사용X
- 지역 변수와 인스턴스 변수를 구별할 때 사용
public class Human {
String name;
String job;
int age;
Human() {
this("홍길동", "취준생", 0); // Human(String name, String job, int age)를 호출
}
public Human(String job) {
this("홍길동", job, 0); // Human(String name, String job, int age)를 호출
}
Human(String name, String job, int age) {
//iv //lv this: 생략 가능하지만 사용 권장
this.name = name;
this.job = job;
this.age = age;
}
}
참조변수 this( )와 생성자 this( )
this:
- 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다.
- 모든 인스턴스 메서드에 지역변수로 숨겨진 채 존재한다.
public class Human {
String name; // this.name
String job; // this.job
int age; // this.age
}
this( ), this(매개변수):
- 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다.
- 클래스 이름 대신 this( )를 사용한다.
참고: this와 this는 비슷하게 생겼을 뿐 완전히 다른 것이다. this는 '참조변수' 이고, this( )는 '생성자' 이다.
변수의 초기화
- 지역 변수는 수동 초기화 해야함(사용전 꼭!!!)
- 맴버 변수는 자동 초기화 된다.
class initTest {
int x; // 인스턴스 변수
int y = x; // 인스턴스 변수
void method1() {
int i; // 지역변수
int j = i; // 에러! 지역변수를 초기화하지 않고 사용
}
}
멤버 변수(iv, cv)의 초기화
1. 명시적 초기화(=)
class Car {
int door = 4; // 기본형 변수의 초기화
Engine e = new Engine(); // 참조형 변수의 초기화
}
2. 초기화 블럭
- 인스턴스 초기화 블럭: { }
- 클래스 초기화 블럭: static { }
3. 생성자(인스턴스 변수 초기화)
Human(String name, String job, int age) {
this.name = name;
this.job = job;
this.age = age;
}
초기화 시점
- 클래스 변수 초기화 시점: 클래스가 처음 로딩될 때(메모리에 올라갈 때) 단 한번
- 인스턴스 변수 초기화 시점: 인스턴스가 생성될 때 마다
- 초기화 순서: 클래스 변수 초기화 => 인스턴스 변수 초기화
오늘의 복습은 마쳤고, 아래는 복습하면서 간단하게 만들어봤다.
public class Card {
public static int width = 200;
public static int height = 300;
private String kind;
private int number;
private String[] kinds = {"스페이스", "하트", "클로버", "다이아몬드"};
Card() {
// 기본 생성자
}
public void drawCard() {
this.kind = kinds[shuffleKind()];
this.number = shuffleNum();
}
public void show() {
System.out.println("당신의 카드: " + kind);
System.out.println("당신의 숫자: " + number);
}
private int shuffleKind() {
double random = Math.random();
int num = (int)Math.round(random * (kinds.length -1));
return num;
}
private int shuffleNum() {
double random = Math.random();
int num = (int)Math.round((random * 9) + 1);
return num;
}
}
- K,Q,J 문자를 제외한 카드뽑기 로직이다.
- shuffleKind, shuffleNum을 통해 랜덤으로 카드종류와 숫자를 뽑아냈다.
- 뽑은 문자열과, 숫자를 인스턴스 변수에 대입했다.
- 넓이와 높이는 이후 Main 로직에서 Card.width, Card.height를 써보기 위해 접근제어자로public 을 선택했다.
- shuffleKind에 0 ~ 3 랜덤 값을 리턴시켜 String 배열의 인덱스를 설정하고 뽑아냈다(ex. kinds[num]).
- 굳이 밖에서 쓸 필요없는 내부로직은 접근제어자 private로 막았다.
- 이를 통해 Main에서는 drawCard( ), show( ) 메서드를 이용해 랜덤한 카드를 뽑을 수 있다.
public class CardMain {
public static void main(String[] args) {
Card card = new Card();
Scanner scanner = new Scanner(System.in);
while (true){
card.drawCard();
card.show();
if (scanner.nextLine().equals("e")) {
break;
}
}
System.out.println("현재 카드의 넓이는: " + Card.width);
System.out.println("현재 카드의 높이는: " + Card.height);
}
}
- shuffleNum( ), shuffleKind( )가 정상적으로 숫자들을 뽑는지 검증하기 위해 while로 반복했다.
- "e" 라는 문자를 치지 않는 이상 계속 반복해서 인스턴스 변수에 랜덤한 종류와 숫자를 대입할 것이다.
'복습' 카테고리의 다른 글
[Java 복습] 예외처리 (1) | 2024.05.02 |
---|---|
[Java 복습] 내부 클래스 (0) | 2024.05.02 |
[Java 복습] 인터페이스의 장점 (0) | 2024.05.02 |
[Java 복습] 다형성의 장점 (0) | 2024.04.30 |
[Java 복습] 상속, 캡슐화, 다형성 (0) | 2024.04.30 |