본문 바로가기

회고록(TIL&WIL)

WIL 2022.12.12 ~ 2022.12.16 java 공부

자바 컴파일 시 클래스 파일 생성 되는 경로 설정 -d [directory]

javac -d dest -encoding utf8 Ex01.java

클래스

특정상황에 $, _ 가 자동으로 생성되는 경우가 있기 때문에 우리가 직접 작성하게되면 오해를 불러 일으킬 수 있기 때문에 피해야한다.
OuterClass$InnerClass.class >> 이너클래스를 사용할 경우 클래스 파일명에 $가 포함되어 자동으로 생성되는 경우가 있다.
이처럼 자동 생성되는 경우가 있기 때문에 클래스 명에 사용할 수 있는 특수문자를 사용할 경우 오해를 할 수 가 있다.


컴파일은 항상 클래스명을 따라 클래스파일이 생성되기 때문에 소스코드 파일명 동일해야한다.
컴파일 자동화할 때도 문제가 생길 뿐더러 파일명이 다르게 되면 여러 명령어를 사용할 때 불일치하면 사용 할 수 없게 된다.

패키지

소스코드에 패키지 추가하고

package com.my;
class Ex01{public static void main(String[] args){System.out.println("출력");}}

클래스 파일이 생성되는 경로를 .을 이용해서 현재 경로로 지정하면 현재위치 기준으로 경로를 찾으며 없을 경우 자동으로 폴더도 생성된다.

javac -encoding utf8 -d . Ex01.java

패키징 되어있는 클래스 파일을 실행하기 위해서는 .을 통해서 경로를 타고 들어가면된다.

java com.my.Ex01

메서드

메서드의 기본의의는 반복이다. 같은 코드를 반복 호출할 수 있도록 해주는 것 이 메서드다.
반복문과 다른 점은 서로 다른 값으로 코드를 반복 할 수 있다. 메서드 호출 시 매개변수의 갯수와 타입이 모두 일치 해야만한다.


원칙적으로 메서드의 이름은 중복이 불가능 하다.
다만, 인자의 유무, 갯수, 타입이 다를 경우 서로 구분이 가능하기 때문에 같은 이름의 메서드라도 정의 가능하다.
이를 메서드 오버로딩(overloading) 이라고 부른다.


모든 메서드는 return을 가지고 있는데 생략해도 컴파일 단계에서 자동으로 생성해준다.
return을 하게 되면 호출 지점으로 돌아간다.


자바에서 종료하는 여러 방법이 있지만 제일 권장되는 방법은 main 메서드를 return; 시키는 것(System.exit(1)의 경우는 강제종료와 같다)


return 시에 매개변수를 가져갈 수 있다. 단, 어떤 타입으로 return하는지 메서드 정의 시 반드시 지정해줘야한다.
return 타입만 다르다고 해서 오버로딩 할 수 없다. 오버로드의 구분요소에 포함되지 않는다.

메모리 구조

클래스영역 | Core | static 영역
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
스택영역 Ex04 me = new Ex04();
ㅡㅡㅡㅡㅡㅡㅡ↓참조ㅡㅡㅡㅡㅡㅡㅡㅡ
힙영역 Ex04의 인스턴스
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
스택 - 선입후출(방문기록, 실행취소 등)
큐 - 선입선출(대기열, 네트워킹 등)


클래스명 함수명을 중복하지 않기 위해서 트리형식으로 패키지를 구성한다.
static > static [클래스명.]메서드명();
static > non-static 참조변수.메서드명();
non-static > static [클래스명.]메서드명();
non-static > non-static [참조변수명.]메서드명();


클래스변수(전역변수)의 특성

  1. 한군데에서 바꾸면 다 바뀐다.
  2. default 값이 존재한다. (초기화 없이 사용 가능)
  3. default 값을 사용하든, 선언과 초기화가 동시에 이뤄져야함.

객체지향적으로 코드를 작성해야한다.

항상 생각 해야 하고 현실과 비유 해보자.
정보 > 필드 , 기능 > 메서드
플로우를 생각하는게 아니라 클래스의 객체 표현 방식을 어떻게 할 건지 생각을 해야한다.
그렇기 때문에 속성과 기능을 나눠서 생각 및 정리하는 것이 중요하다.
조심해야 될 점은 객체와 객체끼리 영향을 주어서는 안된다!
객체 고유의 값은 멤버필드, 클래스(static) 필드를 이용하게 될 경우 모든 객체에 영향이 가니까 주의!
그렇기 때문에 클래스를 작성할 때 이러한 부분들을 판단 해야한다.
자바에 포인터는 없지만 포인터 역할을 하는 참조변수들이 있다.

생성자

객체 생성시점에 하고자 하는 일 명시
객체 생성 시 단 한번만 호출 가능
생성자를 정의하지 않을 시 디폴트 생성자가 자동생성
주의! 생성자 생성 시 재귀호출 하게 될 경우 무한루프에 빠진다.
필드 값을 초기화하는데 많이 사용되며
상수값을 초기화 할 때 유용하다.

상수

변경 되지 않는 값을 선언 해두고 싶을 때
final 키워드를 이용해서 상수 값으로 만들 수 있다.
변수명은 전부 대문자로 작성해야한다.

키워드 this

자기 자신을 호출할 당시에 그 객체를 매개변수로 받지 않더라도 this가 그 객체의 참조변수 역할을 수행한다.
오직 non-static에서만 사용 할 수 있다. static에선 this라는게 존재 할 수 없다.
this(매개변수) >> 오직 생성자에서만 존재하며 오버로딩된 다른 생성자를 호출하는 것(코드의 중복을 막기위한 것)
this()를 사용하는 생성자에서는 객체가 생성되지않는다. 객체 생성은 this()를 통해 호출된 생성자에서 생성된다.

재귀함수

public static int func01(int su){
  if(su==0){
    return 0;
  } else {
    return su-- + func01(su);
  }
}
...
System.out.println(fun01(5));
>> 15

체이닝 기법

public Ex06 func03(){
  System.out.print("fun03 run...");
  return this;
}
...
Ex06 me = new Ex06();
me.fun03().fun03().fun03()
>> fun03 run...fun03 run...fun03 run...

접근제한자

클래스, 생성자, 전역변수, 메서드
public - 어디서든 접근 허용
default - 같은 패키지에서만 접근 허용
private - 외부에서 접근 불가능

하나의 소스코드에에 두개 이상의 클래스가 있을 경우에 public은 파일명과 같은 클래스만 쓸 수 있다.
애초에 다른 클래스들은 외부에서 사용하려는 것이 아닌 내부에서 사용하기 위해 정의 하는 거니까

배열

  1. 0부터 시작
  2. 연속됨
  3. 마지막 index는 lenth -1
  4. ArrayIndexOutOfBoundsException
    image
  • 배열이 사용되는 main 메서드의 매개변수
    image

String 클래스

자바 API 문서
https://docs.oracle.com/javase/8/docs/api/

생성자 이용하여 char[] 배열 잘라서 문자열에 저장하기

char[] arr = {'a','b','c','d'};
String st2 = new String(arr, 1, 2);
System.out.println(st2); >> bc

상수끼리의 연산은 미리 진행된다.

String msg1 = "문자열";
String msg2 = "문자";
String msg3 = "열";
String msg4 = msg2 + msg3;
String msg5 = "문자"+"열"; // 상수의 연산은 미리 진행되기 때문에 결과 값을 기준으로 저장을 한다.

System.out.println(msg1==msg2+msg3); // false
System.out.println(msg1==msg4); // false
System.out.println(msg1==msg5); // true

String msg6 = "문자".concat("열");
System.out.println(msg1==msg6); // false concat()를 이용하니 결국 새로운 객체가 생성된다.
// 결론 : + 기호쓰는게 짱이다.. 새로운 객체를 찍어낼 경우를 생각하고 사용을 하는 것이다.

레퍼런스 비교(참조형 변수에서만)

System.out.println(msg1==msg2);

값 비교

System.out.println(msg1.equals(msg2));

String 클래스의 메서드

byte출력

byte[] arr1 = msg1.getBytes();

문자열을 char[]로 풀어서 받기

char[] arr2 = msg1.toCharArray();

index 번호에 해당하는 문자를 뽑아준다. length()-1은 마지막글자 추출

System.out.println(st1.charAt(st1.length()-1));

포함 여부 확인

System.out.println(st1.contains("cde"));

ab로 시작함?

System.out.println(st1.startsWith("ab"));

h로 끝남?

System.out.println(st1.endsWith("h"));

index 번호 찾기

//char, String를 집어넣고 해당 char가 있는 index를 얻는다.(0부터 length-1까지)
// 2개 있을 경우 제일 먼저 찾은 index 하나만 나온다.시작 index 지정 가능. 없으면 -1 반환
System.out.println(st1.indexOf('a', 2));
System.out.println(st1.indexOf("bc", 2));
// 역순으로 가면서 index 번호 조회 (length-1 부터 0 까지)
System.out.println(st1.lastIndexOf('a', 2));

빈문자열인가?

System.out.println("".isEmpty());
System.out.println("".length()==0);

문자열 자르기

System.out.println(st1.substring(3));
System.out.println(st1.substring(3,6));

특정 문자열 바꾸기

System.out.println(st1.replace('a', 'A')); 
System.out.println(st1.replace("ca", "cA")); //수정 
System.out.println(st1.replace("ade", "a")); //삭제
System.out.println(st1.replace("a", "ABC")); //입력
System.out.println(st1.replace('1', '2')); // 없으면 아무것도안함

대소문자 변환

System.out.println(msg.toUpperCase());
System.out.println(msg.toLowerCase());

문자열로 만드는 방법

// 문자 배열을 문자열로
char[] arr1 = {'a','b','c','d'};
System.out.println(new String(arr1));
System.out.println(String.valueOf(arr1));
// 숫자들을 문자열로
int num = 1234;
System.out.println(num + "");
System.out.println(String.valueOf(num));

양끝의 공백 제거

System.out.println("->"+target.trim()+"<-");

특정 문자 기준 혹은 정규표현식 기준으로 문자열 분리하여 배열에 저장

String target = "Java  DB web framework";
String[] arr1 = target.split(" ");
for(String str : arr1) {
  if(!str.isEmpty()) { // 띄워쓰기 2개이상 되었을 때 나오는 공백들 제거 
    System.out.println(str);
  }
}

문자열 비교 - 얼마나 다른지를 알려줌

String st1 = "java";
String st2 = "jbva";
System.out.println(st1.compareTo(st2)); // 0이 나오면 같은 것
// 문자열의 문자가 다르다 -> 해당하는 문자(char)끼리 뺀 값이 나온다.
// 문자열의 길이가 다르다 -> 각 문자열의 length끼리 뺀 값이 나온다.

배열의 복사

배열의 얕은 복사 - 파라미터에 주는 경우가 많다.

int[] arr1 = new int[] {1,3,5,7};
int[] arr2 = arr1;
arr1[2] = 6;
for(int i = 0; i < arr2.length; i++) {
    System.out.println(arr2[i]);
}

배열의 깊은 복사

int[] arr1 = new int[] {1,3,5,7};
int[] arr3 = new int[arr1.length];
for(int i = 0; i < arr1.length; i++) {
    arr3[i] = arr1[i];
}
arr1[2] = 5; // 값 변경해도 영향 x
for(int i = 0; i < arr3.length; i++) {
    System.out.println(arr3[i]);
}

System.arraycopy()를 이용한 깊은 복사

int[] target = {1,3,5,7,9};
int[] result = new int[5];
// 깊은 복사
System.arraycopy(target, 1, result, 1, 3); 
target[0] = 2; // 값 변경해도 영향 x
for(int i : result) {
    System.out.println(i);
}

제어 키워드

return - 메서드 내부 어디서든 존재가능, 호출된 곳으로 돌아감
continue - 반복문에서만 존재가능, 조건이 맞지않으면 아래 코드를 실행하지 않고 반복문 처음으로 돌아가서 끝까지 실행됨
break - 반복문, switch문에서 존재가능, 위치한 반복문,switch문에서 빠져나감

break와 continue의 가장 큰 차이점은 continue는 반복문 횟수를 다채울때 까지 수행하고
break는 중간에 조건이 걸리면 아직 횟수가 남았더라도 그냥 반복문을 종료함

for(int i = 0; i < 10; i++) {
    System.out.println("before i =" + i);
    if(i > 5) break; or continue;
    System.out.println("after i=" + i);
}

break >> before와 after 결과값이 똑같은 갯수 || continue >> after는 5까지만 찍히고 before는 9까지 다찍힘

상속

자식클래스 extends 부모클래스 의 형태로 상속
상속은 일방통행이다. 부모클래스 -> 자식클래스
자바에서는 다중상속 불가
자바의 모든 클래스는 Object 클래스를 상속받는다.(=자바의 모든클래스는 상속을 받는다)
상속의 목적은 코드의 재활용성

package com.bit;
// 상속
// 다중 상속을 지원하지 않습니다.

// 부모클래스 super class
class Lec02{
    int su1 = 1111;
    void func01() {
        System.out.println("Lec02 func01...");
//        this.func02(); 자식의 메서드 이용불가
    }
}
// 자식클래스 sub class
public class Ex02 extends Lec02{

    void func02() {
        System.out.println("Ex02 func02...");
    }

    public static void main(String[] args) {
        Ex02 me = new Ex02();
        System.out.println(me.su1);
        me.func01();
        me.func02();
    }

}

메서드 오버라이딩

부모의 기능을 자식이 재작성하는 것
접근제한자는 같거나 보다 열리는 방향으로만 허용된다.
메서드 오버라이드 - 부모의 기능을 자식이 재작성
접근제한자는 같거나 보다 열리는 방향으로만 허용됨
return타입, 매개변수까지 같아야 오버라이드가 된다.
다른건 그냥 오버로드다.
그렇기 때문에 어노테이션을 달아주게되면 오버라이드 양식을 지킬 수 있다.
명시적으로 작성해줌으로써 컴파일러가 검증해준다.

@Override
void func() {
  System.out.println("sub function...");
}

캐스팅

package com.bit;

class Lec05{
    int su = 1111;
    void func01() {
        System.out.println("부모기능");
    }
}

public class Ex05 extends Lec05{

    @Override
    void func01() {
        System.out.println("자식기능");
    }
    void func02() {
        System.out.println("다른기능");
    }

    public static void main(String[] args) {
        Lec05 me1 = new Lec05();
        me1.func01();
        // 부모클래스의 객체는 자식을 모르기 때문에 캐스팅 불가능
//        ((Ex05)me1).func02(); 컴파일에선 오류가 안나지만 실행하면 오류 발생

        Ex05 me2 = new Ex05();
        me2.func01(); 
        me2.func02();

        Lec05 me3 = new Ex05();
        // 부모클래스이지만 자식클래스로 객체를 만들면
        // 자식객체로 캐스팅도 가능하다.
        me3.func01(); // 오버라이딩된 자식의 메서드 실행됨
        ((Ex05)me3).func02(); // 자식객체만 가지고 있는 메서드 실행됨
    }

}

생성자


class Lec06{

    public Lec06() {
        super(); // Object의 default 생성자 호출
    }

    void func01() {
        System.out.println("부모기능");
    }
}
public class Ex06 extends Lec06{

    // default 생성자의 형태
    public Ex06() {
        super(); // Lec06의 default 생성자 호출. 
        // 부모객체를 먼저 찍어야지만 내 객체를 찍을 수있다. 
        // 보통은 생략되어있으나 default 생성자가 없을 경우 반드시 명세해줘야한다.
    }
    // 매개변수를 가지고 있는 생성자 오버라이딩 시
    public Ex06(int a) {
        this(); // this와 super는 공존할 수 없다.
        System.out.println("자식 객체 생성");
    }
    public Ex06(double a) {
        this();
        System.out.println("자식 객체 생성");
    }

    public static void main(String[] args) {
        Ex06 me = new Ex06(); // 객체가 생성될 때 부모의 생성자를 먼저 호출함
        me.func01();
    }

}