JAVA
특징
- 플랫폼 독립적: 운영체제 따라 코드를 재 작성하지 않아도 됨
- 객체 지향적: 절차 지향적 언어에 비해 생산성과 보안성이 높음
실행 과정
자바 소스코드(.java) —(자바 컴파일러)—> 바이트코드(.class) —(Java Virtual Machine)—> 실행
String
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// %02d 포맷 지정자는 숫자가 한 자릿수일 경우 앞에 0을 추가하여 총 두 자리 숫자로 표시
String s;
for(int i = 1; i < 10; i++){ //구구단 출력
for(int j = 1; j < 10; j++){
s = String.format("%02d x %02d = %02d ", j, i, i*j);
System.out.print(s);
}
System.out.println();
}
String s1 = "Hi";
String s2 = "Hi";
String s3 = new String("Hi");
System.out.println(s1.equals(s2)); //true
System.out.println(s1 == s3); //false
s1 == s2가 true를 반환하는 이유는, s1과 s2가 둘 다 문자열 리터럴 “Hi”에 의해 초기화되었기 때문입니다. 자바에서는 같은 문자열 리터럴에 대해 하나의 String 객체를 재사용합니다. 따라서, s1과 s2는 동일한 메모리 위치를 가리키게 되고, == 연산자는 true를 반환합니다.
s1 == s3가 false를 반환하는 이유는, s3가 new String(“Hi”)를 사용하여 명시적으로 새로운 String 객체를 생성했기 때문입니다. 이 경우, s3는 s1이나 s2와는 다른 메모리 위치를 가리키게 됩니다. 그래서, == 연산자는 두 참조가 서로 다른 객체를 가리키고 있다고 판단하고 false를 반환합니다.
1
2
3
4
5
6
7
8
9
// - StringBuffer : 문자열을 자주 추가하거나 변경할 때 사용
// 값이 변경되어도 객체가 새로 생성되는 일이 없음
// String은 값에 변화가 생길 때마다 객체가 새로 생성 됨
StringBuffer sb = new StringBuffer("Hello World");
// method : append, insert substring
//array 선언
int[] array = {1,2,3,4};
String[] str = new String[3];
1
2
3
4
5
//list
ArrayList list = new ArrayList();
list.add(1);
// method : add, get, size, remove, clear, sort, contains
list.sort(Comparator.naturalOrder()); //오름차순 정렬
ArrayList에는 두 가지 형태의 remove 메서드가 있습니다
- remove(int index) : 인덱스에 위치한 요소를 제거하고, 제거한 값을 반환합니다.
- remove(Object o) : 매개변수로 받은 객체와 일치하는 첫 번째 요소를 제거합니다. 객체가 리스트 내에 있을 때 제거하고 true를 반환하며, 없을 경우 false를 반환합니다.
1
2
3
4
5
6
7
8
//Map : key, value 쌍으로 이루어짐. key 값을 통해서 접근(get("key"))
HashMap map = new HashMap();
map.put("product", "kiwi");
//method : put, get, size, remove, containsKey
//Generics : 자료형을 명시적으로 지정, 안전성 증가, 형변환 자동
ArrayList<String> list = new ArrayList<String>();
HashMap<String, String> map = new HashMap<String, String>();
형변환
1
2
int num = Integer.parseInt("123");
String str = Integer.toString(123);
삼항 연산자
연산에 사용되는 항이 세 개 왼쪽에 식이 맞았을 때 사용할 값 입력 ex) (3 > 1) ? 1 : 0
2의 보수
2의 보수는 주로 음수를 표현하는 데 사용
2진수 3의 2의 보수를 구하는 방법
- 주어진 수의 이진수 표현을 찾습니다: 3 -> 11
- 이진수의 모든 비트를 반전시킵니다 (0은 1로, 1은 0으로): 11 -> 00
- 반전된 수에 1을 더합니다: 00 + 1 = 01
비트 논리 연산자
&(AND), |(OR), ^(XOR), ~(NOT) « 연산자 : 비트를 왼쪽으로 이동, 곱하기 2 효과
연산자 : 비트를 오른쪽으로 이동, 나누기 2 효과(기존의 부호비트로 앞을 채움 )
연산자 : 부호비트 상관 없이 0으로 채움
오버로딩(Overloading)
- 한 클래스 내에서 같은 이름의 메소드를 여러 개 정의
- 매개변수의 개수 또는 타입이 달라야 함(리턴타입 차이로는 오버로딩 x)
접근제어자
- public: 어디서든 접근 가능
- private: 해당 클래스에서만 접근 가능
- (defalut): 해당 패키지 내에서만 접근 가능
- protected: 해당 패키지 및 상속 받은 클래스에서 접근 가능
Static과 final
static
- 클래스 변수와 메소드:
static
키워드를 사용하면 해당 변수나 메소드는 클래스에 속하게 됩니다. 즉, 특정 인스턴스가 아닌 클래스 자체에 속합니다.1 2 3 4 5 6 7
public class Example { static int staticVariable = 10; static void staticMethod() { System.out.println("This is a static method."); } }
- 클래스 변수:
static
변수는 모든 인스턴스가 공유합니다. 즉, 하나의 클래스에 속하는 모든 객체가 동일한static
변수를 공유합니다. - 클래스 메소드:
static
메소드는 객체의 상태와 무관하게 호출할 수 있습니다. 객체 인스턴스를 생성하지 않고도 호출할 수 있습니다.
- 클래스 변수:
final
- 상수 변수:
final
키워드를 사용하여 변수를 선언하면 그 변수는 한 번 초기화된 후 값을 변경할 수 없습니다.1 2 3
public class Example { final int constantVariable = 100; }
- 상수 변수:
final
변수는 한 번 값이 설정되면 더 이상 값을 변경할 수 없습니다. 보통 상수로 사용됩니다.
- 상수 변수:
- 메소드:
final
메소드는 서브클래스에서 오버라이드할 수 없습니다.1 2 3 4 5
public class Example { final void finalMethod() { System.out.println("This method cannot be overridden."); } }
- 클래스:
final
클래스는 다른 클래스가 상속할 수 없습니다.1 2 3
public final class Example { // This class cannot be subclassed. }
요약
static
: 클래스 변수 및 메소드, 클래스 수준에서 접근 가능.final
: 상수 변수, 메소드 오버라이딩 방지, 클래스 상속 방지.
상속(Inheritance)
- 부모 클래스의 필드와 메소드가 상속됨
- 오버라이딩(Overrifing) : 부모 클래스의 메소드를 자식 클래스에서 재정의(메소드 선언부는 부모 클래스의 선언부와 동일해야 한다.)
1 2 3 4 5 6
class 자식클래스명 extends 부모클래스명 { //필드;; //메소드;; super(); //부모 클래스의 생성자 호출 //super.부모필드; }
다형성(Polymorphism)
- 한 객체가 여러 가지 타입을 가질 수 있는 것
- 부모 클래스 타입의 참조 변수로 자식클래스 인스턴스 참조
1
2
3
4
5
6
7
8
9
class Person{}
class Student extends Person{}
Person p1 = new Student(); // 다형성, 업캐스팅
//이 경우 자식 클래스에서만 정의한 메소드 사용 불가
Student s1 = (Student)p1; //다운캐스팅
//Student s1 = new Person(); // 불가
추상화
추상화는 복잡한 시스템을 단순화하여 필요한 부분만을 클래스로 표현하는 작업. 이는 속성(attribute)과 행동(method)을 통해 실현.
추상 클래스(Abstract Class)
- 정의: 하나 이상의 추상 메소드를 포함하는 클래스.
- 추상 메소드(Abstract Method):
- 자식 클래스에서 반드시 오버라이딩해야 하는 메소드
- 메소드 선언만 있고, 구현 내용은 없다.
- 목적: 반드시 구현해야 하는 부분을 명시적으로 표현.
- 특징: 추상 클래스 자체로는 객체를 생성할 수 없다.
1
2
3
abstract class 클래스명 {
abstract void print();
}
예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
abstract class Animal {
// 추상 메소드
abstract void makeSound();
// 일반 메소드
void breathe() {
System.out.println("Breathing");
}
}
class Dog extends Animal {
// 추상 메소드를 구현
@Override
void makeSound() {
System.out.println("Bark");
}
}
public class Main {
public static void main(String[] args) {
// Animal animal = new Animal(); // 에러: 추상 클래스는 인스턴스화할 수 없음
Animal dog = new Dog();
dog.makeSound(); // 출력: Bark
dog.breathe(); // 출력: Breathing
}
}
인터페이스
- 다중 상속처럼 사용할 수 있는 기능
- 추상 메소드와 상수만으로 이루어짐
1
2
3
4
5
6
7
8
9
10
접근제어자 interface 인터페이스명 {
public static final 타입 상수이름 = 값; //값 변경 불가
public abstract 반환타입 메소드이름(매개변수);
}
//상속과 인터페이스 동시 사용
class 클래스B extends 클래스A implements 인터페이스명{
}
내부 클래스(Inner Class)
- 인스턴스 클래스 : 외부 클래스의 모든 인스턴스 변수 및 메소드에 접근
- 정적 클래스 : 외부 클래스의 정적 멤버에만 접근 가능
- 지역 클래스 : 메서드 내부에 정의
- 익명 클래스 : 선언과 동시에 객체 생성, 일회용
1 2 3 4 5 6 7 8 9 10
class Outer { class Inner { // 내부에서 외부 클래스의 모든 멤버(인스턴스 멤버 포함) 접근 가능 } Anony a1 = new Anony(){ //익명 클래스 } }
입출력
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Scanner sc = new Scanner(System.in);
System.out.print("입력: ");
System.out.println(sc.nextLine());
sc.close();
//출력
System.out.printf("%d\n", 10); //정수
System.out.printf("%o\n", 10); //8진수
System.out.printf("%x\n", 10); //16진수
System.out.printf("%f\n", 5.2f); //소수점
System.out.printf("%.2f\n", 1.126123f); //두번째 자리까지 반올림해서 출력
System.out.printf("%c\n", 'A'); //문자
System.out.printf("%s\n", "안녕하세요"); //문자열
System.out.printf("%5d\n", 123); //5개 공간을 차지
System.out.printf("%-5d\n", 1234); //왼쪽에 붙음
예외 처리(Exception Handling)
- throw : 예외를 발생 시킴
- throws : 예외를 전가 시킴(메소드 안에서 처리x) ```java class NotTenException extends RuntimeException {}
if (ten != 10) { throw new NotTenException(); // NotTenException 예외를 발생시킴 }
public static boolean checkTenWithThrows(int ten) throws NotTenException {// 메서드 선언에 throws를 사용하여 안에서 처리하지 않고 예외를 전달 if (ten != 10) { throw new NotTenException(); } return true; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
### 컬렉션 프레임워크(Collection Framework)
- 자료 구조 및 알고리즘을 구조화한 것
1. List 인터페이스
- 순서가 있는 데이터의 집합
- 데이터 중복 허용
- ArrayList, LinkedList, Vector
2. Set 인터페이스
- 순서가 없는 데이터의 집합
- 데이터의 중복 허용 하지 않음
- HashSet, TreeSet(add 할때, 자동정렬됨)
3. Map 인터페이스
- 키와 값의 쌍의 집합
- 순서를 유지하지 않음
- HashMap, TreeMap
```java
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("Apple");
arrayList.add("Banana");
System.out.println(arrayList.get(0)); // 출력: Apple
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("Carrot");
linkedList.addFirst("Beetroot");
System.out.println(linkedList.getFirst()); // 출력: Beetroot
Vector<Integer> vector = new Vector<>();
vector.add(5);
vector.add(10);
System.out.println(vector.get(1)); // 출력: 10
HashSet<String> hashSet = new HashSet<>();
hashSet.add("Dog");
hashSet.add("Cat");
System.out.println(hashSet.contains("Cat")); // 출력: true
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(22);
treeSet.add(15);
System.out.println(treeSet.first()); // 출력: 15
람다 표현식(Lambda Expression)
- 메소드 대신 하나의 식으로 표현
- 익명 함수(Anonymous function) 또는 일회용 함수라고도 함
1
(int x, int y) -> { return x + y; }
Stream
- 배열, 컬렉션 등의 데이터를 하나씩 참조, 처리하는 기능
- for문의 사용을 줄일 수 있음
- Stream 생성, 중개 연산, 최종 연산 ```java int[] arr = new int[]{1,2,3}; Stream stream = Arrays.stream(arr); //배열의 경우
ArrayList list = new ArrayList(Arrays.asList(1,2,3)); Stream stream = list.stream(); //컬렉션의 경우
stream.forEach(System.out::println);//쉽게 하나씩 참조하여 출력가능
//중개연산 IntStream intSt = IntStream.range(1,10).filter(n->n%2==0); //필터링 IntStream intSt = IntStream.range(1,10).map(n->n+1); //매핑
//최종연산 int sum = IntStream.range(1,10).sum(); int max = IntStream.range(1,10).max().getAsInt(); ```