기본 자료형을 제외한 나머지 자료형을 모두 참조 자료형이라고 하며 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("더 좋은 트렁크"); // 트렁크가 더 좋은 마티즈
}
}
객체에서 사용하는 인스턴스 변수와 매개변수의 이름이 같을 때 구분 짓기 위해 사용하는 예약어
public class Foo {
int fooNumber;
String fooName;
public void setFooNumber(int fooNumber) {
this.fooNumber = fooNumber; // 매개변수와 인스턴스 변수의 이름이 같다
}
public String getFooName() {
return this.fooName;
}
}
생성자 오버로딩과 메서드 오버로딩이 있다
오버로딩은 메서드(생성자)의 이름이 같고 매개변수의 타입이 다르거나 매개변수의 갯수, 순서가 다르다면 다른 매서드(생성자)로 인식하게 해주는 것
생성자 오버로딩
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);
}
}
하나의 객체는 상태와 역할(행동)을 갖게 되는데 여기서 상태는 필드
역할(행동)은 메서드에 해당된다
public class Foo {
int fooNumber;
String fooName;
public void setFooNumber(int fooNumber) { // 선언부
this.fooNumber = 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 메서드에서는 인스턴스 변수가 아닌 클래스 변수만 사용할 수 있다
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);
}
}
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 블록은 객체 생성 전에 호출 된다
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
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과는 다른 레퍼런스를 가진다
참조 자료형에서 사용하는 데이터 전달 방식 매개변수로 받은 참조 자료형의 객체를 호출된 메서드에서 변경이 가능하다
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가 있는 것을 확인 할 수 있다