
→ 연산자 우선순위 : 산술 > 비교 > 논리 > 대입
산술 연산자 : +, -, *, /, %, <<, >>
논리 연산자 : &&, ||, ! → 비교 연산의 결과값으로 받을 수 있는 boolean 값을 연결하는 연산
기타 연산자 : (type)→ 형변환 연산자, ? :, instance
비트 연산자
비트 연산이 제일 빠름 (컴퓨터가 바로바로 이해할 수 있어서)
자릿수를 왼쪽으로 옮기는 횟수만큼 2의 배수로 곱셈이 연산 되는 것과 동일
자릿수를 오른쪽으로 옮기는 횟수만큼 2의 배수로 나눗셈이 연산되는 것과 동일
for 문을 2개로 줄여줌
int[] numbers = {3, 6, 9, 12, 15};
for (int number : numbers) {
~~~~
}
깊은 복사를 해야함(clone 사용 → 2차원 배열에는 얕은 복사로 동작!!)
- 즉, Arrays.copyOf(복사 배열 원본, 길이); 사용!!
int[] a = {1, 2, 3, 4};
int[] b = Arrays.copyOf(a, a.length);
복습 [기본형 변수 vs. 참조형 변수]
String 기능 활용
String str = "ABCD";
int strLength = str.length();
char strChar = str.charAt(1); // str의 1번째 문자 출력
String strSub = str.substring(0, 3); // str의 0번째 부터 3번째 값 출력
//toCharArray() : String -> char[]
char[] strCharArray = str.toCharArray();
//반대로
char[] charArray = {'A', 'B', 'C'};
String charArrayString = new String(charArray);
List : 순서가 있는 데이터의 집합 (데이터 중복 허용) - 배열과 비슷Queue : 빨대🥤처럼 한쪽에서 데이터를 넣고 반대쪽에서 데이터를 뺄 수 있는 집합Set : 순서가 없는 데이터의 집합 (데이터 중복 허용 안함) - 순서없고 중복없는 배열Map : 순서가 없는 (Key,Value) 쌍으로 이루어진 데이터의 집합 (Key값 중복 허용 안함)
Collection🧬 은 기본형 변수가 아닌 참조형 변수를 저장
List
처음에 길이를 몰라도 만들 수 있음
ArrayList → 동적 배열
생성 시점에 작은 연속된 공간을 요청해서 참조형 변수들을 담아놓는다.
ArrayList<Integer> intList = new ArrayList<Integer>(); //선언 생성
intList.add(99);
intList.add(15);
intList.add(3);
sout(intList.get(2));
//2번째 값 10으로 변경
intList.set(1, 10);
//삭제
intList.remove(0); //list 첫번째 값 삭제
//비우기
intList.clear();
//list 속 인자 확인
sout(intList.toString());
linked list
메모리에 남는 공간을 요청해서 여기 저기 나누어서 실제 값을 담는다.
실제 값이 있는 주소 값으로 목록을 구성하고 저장하는 자료구조
기본적 기능은 ArrayList와 동일
조회하는 속도가 느림 (여기저기 저장해서) but, 값을 추가하거나 삭제할 때는 빠름
LinkedList<Integer> linkedList = new LinkedList<Integer>();
//ArrayList와 명령어는 같음
linkedList.add(2, 4); //2번째 index에 4를 추가 -> 빠름
FILO
push, peek, pop 기억!!
최근 저장된 데이터를 나열하거나, 데이터 중복 처리를 막고 싶을 때
Stack<Integer> intStack = new Stack<Integer>();
intStack.push(10);
intStack.push(15);
intStack.push(1);
while(!intStack.isEmpty()){ // 비어 있을 때까지 값을 빼준다.
sout(intStack.pop()); // 상단에 있는 값만 빼준다.
}
intStack.push(10);
intStack.push(15);
intStack.push(1);
sout(intStack.peek()); //상단에 있는 값 출력
sout(intStack.size()); //Stack 크기 출력
FIFO
add, peek, poll 기억
생성자가 없는 인터페이스
Queue<Integer> intQue = new LinkedList<>(); //생성자가 없기 때문에 LinkedList로 선언
intQue.add(1);
intQue.add(5);
intQue.add(9);
while(intQue.isEmpty()) {
sout(intQue.poll()); //처음 넣었던 값 순서대로 빼내기
}
intQue.add(1);
intQue.add(5);
intQue.add(9);
sout(intQue.peek()); // 맨 먼저 넣었던 값 출력
sout(intQue.size()); // 큐 사이즈 출력
집합과 닮음 : 순서 없고, 중복 없음
순서가 보장되지 않는 대신 중복을 허용하지 않도록 하는 프로그램에서 사용할 수 있는 자료구조
Set → 그냥 쓸 수도 있으나, HashSet, TreeSet 등으로 응용
생성자가 없는 인터페이스여서 바로 생성 불가
→ 생성자가 존재하는 HashSet을 이용해서 set 구현 가능
입력한 순서대로 요소를 유지해야 할 필요가 있는 경우에는 LinkedHashSet
을 사용
set은 특정 위치의 값을 불러들이기 힘들다.
Set<Integer> intSet = new HashSet<>();
intSet.add(1);
intSet.add(12);
intSet.add(5);
intSet.add(9);
intSet.add(1);
intSet.add(12);
for (Integer val : intSet){
sout(value);
} // 값이 1, 5, 9, 12 -> 4개만 나옴(중복 제거)
//contains 메소드
sout(intSet.contains(2)); // 2를 포함하고 있니? -> true or false
map : key - value pair → 중요!!
key라는 값으로 unique하게 보장이 되어야 함!!
Map → HashMap, TreeMap 응용!
Map<String, Integer> intMap = new HashMap<>(); // <key, value> !!
intMap.put("일", 11);
intMap.put("이", 12);
intMap.put("삼", 13);
intMap.put("삼", 14);// 중복 키
intMap.put("삼", 15);// 중복 키
for(String key : intMap.keySet()) { //키 값만 빼낸다
sout(key);
} // 세개 키 값만 출력
for(String key : intMap.values()) { //value 값만 빼낸다
sout(key);
} // 11, 12, 15 출력 -> 중복 키의 value 값 중 마지막 값으로 출력
sout(intMap.key("삼")); // 키가 "삼"이라는 키의 value 값을 출력 -> 15!!
객체란 무었인가?
객체 지향 프로그래밍의 특징
객체와 클래스
중요!!
클래스 설계
public class Car {
//필드 영역===============================================================//
//필드 선언
//고유 데이터 영역---------------------------------------------------------//
String company;
String model;
String color;
double price;
//상태 데이터 영역---------------------------------------------------------//
double speed;
char gear;
boolean lights;
//객체 데이터 영역---------------------------------------------------------//
Tire tire;
Door door;
Handle handle;
//생성자 영역=============================================================//
//생성자 : 처음 객체가 생성될 때(instance 화) 어떤 로직을 수행하며,
//어떤 값이 필수로 들어와야 하는지 정의!
public Car() {
}
//logic
// 아무것도 없는 상태 : 기본 생성자 = 생략 가능
// 메서드 영역============================================================//
//gasPedal
//input : km/H
//output : speed
double gasPedal(double kmH) {
speed = kmH;
return speed;
}
//brakePedal
//input : void
//output : speed
double brakePedal() {
speed = 0;
return speed;
}
//changeGear
//input : gear(char type)
//output : gear(char type)
char changeGear(char type) {
gear = type;
return gear;
}
//onOffLight
//input : void
//output : lights(boolean)
boolean onOffLights() {
lights = !lights;
return lights;
}
//horn
//input : void
//output : void
void horn() {
System.out.println("빵빵~~~");
}
}
public class Main {
public static void main(String[] args) {
Car car1 = new Car();
Car car2 = new Car();
System.out.println(car1); // week03.Car@6d03e736
//-> 별도 공간에 저장하고 그 주소를 가져옴
//
Car[] carArray = new Car[3];
car1.changeGear('P');
carArray[0] = car1;
car2.changeGear('N');
carArray[1] = car2;
Car car3 = new Car();
car3.changeGear('D');
carArray[2] = car3;
for(Car car : carArray) {
System.out.println("car.gear = " + car.gear);
}
}
}
//======================================================================//
//Tire Class & Handle Class & Door Class
public class Tire {
public Tire() {
System.out.println("타이어가 생성 되었습니다.");
}
}
public class Handle {
public Handle() {
System.out.println("손잡이 객체가 생성되었습니다.");
}
}
public class Door {
public Door() {
System.out.println("문 객체이 생성되었습니다.");
}
}
객체의 속성
필드

필드를 정의하여 선언했다고 바로 사용 불가 → 인스턴스화를 해야한다.
필드 사용방법
📌 ‘필드를 사용한다’ 라는 의미는 필드의 값을 변경하거나 읽는 것을 의미 - 우리가 클래스에 필드를 정의하여 선언했다고 해서 바로 사용할 수 있는 것은 아님 - 클래스는 설계도일 뿐 실제로 필드의 데이터를 가지고 있는 것은 객체이다. - 따라서 객체를 생성한 후에 필드를 사용할 수 있다. - 외부 접근 - `Car car = new Car();` - 이렇게 객체를 생성했다면 우리는 참조변수 car를 이용하여 외부에서 객체 내부의 필드에 접근하여 사용할 수 있다. - 이때 객체의 내부 필드에 접근하는 방법은 도트(.) 연산자를 사용하면 된다. - `car.color = "blue";` - 내부 접근 - 도트 연산자를 사용하여 외부에서 객체 내부에 접근할 수 있을 뿐만 아니라 객체 내부 메서드에서도 내부 필드에 접근할 수 있다. ```java double brakePedal() { speed = 0; return speed; } ``` - 이처럼 `brakePedal()` 메서드 내부에서 객체의 필드 speed를 바로 호출해서 사용할 수 있다.초기화한 Main Class 코드
public class Main {
public static void main(String[] args) {
Car car = new Car();
//초기값과 기본값 확인 : 초기값을 준 것은 그 값이 들어가고,
//아닌 값은 default value가 set
System.out.println("car.model = " + car.model); // 초기값 "Gv80"이 출력
System.out.println("car.color = " + car.color); // 기본값 null이 출력
System.out.println();
System.out.println("car.speed = " + car.speed); // 기본값 0.0이 출력
System.out.println("car.gear = " + car.gear); // 기본값 \u0000(공백)이 출력
System.out.println("car.lights = " + car.lights); // 초기값 true가 출력
System.out.println();
System.out.println("car.tire = " + car.tire); // 초기값 인스턴스의 주소가 출력
System.out.println("car.door = " + car.door); // 기본값 null이 출력
System.out.println();
//필드 사용
car.color = "blue"; // 필드 color "blue" 저장
car.speed = 100;
car.lights = false;
System.out.println("car.speed = " + car.speed); // 100.0 출력
System.out.println("car.color = " + car.color); // blue 출력
System.out.println("car.lights = " + car.lights); // false 출력
}
}
return; 이렇게 return문을 사용하여 원하는 지점에서 메서드를 종료할 수도 있다.Car car = new Car();car.brakePedal();car.gasPedal(100, 'D');double gasPedal(double kmh, char type) {
changeGear(type);
speed = kmh;
return speed;
}gasPedal(double kmh, char type) 메서드 내부에서 해당 객체의 changeGear(type); 메서드를 호출할 수 있습니다.double gasPedal(double kmH, char type) {
changeGear(type); // 가속도 페달을 밟으면 자동으로 기어가 변한다.
speed = kmH;
return speed;
}
// 자동차의 속도 .. 가변길이 메서드
void carSpeed(double ... speeds) {
for(double v : speeds) {
System.out.println("v = " + v);
}
}
public class Main {
public static void main(String[] args) {
Car car = new Car();
System.out.println("밟기 전 car.gear = " + car.gear);
double speed = car.gasPedal(100, 'D');
System.out.println("speed = " + speed); // 100.0 출력
System.out.println("밟은 후 car.gear = " + car.gear); // D 출력
car.carSpeed(100, 80);
System.out.println();
car.carSpeed(110, 120, 150); // 하나씩 출력
}
}
메서드의 이름이 같고, 매개변수의 개수 or 타입 or 순서가 달라야 함
오버 로딩은 매개변수의 차이로만 구현할 수 있음
예시 코드
public void println(boolean x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
public void println(char x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
public void println(int x) {
if (getClass() == PrintStream.class) {
writeln(String.valueOf(x));
} else {
synchronized (this) {
print(x);
newLine();
}
}
}
메서드 이름을 절약할 수 있음
기본형 매개 변수 → 읽는 것만 가능
참조형 매개 변수 → 읽고 변경하는 것만 가능
예시 코드 Car Class & Main Class
double brakePedal(char type) {
speed = 0;
type = 'P'; // 정지 후 매개변수 type을 어떤 타입으로 전달 받았는지
//상관없이 'P'로 고정시키기
changeGear(type);
return speed;
}
//기본형 매개 변수
char type = 'D';
car.brakePedal(type);
// 메서드 실행 완료 후 전달할 매개값으로 지정된 type 값 확인
System.out.println("type = " + type); // 기존에 선언한 값 'D' 출력,
//원본 값 변경되지 않음
// 메서드 실행 완료 후 반환된 car 인스턴스의 gear 타입 확인
System.out.println("gear = " + car.gear); // 객체 내부에서 type을 변경하여
//수정했기 때문에 'P' 출력
Tire setTire(Tire tireCompany) {
tireCompany.company = "KIA"; // 금호 타이어를 전달 받았지만 강제로
//KIA 타이어로 교체
tire = tireCompany;
return tire;
}
// 참조형 매개 변수
Tire tire = new Tire();
tire.company = "금호"; // 금호 타이어 객체 생성
// 차 객체의 타이어를 등록하는 메서드 호출한 후 반환값으로 차 객체의
//타이어 객체 반환
Tire carInstanceTire = car.setTire(tire);
// 메서드 실행 완료 후 전달할 매개값으로 지정된 참조형 변수 tire의
//company 값 확인
System.out.println("tire.company = " + tire.company); // "KIA" 출력
// 전달할 매개값으로 지정된 tire 인스턴스의 주소값이 전달되었기 때문에
//호출된 메서드에 의해 값이 변경됨.
// 메서드 실행 완료 후 반환된 car 인스턴스의 tire 객체 값이 반환되어 저장된
//참조형 변수 carInstanceTire의 company 값 확인
System.out.println("carInstanceTire.company = " + carInstanceTire.company);
// "KIA" 출력
인스턴스 멤버 / 클래스 멤버
인스턴스 멤버 = 인스턴스 필드 + 인스턴스 메서드
클래스 멤버 = 클래스 필드 + 클래스 메서드
선언하는 방법에 따라 인스턴스 멤버인지 클래스 멤버인지 구분
필드와 메서드를 클래스 멤버로 만들기 위해서는 static 키워드를 사용하면 된다.
일반적으로 인스턴스마다 모두 가지고 있을 필요없는 공용적인 데이터를 저장하는 필드는 클래스 멤버로 선언하는 것이 좋다.
또한 인스턴스 필드를 사용하지 않고 실행되는 메서드가 존재한다면 static 키워드를 사용하여 클래스 메서드로 선언하는 것이 좋다.
인스턴스 멤버는 객체 생성 후에 사용 가능 클래스 멤버는 객체 생성 없이도 사용 가능
[클래스]static String company = "GENESIS"; // 자동차 회사 : GENESIS
[인스턴스]String getCompany() {
return "(주)" + company;
}
→ 필드가 클래스 & 메서드가 인스턴스
[클래스]static String setCompany(String companyName) {
//[인스턴스] System.out.println("자동차 모델 확인: " + model);
// 인스턴스 사용 불가
company = companyName;
return company;
}
메서드가 클래스 필드가 인스턴스/ model을 static을 붙여서 선언
위 코드에서 model은 static 선언을 안 해서 사용 불가
public class Main {
public static void main(String[] args) {
// 클래스 필드 company 확인
System.out.println(Car.company + "\n");
// 클래스 필드 변경 및 확인
Car.company = "Audi";
System.out.println(Car.company + "\n");
// 클래스 메서드 호출
String companyName = Car.setCompany("Benz");
System.out.println("companyName = " + companyName);
System.out.println();
// 참조형 변수 사용
// 인스턴스화 안하고 사용이 가능해서 아래와 같이 안하는 것이 좋음
Car car = new Car(); // 객체 생성
car.company = "Ferrari";
System.out.println(car.company + "\n");
String companyName2 = car.setCompany("Lamborghini");
System.out.println("companyName2 = " + companyName2);
}
}
지역 변수/final 필드/상수
생성자 !!
인스턴스를 의미
무조건 this를 써주는게 좋다.
this() → 생성자 의미
public Car(String model) {
this.model = model;
this.color = "Blue";
this.price = 50000000;
}
public Car(String model, String color) {
this.model = model;
this.color = color;
this.price = 50000000;
}
public Car(String model, String color, double price) {
this.model = model;
this.color = color;
this.price = price;
}
// 같은 의미 코드 중복 제거!!
public Car(String model) { // 맨 아래 생성자로 토스!
this(model, "Blue", 50000000);
}
public Car(String model, String color) { // 맨 아래 생성자로 토스!
this(model, color, 100000000);
}
public Car(String model, String color, double price) {
this.model = model;
this.color = color;
this.price = price;
}
접근 제어자
public : 접근 제한이 전혀 없습니다. *protected : 같은 패키지 내에서, 다른 패키지의 자손 클래스에서 접근이 가능합니다default : 같은 패키지 내에서만 접근이 가능합니다.private : 같은 클래스 내에서만 접근이 가능합니다. *public, defaultpublic, protected, default, privatepackage와 import
상속
final 클래스 & final 메서드
Object 클래스
오버 라이딩
super : 자식 클래스에서 부모 클래스 멤버에 접근할 때 사용
// 부모 클래스 Car
String model; // 자동차 모델
String color; // 자동차 색상
double price; // 자동차 가격
// 자식 클래스 SportsCar
String model = "Ferrari"; // 자동차 모델
String color = "Red"; // 자동차 색상
double price = 300000000; // 자동차 가격
//자식 클래스의 메서드
public void setCarInfo(String model, String color, double price) {
super.model = model; // model은 부모 필드에 set
super.color = color; // color는 부모 필드에 set
this.price = price; // price는 자식 필드에 set
}
자식 클래스의 메서드를 호출하면 super 키워드로 접근한 부모 클래스의 model, color 필드에 매개변수의 값이 저장
this 키워드로 접근한 자식 클래스의 price 필드에는 매개변수의 값이 저장
다형성
여러 가지 형태를 가질 수 있는 능력
instanceof → 상속 관계 확인 명령어
Parent p = new Parent();
System.out.println(p instanceof Object); // true 출력
System.out.println(p instanceof Parent); // true 출력
System.out.println(p instanceof Child); // false 출력
Parent c = new Child();
System.out.println(c instanceof Object); // true 출력
System.out.println(c instanceof Parent); // true 출력
System.out.println(c instanceof Child); // true 출력
추상화
abstract 키워드를 사용하여 추상 메서드를 선언
추상 메서드는 일반적인 메서드와는 다르게 블록{ }이 없다.
즉, 정의만 할 뿐, 실행 내용은 가지고 있지 않다.
public abstract class 추상클래스명 {
abstract 리턴타입 메서드이름(매개변수, ...);
}
추상 메서드는 extends 키워드를 사용하여 클래스에서 상속
상속받은 클래스에서 추상 클래스의 추상 메서드는 반드시 오버라이딩 되어야 한다.
public class 클래스명 extends 추상클래스명 {
@Override
public 리턴타입 메서드이름(매개변수, ...) {
// 실행문
}
}