ch04~ch06

김민지·2023년 1월 12일
0

자바의정석

목록 보기
5/8

객체지향

선언과 할당

Tv tv;//a
tv = new Tv();//b
tv = new Tv();//c

a: 메모리공간에 참조변수 tv를 위한 공간이 마련된다.
b: Tv의 인스턴스가 생성되고 tv가 이를 가리키게 된다
c: b에서 생성된 공간은 JVM의 가비지 컬렉터가 제거

다형성

하나의 배열로 여러종류의 객체를 다루는 방법 - 다형성 사용하기

제어자

  • 제어자와 메서드를 적절하게 활용하면 이상한 값을 넣었을때와 같은 예외처리를 쉽게할 수 있다
public class Time{
	private int hout;
    public void setHour(int h){
    	if(h<0 || h>23) return; 
        hour = h;
    }
}

변수 종류

  • 클래스변수: 멤버변수중 static이 붙은 것
  • 인스턴스변수: 멤버변수중 static이 붙지않은 것
  • 지역변수

JVM의 메모리구조

Method Area: 클래스 변수, 클래스 정보 저장
Heap: 인스턴스변수 저장
call Stack: 메서드작업에 필요한 메모리공간 제공

값의 복사

  • 기본형 변수인 경우는 값이 복사되지만 참조형인 경우 주소가 복사된다
class Data {int x;}
public static void main(String[] args){
	Data d = new Data();
    d.x = 10;
    change(x);
    System.out.println(x);//10
}
static void change(int x){
	x = 1000;
    System.out.println(x);//1000
}
  • 변경되지않은 이유는 매개변수로 기본형이 넘어갔기때문에 원복을 수정하지 않고 복사본을 수정했기때문이다 change라는 메서드가 종료되면서 call stack에서 사라졌고, 그 결과 1000을 가진 x라는 변수도 사라져 버렸다

왜 static 메서드인데 클래스이름을 생략할까?


public class Main{
    public static void func(){
        
    }
    public static void main(String[] args) throws IOException {
        Main.func();
        func();
    }


}
  • 같은 클래스 내에 있으면 class이름을 생략하여도된다

static method

  • 인스턴스변수를 사용한다면 인스턴스 메서드를 사용하고 만약 인스턴스와 관꼐없는 작업을 한다면 static 메서드로 정의한다
    (메서드 호출시간이 짧아져서 성능이 향상된다)
class Math2{
	int a,b;
    int add() {return a+b;}//인스턴스 메서드
    static int add(int x,int y) {return x+y;}//static method
}

오버로딩

  • 한 클래스내에 같은이름의 메서드를 여러번 정의하는것
  • 매개변수 개수/타입이 다른경우 사용할 수 있음
long add(int x, int y) {return a+b;}
long add(int x, long y){return a+b;}
add(1,2);//compile error! 무엇을 호출할지 모르겠음!
  • 위의 경우는 컴파일에러가 발생한다
  • 같은기능을 하지만 매개변수의 개수나 타입이 다르다고 여러번 정의해야하면 부담이 갈것이다. 기능이 같으니 수정할때의 포인트가 늘어날것이다

가변인자

public printStream printf(String format, Object ...args){..}
  • 타입...변수명 으로 사용한다
  • 가변인자는 가장 마지막에 선언해야한다
  • 가변인자는 내부적으로 배열을 이용한다

가변인자 vs 배열

  • 배열로하면 인자생략이 불가능

주의사항

static String concatenate(String delim, String... args)
static String concatenate(String... args)

concatenate("-", {"100","200"});//compile error
concatenate("-", "100","200");//ok
concatenate("-", new String[]{"100","200"});//ok

첫번째 concatenate는 compile error가 나지만 그 밑에줄은 컴파일에러가 나지 않는다. 이둘은 무슨차이가 있을까?

  • 문법에서 선언과 동시에 초기화하는 경우엔 new String[]을 생략하게 해줌 초기화 문법을 할당 문법에 쓰려 해서 안되는것임

  • str은 주소이기 때문에 16번째줄과 같은 대입이 불가능하다
    따라서 {}로 묶어준다고 값이 전달되지 않는다

  • 첫번째 concatenate는 값을 전달하고 있고 두번째는 주소를 전달하고 있다

String= " " vs new String

  • String 도 참조형은 맞지만 String은 변경이 불가능하다
  • 아래의 코드에서 몇개의 객체가 만들어질까?
public static void main(String [] args) {
    String name1 = new String("nroo");//heap에 개별메모리
    String name2 = "nroo";// String Constant Pool에 만들어진 객체
    String name3 = "nroo";// String Constant Pool에 만들어진 객체
    name1==name2;//false
    name2==name3;//true
  } 
  • 두개의 객체가 만들어진다
  • String의 연산이 이루어지면 값이 바뀌는것이 아니다 새로운 객체를 계속만들어내는것이다 그래서 비효율적이다
  • String 리터럴로 생성하면 해당 String값은 Heap영역내의 String Constant Pool에 저장되어 재사용된다
  • 하지만 new String으로 생성하면 같은 내용이여도 각각 Heap영역을 차지하게 된다

인스턴스가 생성되는 단계

Card c = new Card();
  1. new에 의해서 heap에 인스턴스 생성
  2. 생성자호출
  3. c에 인스턴스의 주소값 저장

생성자 호출

  • 생성자의 이름대신 this사용
  • this는 instance method만 사용가능
  • 첫줄에서만 다른 클래스의 생성자 호출 가능

변수의 초기화

  • 지역변수를 사용전에 초기화하지 않으면 error

멤버변수의 초기화

  1. 명시적초기화
  2. 생성자
  3. 초기화블럭
  • 클래스 초기화블럭, 인스턴스 초기화 블럭
  • 인스턴스 초기화 블럭에는 모든 생성자에서 공통으로 수행되어야하는 부분에 대해 사용한다
Car(){
	count++;
    serialNo = count;
    color = "white";
}
Car(String color){
	count++;
    serialNo = count;
    this.color = color;
}
  • 코드중복제거
class BlockTest{
	static{
    	System.out.println("static초기화블럭");
    }
    {
    	System.out.println("인스턴스초기화블럭");
    }
    BlockTest(){
    	System.out.println("생성자");	
    }
}
BlockTest b1 = new BlockTest();
BlockTest b2 = new BlockTest();

출력결과는
static초기화블럭
인스턴스초기화블럭
생성자
인스턴스초기화블럭
생성자

멤버변수의 초기화 시점

클래스변수
기본값 -> 명시적초기화 -> 클래스초기화 블럭
인스턴스변수
기본값 -> 명시적초기화 -> 인스턴스초기화 블럭 -> 생성자

  • 근데 여기서 클래스변수는 클래스가 메모리에 처음으로 로딩될때 초기화가 시작되고, 인스턴스 변수는 인스턴스가 생성되었을때 초기화가 시작된다

https://ict-nroo.tistory.com/18

profile
안녕하세요!

0개의 댓글