변수 - 클래스변수, 인스턴스변수, 지역변수
class Variables { // 클래스 영역
int iv; // instance valuable
static int cv; // class valuable, static valuable
void method() { // 메서드 영역
int lv = 0; // local valuable
}
}
+) cv는 클래스가 메모리에 로딩될 때 생성되어 종료될 때까지 유지, public을 앞에 붙이면 같은 프로그램 내에서 어디서나 접근할 수 있는 전역변수의 성격을 가진다.
인스턴스 변수는 인스턴스가 생성될 때마다 생성되므로
인스턴스마다 각기 다른 값을 유지할 수 있다.
클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 갖는다.
특정 작업을 수행하는 일련의 문장들을 작업단위로 묶은 것.
이후의 세세한건 알고 잇어서... 궁금하시면 자바의 정석을 드셔보세요
메서드 영역
힙
호출스택
- 메서드 호출 -> 필요한만큼 메모리를 스택에 할당
- 수행을 마치면 사용한 메모리 반환 -> 스택에서 제거
- 맨 위의 메서드 = 현재 실행중인 메서드
- 그 아래에 있는 메서드 = 바로 위의 메서드 호출한 메서드
메서드 호출 시 매개변수로 지정한 값을 메서드의 매개변수에 복사
해서 넘겨준다.
기본형
일 때는 기본형 값 자체
가 복사
참조형
이면 인스턴스의 주소
가 복사
기본형 매개변수 - 변수의 값을 읽기만
참조형 매개변수 - 변수의 값을 읽고, 쓰기(변경)
외요?
인텔리제이 꺼라. 그림판 켜라,..
class Data {
int x;
}
class PrimitiveParamEx {
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
System.out.println("main() : x = " d.x);
change(d.x);
System.out.println("After cahnge(d.x)");
System.out.println("main() : x = " d.x);
}
static void change(int x) {
x = 1000;
System.out.pringln("change() : x = " + x);
}
}
change 메서드는 수행하고나서 stack에서 제거되고, main이 바라보고 있는 변수는 여전히 10으로 남아있기 때문이다.
이번엔 참조변수를 보자
class Data {
int x;
}
class PrimitiveParamEx {
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
System.out.println("main() : x = " d.x);
change(d);
System.out.println("After cahnge(d.x)");
System.out.println("main() : x = " d.x);
}
static void change(Data d) {
d.x = 1000;
System.out.pringln("change() : x = " + d.x);
}
}
이번엔 주소를 넘겨줬다!!
그러니 객체를 다룰 수 있도록 리모콘을 넘겨준거니 값을 조작할수 있게 되었다.
int 배열도 있는데 얘도 참조변수니까 똑같이 돌아간다고 생각하면 된다~~~ 어우 힘들어
class ReferenceParamEx2{
int[] x = {10};
System.out.println("main() : x = " + x[0]);
change(x);
System.out.println("After change(x)");
System.out.println("main() : x = " + x[0]);
static void change(int[] x) {
x[0] = 1000;
System.out.println("change() : x = " + x[0]);
}
}
실행결과
main() : x = 10
change() : x = 1000
After change(x)
main() : x = 1000
그림판 꺼라...
메서드 앞에 static 붙으면 클래스메서드~
이렇게 클래스 변수를 생성하면, 객체를 생성하지 않고 클래스이름.메서드이름
요런 형식으로 호출이 가능하다. 인스턴스 메서드는 당연히 객체를 생성해야 호출이 가능하고여
그럼 언제 static을 붙여야할까?
인스턴스와 관계없는 메서드를 정의할 때!
멤버변수 중 모든 인스턴스에 공통으로 사용하는 것
모든 인스턴스에서 같은 값이 유지되어야하는 변수
는 static을 붙여 클래스변수로 정의해주자.클래스 변수(static 변수)는 인스턴스 생성안해도 사용 가능
클래스 변수는 인스턴스 변수를 사용할 수 없다.
메서드 내에서 iv를 사용하지 않는다면, static을 붙이는걸 고려하자
클래스 멤버변수 중 모든 인스턴스에
공통된 값
을 유지해야하는 것이 있다면, static을 붙여보자.
메서드 중 인스턴스 변수나 인스턴스 메서드를 사용하지 않는다면, 메서드에 static을 붙일 것을 고려해보자~
Q. static 메서드는 static 메서드 호출 가능?
A. 예. 언제 어디서든 가넝
Q. static메서드는 인스턴스 변수, 메서드 사용 가능?
A. 둘다 안돼 숭이야
Q. 왜여?
A. static메서드 호출 시 객체(iv묶음)가 없을 수도 없어서요
와 드디어 다음챕터다 쒸엣~~~ 쏴리질러
한 클래스 내에 같은 이름의 메서드를 여러 개 정의한다.
엥? 구분은 어덕하라고요
오버로딩의 조건은 다음과 같다.
메서드 이름이 같다.
근데 여기서? 매개변수 개수 혹은 타입이 달라야됨
반환값은 아무런 영향을 못준다,,
어? 왜 벌써.. ㅋㅋ
인스턴스가 생성될 때 호출되는
인스턴스 초기화 메서드
iv 초기화 + 객체 생성으로 이해하면 된다.
클래스 내에 선언되어 구조도 메서드와 유사한데, 리턴 값이 없다
조건은
class Card {// class 이름
Card() {} // 기본생성자
Card(String k, int num) {
}
}
오버로딩한 생성자 이름들이 다 class 이름과 같다~
Card c = new Card();
백준에서도, 연습문제에서도 부루룩박박 대충 코드 짰는데, 사실 인스턴스를 생성하기 위해서는 생성자는 꼭 클래스당 하나 이상
있어야한다
저는 그딴거 만든적 없는데요? -> 컴파일러가 개짱천재라 기본생성자를 자동으로 넣어준거다.
클래스명() {}
의 구조를 갖고 있다. 매개변수도 없고, 내용도 없다.
// ConstructorTest.java
class Data1 {
int value; // 생성자가 없다.
}
class Data2 {
int value;
Data2(int x) { // 매개변수를 지닌 생성자.
value = x;
}
}
class ConstructorTest {
public static void main(String[] args) {
Data d1 = new Data1(); // 얜 돼요
Data d2 = new Data2(); // 얘 컴파일 오류나요
}
}
왜 Data1은 인스턴스가 생성되고, Data2는 컴파일 오류가 날까?
말했듯, 클래스 안에 생성자가 하나도 없으면, 기본생성자가 자동으로 생성된다
Data1에는 생성자가 하나도 없고, Data2에는 매개변수를 지닌 생성자가 하나 있다.
Data1 -> 없으니까 기본생성자 자동생성
Data2 -> 매개변수 지닌 생성자가 있어서 기본생성자 안생김.
엥? 매개변수를 지닌 생성자가 있다며!! 그럼 하나 있는거 아님?
그럴려면 Data2()로 매개변수가 없게 넘기는게 아니라, Data2(int변수)를 넣어 생성자를 사용
해주면 된다
매개변수가 있는 생성자에 대해 더 알아보자
인스턴스 초기화 작업 시, 인스턴스마다 각 다른 값으로 초기화해야하는 경우가 있다. 매개변수를 사용해 지리게 초기화해주자.
class Car {
String color;
String gearType;
int door;
Car() {}
Car(String c, String g, int d) {
color = c;
gearType = g;
door = d;
}
}
Car라는 클래스에서 iv가 세 개 선언되고, 기본생성자 Car()과 매개변수가 있는 생성자 Car(String c, String g, int d)가 선언되었다
매개변가 있는 생성자는 iv를 이용해 인스턴스를 초기화하며, 기본생성자만 있었다면 생성 후에 따로 초기화를 해줘야한다.
Car c = new Car();
c.color = "white";
c.gearType = "auto";
c.door = 4;
위의 코드를 이렇게 간결하게 초기화 쌉가넝~
Car c = new Car("white", "auto", 4);
class Car {
String color;
String gearType;
int door;
Car() {} // 기본생성자
Car(String c, String g, int d) { // 매개변수가 있는 생성자
color = c;
gearType = g;
door = d;
}
}
class CarTest{
public static void main(String[] args) {
Car c1 = new Car(); // 기본생성자를 이용해 인스턴스 생성
c1.color = "white";
c1.gearType = "auto";
c1.door = 4;
Car c2 = new Car("white", "auto", 4); // 매개변수가 있는 생성자로 인스턴스 생성 -> 바로 초기화댐 굿
}
}
c1, c2의 요소를 출력해보면 둘 다 같은 결과를 뱉는다.
🚨🚨 this()와 this는 완전 딴얘기입니당 관련 없음
생성자 이름으로
클래스 대신 this
사용
한 생성자 내부에서 다른 생성자 호출 시,첫 줄
에서만 호출 가능
아래의 코드는 오류가 있따
Car(String color) {
door = 5;
Car(color, "auto", 4);
}
예시를 좀 더 들어보자
class Car {
String color;
String gearType;
int door;
Car() {
this("white", "auto", 4); // 첫줄에서 Car(String color, String gearType, int door) 호출
}
Car(String color) { // 첫줄에서 Car(String color, String gearType, int door) 호출
this(color, "auto", 4);
}
Car(String color, String gearType, int door) {
this.color = "white";
this.gearType = "auto";
this.door = 4;
}
}
class CarTest {
public static void main(String[] args) {
Car c1 = new Car();
Car c2 = new Car("blue");
}
}
출력 해보면
c1은 흰, 오토, 4
c2는 파랑, 오토, 4
Car(String color, String gearType, int door) 생성자 클래스를 호출해 초기화한 코드인데 엥, 위에선 this.color 아니고 걍 color = 이런식으로 했잔아요
원래는 this.color가 맞는데, 같은 클래스 안이라 this.를 생략한거당~~
그래서 생성자 this() 말고 this는 머임??
this는
참조변수
. 인스턴스 자신을 가리킨다. 인스턴스 메서드(생성자 포함)에서 사용 가능하며, lv와 iv를 구별하기 위해 사용한다.
즈엉리
this
: 선언하지 않아도 사용 가능하며, 인스턴스 자신을 가리키는 참조변수. 인스턴스의 주소가 저장되어 있고, 모든 인스턴스메서드에 lv로 숨겨진 채로 존재.
this(), this(매개변수)
: 생성자. 같은 클래스 안에서 다른 생성자를 호출할 때 사용한다.
Car(Car c) {
color = c.color;
gearType = c.gearType;
door = c.door;
}
Car 클래스의 참조변수 (c)를 매개변수로 선언한 생성자
Car 인스턴스 변수인 color, gearType, door의 값을 인스턴스 자신으로 복사! 종합된 예시를 보자
class Car{
String color;
String gearType;
int door;
Car() {
this("white", "auto", 4);
}
Car(Car c) { // 인스턴스 복사를 위한 생성자
color = c.color;
gearType = c.gearType;
door = c.door;
}
/*
위의 코드는 이렇게 고쳐 재사용하는게 더 바람직..
Car(Car c) {
this(c.color, c.gearType, c.door);
}
*/
Car(String color, String gearType, int door) {
this.color = color;
this.gearType = geraType;
this.door = door;
}
}
class CarTest3 {
public static void main(Strint[] args) {
Car c1 = new Car();
Car c2 = new Car(c1) // c1의 복사본 c2 생성 Car(Car c) 생성자로 들어감
System.out.println("c1의 요소들 " + c1.color + " " + c1.gearType + " " + c1.door); // c1의 요소들 white, auto, 4
System.out.println("c2의 요소들 " + c2.color + " " + c2.gearType + " " + c2.door); // c2의 요소들 white, auto, 4
c1.door = 100;
System.out.println("c1.door=100 수행 후");
System.out.println("c1의 요소들 " + c1.color + " " + c1.gearType + " " + c1.door); // c1의 요소들 white, auto, 100
System.out.println("c2의 요소들 " + c2.color + " " + c2.gearType + " " + c2.door); // c2의 요소들 white, auto, 4
}
}
인스턴스 c2는 c1을 복사해 생성한 것이라 같은 상태
를 갖는다.
하지만 서로 독립적으로 메모리 공간에 존재하는 별도의 인스턴스
이므로, c1의 값이 변경되어도 c2는 영향을 받지 않는다.
인스턴스 생성 시 유의할 점
1. 클래스 - 어떤 클래스의 인스턴스를 생성할 것인가?
2. 생성자 - 선택한 클래스의 어떤 생성자로 인스턴스를 생성할 것인가?