- 자신의 메모리를 가리킨다.
- 생성자에서 다른 생성자를 호출한다.
- 자신의 주소를 반환한다. (이건 자주 쓰진 않음)
package thisex;
class BirthDay{
int day;
int month;
int year;
public void setYear(int year) {
this.year = year;
// 멤버변수 지역번수
// 위 코드에서 this를 생략하게 되면 year은 파라미터로 사용되는 yrar로 인식 된다.
}
// public void setYear(int y) {
// year = y; <<this 안쓸거면 이렇게 변수명을 다르게 써주면 되긴 됨
// }
public void printThis() {
System.out.println(this); //this를 출력하라는 하나의 메소드
}
}
public class ThisExample {
public static void main(String[] args) {
BirthDay b1 = new BirthDay();
BirthDay b2 = new BirthDay();
System.out.println(b1);
b1.printThis(); //BirthDay class에서 printThis라고
System.out.println(b2);
b2.printThis(); //정의한 메소드 가져다 쓴거
}
}
위 출력과 같이 코드는 똑같이 다 this지만 매번 가리키는 것은 그때의 instence의 주소값이라는 것을 확인할 수 있다.
class Person{
String name;
int age;
public Person() {
this("이름없음", 1);
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class CallAnotherConst {
public static void main(String[] args) {
Person p1 = new Person();
System.out.println(p1.name);
}
}
p1 변수에 Person 객체를 default 생성자로 호출했고 default 생성자에서는 name과 age를 사용한 생성자를 호출하여 name이 "이름없음"으로 출력된다.
public Person() { int i = 0; name = "test" this("이름없음", 1); }
위처럼 constructor에서 다른 constructor를 호출하기 위해 this를 쓸 때에는 this 앞에 문장(statement)이 들어갈 수 없다.
왜냐하면 이 객체가 생성되기 위해서 다른 생성자를 호출했다는 것은 이 객체가 아직 다 제대로 생성이 안됐다는거고 그러기 위해서 할 일이 마무리되지 않았기 때문에 this 앞에 그 어떤 statement도 오는것이 허락되 않는 것이다.
package thisex;
class Person{
String name;
int age;
public Person(){
this("이름없음", 1); // Person(String, int)
}
public Person(String name, int age){
this.name = name;
this.age = age;
}
public Person returnSelf() {
return this;
}
}
public class CallAnotherConst {
public static void main(String[] args) {
Person p1 = new Person();
System.out.println(p1.name);
System.out.println(p1.returnSelf());
}
}
자주 쓰이지 않는다.
학생이 버스나 지하철을 타는 상황을 프로그래밍하기 위해서는 클래스가 학생, 버스, 지하철이 필요하다.
학생의 속성은 이름, 가진 돈, 학년(해당 상황에 필요한 것은 아님)으로 만들었고, 버스를 타거나 지하철을 타면 가진 돈이 줄어드는 메서드로 만들었다.
public class Student {
String studentName;
int grade;
int money;
public Student(String studentName, int money) {
this.studentName = studentName;
this.money = money;
}
public void takeBus(Bus bus) {
bus.take(1000);
money -= 1000;
}
public void takeSubway(Subway subway) {
subway.take(1500);
money -= 1500;
}
public void showInfo() {
System.out.println(studentName + "님의 남은 돈은 " + money + "원 입니다.");
}
}
버스의 속성
버스 번호, 승객 수, 수입으로 만들었고, 탑승하는 경우에 승객과 수입이 증가하는 메서드를 만들었다.
public class Bus {
int busNumber;
int passengerCount;
int money;
public Bus(int busNumber) {
this.busNumber = busNumber;
}
public void take(int money) {
this.money += money;
passengerCount++;
}
public void showInfo() {
System.out.println("버스 " + busNumber + "번의 승객은 " + passengerCount + "명이고, 수입은 " + money +"입니다.");
}
}
지하철의 속성은 노선 번호, 승객 수, 수입으로 만들었고, 버스와 마찬가지로 탑승하는 경우에 승객과 수입이 증가하는 메서드를 만들었다.
public class Subway {
int lineNumber;
int passengerCount;
int money;
public Subway(int lineNumber) {
this.lineNumber = lineNumber;
}
public void take(int money) {
this.money += money;
passengerCount++;
}
public void showInfo() {
System.out.println("지하철 " + lineNumber + "호선의 승객은 " + passengerCount + "명이고, 수입은 " + money +"입니다.");
}
}
2명이 버스와 지하철에 각각 한명씩 탄다고 생각하고
2개의 Student 생성자를 만들어 넣어주었다.
또 타게될 100번버스, 2호선 지하철 각각 생성자를 만들었다.
public class TakeTrans {
public static void main(String[] args) {
Student james = new Student("James", 5000);
Student tomas = new Student("Tomes", 10000);
Bus bus100 = new Bus(100);
james.takeBus(bus100);
james.showInfo();
bus100.showInfo();
Subway subway2 = new Subway(2);
tomas.takeSubway(subway2);
tomas.showInfo();
subway2.showInfo();
}
}
take는 추상메소드로 두고 taxi를 추가하고 탈 것들을 Trans로 묶어 Student와 Trans가 협업을 할 수 있게끔 코드를 변환해보자.
모르겠음 ㅠㅡㅠ 후에 다시 할 예정...
뒤에서 배우는 상속에서 extend를 쓰면 어찌저찌 될 것 같은데...
안쓰고 어떻게 하지...
⇒ 정적 멤버는 클래스에 고정된 멤버 ⇒ 객체를 생성하지 않고 사용할 수 있는 필드와 메소드
- 이들을 각각 정적 필드, 정적 메소드라고 부름
- 정적 멤버는 객체(인스턴스)에 속해있지 않음 ⇒ 클래스에 속해있음 ⇒ 클래스 멤버라고도 부름
- static 변수는 자료형 앞에 static 예약어를 써서 사용하며, 여러 개의 인스턴스가 같은 메모리의 값을 공유하기 위해 사용
static 변수는 heap 메모리가 아닌 다른 영역(데이터 영역 메모리)에 저장되고, 프로그램이 메모리에 적재(load)될 때 값이 할당된다.
(인스턴스는 new 키워드로 객체가 생성될 때 heap 메모레어 할당되고, 객체가 소멸되면 사라진다.)
따라서 인스턴스의 생성과 관계없이 클래스 이름으로 직접 참조함
static 변수는 클래스 변수라고도 한다. (멤버변수는 인스턴스 변수라고도 한다.)
Student class
package staticex;
public class Student {
static int serialNum = 10000;
int studentID;
String studentName;
public Student() {
serialNum++;
studentID = serialNum;
} //ㄴ> 객체 생성 시 serailNum이 증가하고 그 값을 studentID에 대입
}
생성자가 생성됨에(학생수가 늘어남에) 따라 학번이 순차적으로 1씩 늘어나면서 배정되도록 하였다.
main class
package staticex;
public class StudentTest1 {
public static void main(String[] args) {
Student studentJ = new Student();
System.out.println("J학생의 학번은"+studentJ.studentID);
Student studentT = new Student();
System.out.println("T학생의 학번은"+studentT.studentID);
System.out.println("J학생의 학번은"+studentJ.studentID);
System.out.println("생성자가 추가되어도 학번은 다르고 instans값만 같다");
System.out.println("T학생의 instans값은"+studentT.serialNum);
System.out.println("J학생의 instans값은"+studentJ.serialNum);
}
}
T,J 학생이 학번은 각각 다르게 가져갔지만 instans값은 같은 것을 볼 수 있다.
그런데 위 코드는 아래와 같이 경고가 뜨는 것을 볼 수 있다.
경고문: The static field Student.serialNum should be accessed in a static way
serialNum이 static변수인데 왜 class이름으로 참조하지 않고 instance변수로 참조 했냐는 경고문이다.
package staticex;
public class StudentTest1 {
public static void main(String[] args) {
Student studentJ = new Student();
System.out.println("J학생의 학번은"+studentJ.studentID);
Student studentT = new Student();
System.out.println("T학생의 학번은"+studentT.studentID);
System.out.println("J학생의 학번은"+studentJ.studentID);
System.out.println("생성자가 추가되어도 학번은 다르고 instans값만 같다");
System.out.println("T학생의 instans값은"+Student.serialNum);
System.out.println("J학생의 instans값은"+Student.serialNum);
}
}
경고문에 따라 수정해도 같은 결과가 나오는 것을 볼 수 있다.
(어차피 serialNumber를 static으로 선언하면 모든 student instance에 대해 하나의 변수로 유지 되는데, 굳이 class로 호출하지 않고 하나의 instance를 통해 각각 호출하려고 할 필요가 없다.)
serialNumber를 static으로 선언하면 모든 student instance에 대해 하나의 변수로 유지 되고 이러한 변수를 class변수라 한다.
각 학생이 생성될 떄 마다 static 변수 값을 복사해 와서 하나 증가시킨 값을 생성된 인스턴스의 학번 변수에 저장해 줌
클래스 메서드라고도 함
메서드에 static 키워드를 사용하여 구현
주로 static 변수를 위한 기능 제공
static 메서드에서 인스턴스 변수를 사용할 수 없음
static 메서드도 인스턴스의 생성과 관계 없이 클래스 이름으로 직접 메서드 호출
Student class
package staticex;
public class Student {
static int serialNum = 10000;
int studentID;
String studentName;
public Student() {
serialNum++;
studentID = serialNum;
} //ㄴ> 객체 생성 시 serailNum이 증가하고 그 값을 studentID에 대입
public static int getSerialNum() {
int i = 10; // 지역변수
i++;
System.out.println(i);
studentName = "홍길동"; //멤버변수, 인스턴스 변수
//ㄴ> 생성되지도 않은 인스턴스 변수에 홍길동을 넣게 되는 꼴이라 오류남
return serialNum; // static 변수, 클래스 변수
}
}
StudentTest1 class
package staticex;
public class StudentTest1 {
public static void main(String[] args) {
System.out.println(Student.getSerialNum());
Student studentJ = new Student();
System.out.println(Student.getSerialNum());
Student studentT = new Student();
System.out.println(Student.getSerialNum());
}
}
Student.getSerialNum();
getSerialNum() << 이게 static 메서드
인스턴스의 변수의 경우 꼭 인스턴스가 먼저 생성 되어야 하므로 static 메서드에서는 생성이 불확실한 인스턴스 변수를 사용할 수 없음
선언 위치 = 함수 내부에 선언
사용 범위 = 함수 내부에서만 사용
메모리 = 스택
생성과 소멸 = 함수가 호출될 때 생성되고, 함수가 끝나면 소멸함
선언 위치 = 클래스 멤버 변수로 선언
사용 범위 = 클래스 내부에서 사용하고 private이 아니면 참조 변수로 다른 클래스에서 사용 가능
메모리 = 힙
생성과 소멸 = 인스턴스가 생성될 때 힙에 생성되고, 가비지 컬렉터가 메모리를 수거할 때 소멸됨
new할 때 사용 되던거! class 내부에서 class속성을 나타내는데 사용 했었음
선언 위치 = static 예약어를 사용하여 클래스 내부에 선언
사용 범위 = 클래스 내부에서 사용하고 private이 아니면 클래스 이름으로 다른 클래스에서 사용 가능
메모리 = 데이터 영역
생성과 소멸 = 프로그램이 처음 시작할 때 상수와 함께 데이터 영역에 생성되고 프로그램이 끝나고 메모리를 해제할 때 소멸됨 ( 따라서 너무 크게 만들면 로딩 커진다~)
class 이름으로 사용하던 애들
변수 유형 | 선언 위치 | 사용 범위 | 메모리 | 생성과 소멸 |
---|---|---|---|---|
지역 변수 (로컬 변수) | 함수 내부에 선언 | 함수 내부에서만 사용 | 스택 | 함수가 호출될 때 생성되고,함수가 끝나면 소멸함 |
멤버 변수 (인스턴스 변수) | 클래스 멤버 변수로 선언 | 클래스 내부에서 사용하고 private이 아니면 참조 변수로 다른 클래스에서 사용 가능 | 힙 | 인스턴스가 생성될 때 힙에 생성되고, 가비지 컬렉터가 메모리를 수거할 때 소멸됨 |
static 변수 (클래스 변수) | static 예약어를 사용하여 클래스 내부에 선언 | 클래스 내부에서 사용하고 private이 아니면 클래스 이름으로 다른 클래스에서 사용 가능 | 데이터 영역 | 프로그램이 처음 시작할 때 상수와 함께 데이터 영역에 생성되고 프로그램이 끝나고 메모리를 해제할 때 소멸됨 |
Company class
public class Company {
private static Company instance = new Company();
//ㄴ> Company 객체는 현재 클래스 내부에서 단 한 개만 존재함.
private Company(){}//외부에서 constructor 호출을 제한
public static Company getInstance() { //외부에서 instance 객체를 사용할 수 있게 함
if(instance == null) { //<< 매우 방어적인 코드
//null일리가 없지만 혹시 모르니 조치를 한번 더 취한거
instance = new Company();
}
return instance;
}
}
이처럼 Company instance가 함부로 바뀌거나 null이면 안되니 private으로 생성자를 만들고, 유일하게 사용하려는 instence기 때문에 static으로 선언한 후, get 메서드를 제공하여 객체를 사용할 수 있도록 만든다.
CompanyTest class
public class CompanyTest {
public static void main(String[] args) {
Company c1 = Company.getInstance();
Company c2 = new Company(); //error
}
}
main함수가 있는 다른 class에서 Company객체를 사용하고 싶다면 new 생성자가 아닌 getInstance() 메서드를 이용해야 사용할 수 있다.