국비/Java

2023.03.02 25일차 Java

춘핑이 2023. 3. 2. 17:18

6.클래스

6.8 생성자

인스턴스 만들자마자 해야하는 일으로 필드 초기화가 있다.
이후 관련된 메소드를 사용한다.
그래서 이것을 만들때마다 하니 클래스 안에 넣어두고 싶다.

생성자(constructor)란 인스턴스 만들때 해야하는 일이 있는 코드블럭이다.
주로 필드 초기화 역할을 한다.

MyClass02 () {
//명령문들...
System.out.println("인스턴스 만들때 해야하는 일들...");
}
인스턴스가 만들자마자 생성자 안의 코드들이 실행된다.

6.8.1 생성자-1

필드를 일괄적으로 처리하기

public class MyClass03 {
    String name;
    int age;

    MyClass03() {
        // 최초로 해야하는 일들
        name = "son";
        age = 77;
    }

    void descript() {
        System.out.println("이름: " + name + ", 나이: " + age);
    }
}

public class C03Constructor {
    public static void main(String[] args) {
        MyClass03 o1 = new MyClass03();
        MyClass03 o2 = new MyClass03();

        o1.descript(); //이름: son, 나이: 77
        o2.descript(); //이름: son, 나이: 77
    }
}

6.8.2 생성자-2

필드를 초기화할때 값을 받으면 어떨까
이때 파라미터가 필요하다.

public class MyClass04 {
    String model;
    int price;

    MyClass04(String m, int p) {
        model = m;
        price = p;
    }

    void descript() {
        System.out.println("모델: " + model);
        System.out.println("가격: " + price);
    }
}

public class C04Constructor {
    public static void main(String[] args) {
        MyClass04 o1 = new MyClass04("abc", 300);
        MyClass04 o2 = new MyClass04("def", 500);

        o1.descript(); //모델: abc 가격: 300
        o2.descript(); //모델: def 가격: 500
    }
}

6.8.3 생성자 - 3

파라미터값이 즉 필드값이 되니 파라미터를 축약해서 적는게 싫다.
파라미터와 필드의 이름을 같게하고 싶다.

MyClass04(String model, int price) {
    model = model;
    price = price;
}

그런데 이렇게 넣으면 둘다 파라미터의 변수를 가르키게 된다.
그래서 이것을 해결하기 위해 this 키워드를 넣어야한다.

MyClass04(String model, int price) {
    this.model = model;
    this.price = price;
}

6.8.4 생성자 - 4

인스턴스만들때 생성자가 있어야하는데 지금까지 없이 객체 생성이 가능했다.
생성자를 작성하지 않으면 파라미터 없는 생성자를 자동으로 생성해주기 때문이다.
no-argument constructor(no-arg constructor, default constructor), 기본생성자라고 한다.

그런데 생성자를 만들면 기본생성자를 사용하지 못한다.

public MyClass06(String name, int age) {
    this.name = name;
    this.age = age;
}

MyClass06 o1 = new MyClass06("son", 77);
//MyClass06 o2 = new MyClass06(); 불가능

기본생성자가 필요하다면 만들어줘야한다.
같은 이름에 파라미터 개수 순서가 다르면 오버로딩이다.
메소드를 오버로딩햇듯이 생성자도 오버로딩할 수 있다.
즉 파라미터 순서, 타입, 개수에 따라 생성자를 여러개 만들 수 있다.

//생성자
public MyClass07() {
    //기본 생성자 만들수 있음.
}

public MyClass07(String name, int age) {
    this.name = name;
    this.age = age;
}

6.8.5 생성자 오버로딩

값을 아직 잘모르는데 초기화하고 싶다.
null값 같은 것을 넣을 수 있다.
이렇게 해도되는데 오버로딩이 가능하니 넣지 않는 생성자를 넣으면 된다.

// 생성자
MyClass08(String name, int age, boolean married) {
    this.name = name;
    this.age = age;
    this.married = married;
}

MyClass08(String name, int age, String birthDate, boolean married) {
    this.name = name;
    this.age = age;
    this.birthDate = birthDate;
    this.married = married;
}

MyClass08 o2 = new MyClass08("son", 33, null, false);
MyClass08 o3 = new MyClass08("son", 33, false);

후자로 작성하는게 더 깔끔하다.

6.8.6 String 생성자 오버로딩

String 인스턴스도 다양하게 오버로딩되어 있다.
이런식으로 남이 작성한 생성자가 오버로딩 되어있으면 필요한 생성자를 가져다 사용하면된다.

public class C09String {
    public static void main(String[] args) {
        String s1 = new String();
        System.out.println(s1);

        String s2 = new String(new byte[] { 97, 98, 99 });
        System.out.println(s2); // abc

        String s3 = new String(new byte[] { 97, 98, 99 }, 1, 2);
        System.out.println(s3); //bc

        String s4 = new String(new char[] { '가', '나', '다', 'a', 'b' });
        System.out.println(s4); //가나다ab
    }
}

6.8.7 생성자 오버로딩 -1

생성자를 오버로딩하다보니 중복되는 코드가 너무 많다.
this.name = name;에서의 this는 앞으로 만들어질 인스턴스를 호출하는 것이다.

this();을 하면 다른 생성자를 호출하는 것이다.
파라미터의 개수 순서 타입을 보고 각자에 맞는 생성자를 호출하게 된다.
보통은 마지막 생성자만 작성하고 앞에 생성자들에는 기본값을 넣어서 초기화한다.

public class Car {
    // 필드선언
    String company = "현대자동차";
    String model;
    String color;
    int maxSpeed;

    Car(String model) {
        // 20라인 생성자 호출
        this(model, "은색", 250);
    }

    Car(String model, String color) {
        // 20라인 생성자 호출
        this(model, color, 250);
    }

    Car(String model, String color, int maxSpeed) {
        this.model = model;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }
}

public class CarExample {
    public static void main(String[] args) {
        Car car1 = new Car("자가용"); // 1.생성자호출
        System.out.println(car1.company); // 현대자동차
        System.out.println(car1.model); // 자가용
        System.out.println(car1.color); //은색
        System.out.println(car1.maxSpeed); //250
        System.out.println();

        Car car2 = new Car("자가용", "빨강"); // 2.생성자호출
        System.out.println(car2.company); // 현대자동차
        System.out.println(car2.model); // 자가용
        System.out.println(car2.color); //빨강
        System.out.println();

        Car car3 = new Car("택시", "검정", 200); // 2.생성자호출
        System.out.println(car3.company); // 현대자동차
        System.out.println(car3.model); //택시
        System.out.println(car3.color); //검정
        System.out.println(car3.maxSpeed); //200
        System.out.println();
    }
}

6.8.8 final

final필드는 초기 값을 꼭 넣어줘야한다.
필드 선언할때 값을 지정 안해줬다면 생성자를 호출할때 초기화를 해줄 수 있다.

public class MyClass11 {
    final String name = "son";
    final int age; //생성자에서 값 할당해야함.

    MyClass11(){
        age = 99;
    }

    MyClass11(int age){
        this.age = age;
    }
}

6.9 static block

인스턴스필드는 생성자에서 초기화하면되는데 정적필드는 어디서 초기화하나?
생성자는 인스턴스 필드 초기화를 주로 한다.
정적필드은 static block에서 주로 초기화한다.

static {
    //명령문들
    company = "samsung";
}

그냥 값을 초기화하면되는데 왜 이 블록을 사용하냐?
연산을 이용해서 복잡한 초기화를 하는경우가 있다.
이럴 경우에 사용하게 된다.

public class Television {
    static String company = "MyCompany";
    static String model = "LCD";
    static String info;

    static {
        info = company + "-" + model;
    }
}

public class TelevisionExample {
    public static void main(String[] args) {
        System.out.println(Television.info); //MyCompany-LCD
    }
}

6.10 패키지

하나의 폴더에 모든 파일을 넣지 않듯이 클래스도 패키지로 분류해서 넣게 된다.
show in -> system explorer패키지명과 폴더명이 일치하게 만들어진다.
패지키를 배우지 않앗을때 클래스를 그냥만들었다.
크래스의 풀네임은 패키지명.클래스이름이 된다.

그래서 원래 객체를 만들때 풀네임으로 만들엇어야햇다.
풀네임을 작성하는 것은 너무 길기때문에 import를 해서 해당 클래스를 사용할 수 있다.

public class C01Package {
    public static void main(String[] args) {
        ch06.lecture.p09package.package1.MyClass01 o1 = new ch06.lecture.p09package.package1.MyClass01();
        ch06.lecture.p09package.package2.MyClass02 o2 = new ch06.lecture.p09package.package2.MyClass02();
    }
}

import ch06.lecture.p09package.package1.MyClass01;
import ch06.lecture.p09package.package2.MyClass02;

public class C02Package {
    public static void main(String[] args) {
        MyClass01 o1 = new MyClass01();
        MyClass02 o2 = new MyClass02();
    }
}

6.10.1 import

Scanner와 같은것은 import햇늗네 String은 왜 import를 안하나?
생략가능한 경우가 두가지가 있다.
1.java.lang패키지 내의 클래스 생략가능
2.같은패티지의 클래스 생략가능

6.10.2 import - 2

우연히 같은 클래스명의 서로 다른 패키지에 있는 것을 사용할 경우가 있다.
import하려면 어떤 것을 사용할 건지 선택하게 해준다.

그런데 둘 다 사용하고 싶을때 import를 또하면 같은 이름으로 명시할 수 없다.
그래서 둘 중 하나는 풀네임을 작성해야한다.

import ch06.lecture.p09package.package1.MyClass04;

public class C04import {
    public static void main(String[] args) {
        MyClass04 o1 = new MyClass04();

        ch06.lecture.p09package.package2.MyClass04 o2 = new ch06.lecture.p09package.package2.MyClass04();
    }
}

6.10.3 Static import

정적멤버 import할때 그냥 import가 아니라 imort static할 수 있다.
import static 패키지명.클래스이름.필드명
import static 패키지명.클래스이름.메소드명
으로 import해서 클래스이름 없이 사용할 수 있다.
하지만 코드를 해석하는데 헷갈릴 수 있으니 잘 살펴보고 사용해야한다.

import static ch06.lecture.p09package.package1.MyClass05.name;
import static ch06.lecture.p09package.package1.MyClass05.method1;
import static ch06.lecture.p09package.package1.MyClass05.method2;

public class C05SataticImport {
    public static void main(String[] args) {

        String n = name;

        method1();
        method2();
    }
}

6.10.4 import all

같은 패키지에 여러 클래스를 가져다 사용하면 패키지명들이 반복된다.
이경우
import ch06.lecture.p09package.package1.*;
해주면 이 패키지 밑의 모든 클래스를 사용할 수 있다.

import ch06.lecture.p09package.package1.*;

//패키지 내 모든 클래스
public class C06ImportAll {
    public static void main(String[] args) {
        MyClass01 o1 = new MyClass01();
        MyClass04 o2 = new MyClass04();
    }
}

기본설정은 모두 따로 작성하는 것이다.
설정에 orinize import 99개부터 나타내는 것을 1로 바꾸면 하나만 import해도 바꿀수있다.
나는 다 보고 싶어서 그냥으로 하기로 한다.

6.10.5 확인문제

두개 주사위 던져서 출력하는 코드
import static을 사용해보자.

import static java.lang.Math.*;

public class C08StaticImportAll {
    public static void main(String[] args) {
        // 두개 주사위 던져서 출력하는 코드
        //double num1 = Math.floor(Math.random() * 6) + 1;
        double num1 = floor(random() * 6) + 1;
        double num2 = floor(random() * 6) + 1;

        System.out.println((int) num1);
        System.out.println((int) num2);
    }
}

6.11 접근제한자

접근을 어떻게 제한할건지 명시하는 키워드이다.
public은 누구에게나 공개이다. 즉 public은 어디서든지 접근가능하다.
private는 개인적인 것이다. 즉 private는 작성한 클래스 내에서만 접근가능하다.
private는 언제쓰느냐? 내부에서 접근 가능하다.
default는 아무것도 작성하지 않은 상태이다.
같은 패키지 내라면 접근 가능하고 다른 패키지라면 접근이 불가능하다.

public class MyClass01 {
    // 필드
    public String name;
    private int age;

    // 메소드
    public void method1() {
        System.out.println("메소드1");
    }

    private void method2() {
        System.out.println("메소드2");
    }

    public void method3() {
        System.out.println(age);
    }

    public void method4() {
        method2();
    }
}

public class C01AccessModifier {
    public static void main(String[] args) {
        MyClass01 o1 = new MyClass01();
        System.out.println(o1.name); //접근가능
        //System.out.println(o1.age); 접근 불가능

        o1.method1(); //실행(접근) 가능
        // o2.method2(); 실행(접근) 불가능
    }
}

6.12 Getter와 Setter

객체에는 필드(데이터, 속성)이 있는데 이것을 다른사람이 변경할 수 없게 하고싶다면 private를 해야한다.
int age가 잇을때 -1이 되버리면 무결성이 깨진다 이를 방지하기 위해서 메소드를 사용한다.

public void setAge(int age) {
    if (age < 0 ) {
        this.age = 0;
    }
    this.age = age;
}

메소드로 값을 받는데 무결성을 해친다면 다른값을 넣어주거나 예외를 발생시키게 할 수 있다.

public int getAge() {
    return this.age;
}

값을 읽어오기 위해선 getter를 쓰면된다.

메소드 통해서 필드에 접근하도록 설정한다.
쓸때는 public void set필드이름() 읽을때는 public void get필드이름()으로 만든다.
읽을때는 필드값을 줘야하니 리턴값에 필드값을 넣고 쓸때는 값을 설정하면된다.

public void setName(String name) {
    //변경
    this.name = name;
}

public String getName() {
    //읽기
    return name;
}

만약 boolean type이면 getter는 is로 시작한다.

public boolean isMarried() {
    return married;
}

6.12.1 확인문제 13번

멤버클래스를 만들어보자.

public class Member {
    private String name;
    private String id;
    private String password;
    private int age;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

2023.03.02 후기

백준문제를 많이 풀었다.