자바의 신 8장

sjhello·2020년 11월 8일
0

참조 자료형

기본 자료형을 제외한 나머지 자료형을 모두 참조 자료형이라고 하며 new를 사용하여 값을 할당한다
String은 참조 자료형이면서 new를 사용하지 않고도 객체를 생성할 수 있다

생성자

생성자는 객체를 만들기 위해 존재하는데, 특징으로는 리턴 타입이 없으며 클래스의 이름과 동일한 것이 특징이다

기본 생성자

클래스를 만들게 되면 기본으로 만들어지는 생성자가 있는데, 이것이 기본 생성자이다

public class Foo {
    public Foo() {}
	...
}

생성자를 이렇게 생각하면 더 좋을 것 같다.
똑같은 마티즈를 사는데..
아무런 옵션없이 기본 옵션만 붙어있는 마티즈를 구입 할 수도 있는거고(기본 생성자 사용)
더 좋은 트렁크의 마티즈를 구입 할 수도 있는거고..(다른 생성자 사용)

public class Matiz {
    String trunk = "기본 트렁크";

    public Matiz(){
        System.out.println("트렁크: " + trunk);
    }
    public Matiz(String trunk) {
        this.trunk = trunk;
        System.out.println("트렁크: " + trunk);
    }

    public static void main(String[] args) {
        Matiz matiz = new Matiz();        // 기본 옵션 마티즈
        Matiz matiz2 = new Matiz("더 좋은 트렁크");     // 트렁크가 더 좋은 마티즈
    }
}

this

객체에서 사용하는 인스턴스 변수와 매개변수의 이름이 같을 때 구분 짓기 위해 사용하는 예약어

public class Foo {
    int fooNumber;
    String fooName;

    public void setFooNumber(int fooNumber) {
        this.fooNumber = fooNumber;    // 매개변수와 인스턴스 변수의 이름이 같다
    }

    public String getFooName() {
        return this.fooName;
    }
}

오버로딩(Overloading)

생성자 오버로딩과 메서드 오버로딩이 있다
오버로딩은 메서드(생성자)의 이름이 같고 매개변수의 타입이 다르거나 매개변수의 갯수, 순서가 다르다면 다른 매서드(생성자)로 인식하게 해주는 것

생성자 오버로딩

public class Foo {
    int fooNumber;
    String fooName = "foofoo";

    public Foo() {}
    public Foo(String name) {}

...
}

메서드 오버로딩

public class MethodVarargs {
    public static void main(String[] args) {
        MethodVarargs mv = new MethodVarargs();
        int number = 3;
        String name = "name";
        mv.varArgs(name, number);
    }

    public void varArgs(String name, int...number) {
        float [] numberss = new float[3];
        System.out.println("number = " + number);
    }

    public void varArgs(int[] number, String name) {}

    public void varArgs(int [] number) {
        System.out.println("number = " + number);
    }
}

메서드(Method)

하나의 객체는 상태와 역할(행동)을 갖게 되는데 여기서 상태는 필드
역할(행동)은 메서드에 해당된다

메서드 구조

public class Foo {
	int fooNumber;
	String fooName;

	public void setFooNumber(int fooNumber) {    // 선언부
		this.fooNumber = fooNumber;    // 구현부
  }
}
  • 선언부: 접근제어자 반환타입 메소드이름(매개변수 목록) 의 구조로 이루어짐
    • 접근제어자: public
    • 반환타입: void
    • 메서드 이름: setFooNumber
    • 매개변수 목록: int fooNumber
  • 구현부: 메서드가 실행할 동작(명령)

메서드 종료 조건

  • 모든 문장종료

  • return

    • 반환 타입에 void가 아닌 자료형(기본자료형과 참조 자료형)을 쓰면 반드시 return 예약어를 사용하여 한가지 타입의 값을 전달할 수 있으며 return문이 실행되면 메서드가 종료된다

      public class Foo {
      	int fooNumber;
      	String fooName = "foofoo";
      
        public static void main(String [] args) {
          Foo foo = new Foo();
          String fooName = foo.getFooName();    // getFooName() 호출
          System.out.println(fooName);    // foofoo
        }
      
      	public void setFooNumber(int fooNumber) {
      		this.fooNumber = fooNumber;   
        }
      
        public String getFooName() {
          return this.fooName;    // return문을 만나게 되어 메서드 종료
        }
      }
    • 반환 타입이 void인 형태의 메서드에서 return문을 사용하면 return문이 있는 위치에서 즉시 그 메서드를 종료 시킨다

      public class Foo {
      	int fooNumber = 12;
      	String fooName;
      
        public static void main(String [] args) {
          Foo foo = new Foo();
          foo.setFooNumber(10);
          // 매개변수로 10을 보냈지만 return을 만나서 초기화 부분은 실행 안됨
          System.out.println(foo.fooNumber);
        }
      
      	public void setFooNumber(int fooNumber) {
          return;    // return문을 만나 메서드 강제 종료 return문 아래 명령은 실행되지 않음
      		this.fooNumber = fooNumber;   // Unreachable statement
        }
      
        public String getFooName() {
          return this.fooName;
        }
      }

      코드 실행 시 Unreachable statement 컴파일 에러가 발생한다

  • 예외(Exception)

static

앞서 공통의 값이 필요할때는 static을 사용하자 에서 static을 간략하게 나마 공부했다

다시 한번 static의 특징에 대해 정리하자면

  • static 키워드가 붙은 메서드나 변수는 객체를 생성하지 않고 호출 할 수 있다
  • 웬만해서는 변하지 않는 값, 여러 곳에서 사용하는 설정 정보를 저장할 때 주로 사용 된다
  • static 키워드를 남발하면 시스템에 속도 저하 문제가 발생 할 수 있다
  • 객체가 생성되기 전에 먼저 메모리에 올라가며 프로그램 종료시점에 메모리에서 해제된다

static 메서드와 일반 메서드의 차이

static의 특징에서 알 수 있듯이 static이 붙은 메서드는 객체를 생성하지 않고 바로 호출 할 수으며 일반 메서드는 객체를 생성한 후에 호출 할 수 있는 차이점이 있다

또한 static 메서드에서는 인스턴스 변수가 아닌 클래스 변수만 사용할 수 있다

public class StaticNonStatic {
    static String name;  // 클래수 변수
    String name2;  // 인스턴스 변수

    public static void main(String[] args) {
        getName();
    }

    public static void getName() {
				// Non-static field 'name2' cannot be referenced from a static context
        System.out.println(name2);  
    }

		public void instanceGetName() {
        System.out.println(name2);
        System.out.println(name);
    }
}

static 블록

  • static 블록은 객체가 생성되기 전에 한 번만 호출되며 호출이 한번 되면 다시 한번 호출 할 수 없다
  • static 블록의 선언 위치는 클래스 내부에서 선언해야 하며 메서드와 생성자 내부에서는 선언 할 수 없다
  • static 블록은 여러개 선언 할 수 있으며 선언된 순서대로 호출 된다
  • static 블록에서 사용되는 변수는 static 키워드가 붙은 변수들만 사용할 수 있다(인스턴스 변수 사용불가)
public class StaticBlock {
    static String staticName = "staticVariable";  // static 블록에서 사용가능
    String instanceName = "instanceVariable";  // static 블록에서 사용 불가능

    static {
        System.out.println("first static block");
    }

    static {
        System.out.println("second static block");
    }

    public StaticBlock() {
        System.out.println("StaticBlock 기본 생성자");
    }

    public static void main(String[] args) {
        StaticBlock block = new StaticBlock();
    }
}
// 실행결과
first static block
second static block
StaticBlock 기본 생성자

객체가 생성되면 기본 생성자가 먼저 실행이 되지만 static 블록은 객체 생성 전에 호출 된다

값을 전달하는 pass by value(기본 자료형), 참조 자료형의 값을 변화시키는 pass by reference(참조 자료형)

pass by value

  • 기본 자료형은 호출한 매서드의 구현부 안에서 값을 변경해도 값이 변하지 않는다
  • 값만 전달한다 어떠한 변수를 다른 메소드로 넘길때 원래의 값은 그대로 두고 값만을 그대로 전달한다
public class CallbyValue {
    public static void main(String[] args) {
        CallbyValue cbv = new CallbyValue();

        String name = "name";
        int age = 12;

        System.out.println("passByValue 호출 전");
        System.out.println("name = " + name);
        System.out.println("age = " + age);

        cbv.passByValue(name, age);

        System.out.println("passByValue 호출 후");
        System.out.println("name = " + name);
        System.out.println("age = " + age);
    }

    public void passByValue (String name, int age) {
        name = "name!!!";
        age = 20;

        System.out.println("in passByValue");
        System.out.println("name = " + name);
        System.out.println("age = " + age);
    }
}
/// output - passByValue
passByValue 호출 전
name = name
age = 12
in passByValue
name = name!!!
age = 20
passByValue 호출 후
name = name
age = 12

String을 기본 자료형처럼 선언, 초기화 해서 매개변수로 보냈는데 왜 값이 변하지 않은걸까?

public void passByValue (String name, int age) {
    name = "name!!!";
    age = 20;

    System.out.println("in passByValue");
    System.out.println("name = " + name);
    System.out.println("age = " + age);
}

passByValue에서 name의 할당 부분을 잘 보면

name = "name!!"

이런식으로 되어있는데 String은 따옴표로 값을 할당 하더라도 실제로 동작하는 방식은

String name = new String("name!!")

이 된다 따라서 매개변수로 넘어온 name을 재할당 하더라도 다른 객체가 되기 때문에 main 함수 안에서의 name과는 다른 레퍼런스를 가진다

pass by reference

참조 자료형에서 사용하는 데이터 전달 방식 매개변수로 받은 참조 자료형의 객체를 호출된 메서드에서 변경이 가능하다

public class CallbyReference {
    public static void main(String[] args) {
        Member member = new Member();
        member.age = 12;
        member.name = "name";

        System.out.println("passByReference 호출 전");
        System.out.println("member.age = " + member.age);
        System.out.println("member.name = " + member.name);

        CallbyReference cbr = new CallbyReference();
        cbr.passByReference(member);

        System.out.println("passByReference 호출 후");
        System.out.println("member.age = " + member.age);
        System.out.println("member.name = " + member.name);
    }

    public void passByReference(Member member) {
        member.age = 20;
        member.name = "name!!!";
        System.out.println("member.age = " + member.age);
        System.out.println("member.name = " + member.name);
    }
}
/// output - passByReference
passByReference 호출 전
member.age = 12
member.name = name
member.age = 20
member.name = name!!!
passByReference 호출 후
member.age = 20
member.name = name!!!

가변인수를 이용한 메서드

가변인수란? 필요에 따라 매개변수를 여러개 받거나, 하나만 받게 할 수 있는 것

가변인수가 없을때...

public static void main(String[] args) {
    MethodVarargs mv = new MethodVarargs();
    int [] number = {1,2,3,4,5};
    String name = "name";
    mv.varArgs(name, number);
}

// int를 받아야 하긴 하지만 하나만 받을지 n개이상을 받을지 모르는 상황
public void varArgs(String name, int[] number) {
    ...
}

비록 int 매개변수를 하나만 쓸지라도 배열로 선언해야하는 단점이 있음

가변인수를 사용할때

public static void main(String[] args) {
    MethodVarargs mv = new MethodVarargs();
    int [] number = {1,2,3,4,5};
		// int number = 3;
    String name = "name";
    mv.varArgs(name, number);
}

public void varArgs(String name, int...number) {
    ...
}

배열로 선언하지 않고도 가변인수를 사용하여 일반 변수도 매개변수로 사용 가능하다

사실 가변인수는 자바 컴파일러가 코드를 읽어 인자값으로 ... 이라는 것이 있으면 이것을 배열로 바꾸어 준다 바이트 코드를 보면 알 수 있듯이 varArgs()의 인자값으로 String과 int...number가 있는 것을 확인 할 수 있다

0개의 댓글