우선, 클래스를 선언해보자.
// 클래스가 여러개일 경우, public 접근제한자는 파일이름과 같은 클래스에만 붙일 수 있다
public class Car{
}
이 클래스(설계도)를 이용하여 객체, 즉 인스턴스를 만들어보자!
// 클래스로부터 객체 생성 - car 클래스 변수가 Car객체를 참조한다
public class carExample{
public static void main(String[] args) {
Car car1 = new Car();
// 즉 new를 통해 힙에 Car객체를 만들고, 그 주소를 car변수에 할당한것
Car car2 = new Car();
// 서로 다른 Car객체를 car1과 car2가 참조하고 있는것이다. 서로 독립적임
}
}
자 이제 두가지 클래스를 만들었다. 클래스는 라이브러리(API)용이고 하나는 실행용이다.
실행클래스에선 프로그램을 실행하기위한 main() 메소드를 제공한다.
이렇게 용도가 다른 클래스들은 어떻게 이루어져 있을까?
String campany = "현대자동차";
int maxSpeed = 100;
이런식으로 현재 데이터를 저장 해준다. 만약 저장을 따로 하지 않는다면 기본 초기값이 할당된다.
기본타입은 0, 논리타입은 false, 참조타입은 null이 들어간다.
약간 변수 선언이랑 비슷함! 근데 변수라고는 절대 안부른다.
외부 CarExample 클래스에서 Car 클래스의 필드를 바꾸고자 할땐 어떻게 할까?
필드는 객체에 소속된 데이터이다. 객체가 존재해야 값도 바꿀 수 있으므로 우선 클래스로부터 객체를 생성 한 뒤 필드를 사용한다.
public class Car{
String company = "현대자동차";
int maxSpeed = 350;
}
public class CarExample{
public static void main(String[] args) {
Car mycar = new Car(); //새로운 Car 객체를 생성해 그 주소를 mycar에 할당
mycar.maxSpeed = 60; //이렇게 하면 현자동차는 그대로, 스피드는 60으로 변경된다
}
}
우선, Car 생성자를 다시한번 호출해보자
Car mycar = new Car("그랜저", "검정", 300); //3개의 매개값을 준다고 가정한다.
매개값을 받아야 하기 때문에 매개변수를 선언한다.
public class Car{
Car(String model, String color, int maxSpeed) {...}
}
반대로, Car 클래스가 다음과같이 선언되어있다면 Example클래스에선 반드시 세 매개값을 호출하는 객체를 만들어야한다. 위와같은 생성자가 존재하므로 기본생성자는 자동으로 호출되지 않는다. 따라서 Car mycar = new Car(); 과 같은 객체는 불가능하다!
필드와 생성자에 대해 알았으니, 필드초기화 이야기를 해보겠다.
필드 초기화 방법은 두가지가 존재한다.
1번은 필드 선언할때 값을 같이주면 되고, 2번에 대해 설명하자면
public class Korean{
//필드
String nation = "대한민국";
String name;
String ssn;
//생성자
public Korean(String name, String ssn){
this.name = name;
this.ssn = ssn;
}
}
이렇게 선언하고 KoreanExample로 실행하면 생성자로 인해 제공된 name과 ssn으로 초기화된다.
public class Car{
String company = "현차";
String color;
String model;
int maxSpeed;
//생성자
Car(){}
Car(String model){
this.model = model;
}
Car(String model, String color){
this.model = model;
this.color = color;
}
} // 이렇게 선언하고, CarExample에서 주어지는 매개변수에 따라 생성자가 다르게 호출된다
public class Car{
String company = "현차";
String color;
String model;
int maxSpeed;
//생성자
Car(){}
Car(String model){
this(model,color)
}
Car(String model, String color){
this.model = model;
this.color = color;
}
} //이런식으로 가장 긴 코드를 써주고, 나머지 생성자는 this안에 넣어 중복코드를 줄일 수 있다
이제 클래스의 구성멤버중 마지막인 메소드에 대해 알아보겠다.
[형식]
리턴타입 메소드이름 ([매개변수선언,...]) {메소드 실행블록}
// 메소드 선언
public class Calculator{
void powerOn() {
system.out.println("전원을 켭니다");
}
int plus(int x, int y){
int result = x+y;
return result;
}
}
//메소드 호출
public class CalculatorExample{
public static void main(String[] args) {
Calculator myCalc = new Calculator();
myCalc.powerOn();
int result1 = myCalc.plus(5,6);
system.out.println("result1: "+result1)
}
}
public class Computer {
int sum(int ...values){
int sum = 0;
for(int i=0; i<values.length;i++){
sum += values[i];
}
return sum;
}
}
public class Computer {
public static void main(String[] args) {
Computer myCom = new Computer();{
int[] values1 = {1,2,3};
int result1 = myCom.sum1(values);
}
int result2 = muCom.sum1(new int[] {1,2,3,4,5});
}
}
// 내부에서 호출
double avg(int x, int y) {
double sum = plus(x,y);
double result = sum/2;
}
void execute() {
double result = avg(7,10);
}
// 외부에서 호출
public class CalculatorExample{
public static void main(String[] args) {
Calculator myCalc = new Calculator();
myCalc.execute();
}
}
Calculator myCalc= new Calculator()→ myCalc.execute() → void execute() → double avg(int x, int y)
[정적 필드 예시]
public class Calculator{
Stirng color; // 계산기별로 색 다르니 그냥 스트링
static double pi = 3.14; // 파이는 모두 똑같으므로 static
}
[정적 메소드 예시]
public class Calculator{
String color;
void setColor(String color) { this.color = color; }
static int plus(int x, int y) { return x+y; }
}
// 위와같이 선언 되었다면,
double result1 = 10*10*Calculator.pi;
int result2 = Calculator.plus(10,5);
// 이렇게 사용 할 수 있다
// 또한 원칙적으로는 클래스.필드 or 클래스.메소드 라고 써야하나
// 객체참조 변수로도 접근은 가능하다. (추천x) (ex. myCalc.pi)
public class ClassName{
// 인스턴스 필드와 메소드
int field1;
void method1() {...}
// 정적필드와 메소드
static int field2;
static void method2() {...}
//정적메소드
static void method3() {
// 컴파일에러
this.field1 = 10;
this.method1();
// 컴파일 에러
this.field2 = 10;
this.method2();
}
}
정적메소드에서 인스턴스 멤버를 사용하려면?
// 정적메소드 안에 객체를 생성하고 참조변수로 접근
static void method3() {
className obj = new ClassName();
obj.field1=10;
obj.method2();
}
public class Singleton{
private static Singleton singleton = new Singleton(); //정적필드..
private Singleton() {} //생성자가 private라서 객체 생성x
static Singleton getInstance() { //대신 정적메소드엔 접근 가능!
return singleton; // 새객체x, 이 필드에서 참조하는 자신의 객체 리턴
}
}
public class SingletonExample{
public static void main(String[] args){
/* Singleton obj1 = new Singlerton();
Singleton obj2 = new Singlerton(); */ //컴파일에러. 생성자 접근 안돼서 뉴객체 생성 안되니까 당연
Singleton obj1 = Singleton getInstance();
Singleton obj2 = Singleton getInstance();
if(obj1==obj2){
system.out.println("같은 싱글톤 객체입니다"); //이게 출력됨
} else {
system.out.println("다른 싱글톤 객체입니다");
}
}
}
final String nation = "Korea";
static final double PI = 3.14159;
객체의 필드를 외부에서 접근하게 되면 객체의 무결성이 깨진다
(예를 들어, 자동차 속력은 음수가 될 수 없는데, 외부에서 음수로 변경하면 변경된다 = 무결성이 깨진다)
따라서 메소드를 통해 필드를 변경한다.
Setter : 매개값을 검증하여 유효한 값만 객체의필드로 저장
void setSpeed(double speed){
if(speed <0){
this.speed = 0;
return;
} else {
this.speed = speed;
}
}
Getter : 필드값을 가공 한 후, 외부객체에서 데이터를 읽어온다.
double getSpeed() {
double km = speed*1.6;
return km;
}