본문 바로가기

Programming/자바

자바 재정리 - 클래스

https://cerulean85.tistory.com/149

 

객체와 인스턴스의 차이

* 자의적인 해석이므로 논란의 여지가 있음 객체와 인스턴스의 차이를 알아보니 블로그마다 말이 다르다. 어떤 블로거는 인스턴스는 객체와 같지만, 관계적인 측면에서 이야기할 때 객체 대신

cerulean85.tistory.com

객체 지향 프로그래밍 (Object Oriented Programming)

부품 객체들 먼저 만들고, 하나씩 조립해나가 프로그램 완성

 

객체 : 소프트웨어 세계에 구현할 대상 / 독립적으로 존재하며 서로 상호작용

클래스 : 객체 구현 위한 설계도

인스턴스 : 클래스에 의해 소프트웨어 세계에 구현된 실체 

 

객체⊃인스턴스

 

 

  • 객체

물리/추상적으로 존재하는 것 중 속성 갖고 식별 가능한 것

객체 모델링 : 현실 세계의 객체 -> 소프트웨어 객체

A 객체가 B 객체 기능 이용하려면 메소드 호출해야 함 ex. B.메소드(매개값);

 

 

 

 

  • OOP 특징

1. 캡슐화 : 객체의 내부 구조를 감추고 노출된 필드, 메소드만 이용 가능하 하여 사용범위 제한, 보호

2. 상속 : 상위 객체가 하위 객체에 필드, 메소드 물려줌 => 효율적, 코드 중복 줄임

3. 다형성: 하나의 타입에 여러 객체 대입 가능

  => 부모 타입에 모든 자식 객체 대입 가능, 인터페이스 타입에 모든 구현 객체 대입 가능

ex. A 인터페이스 타입 타이어 = 여러 회사의 A 구현 타이어들 모두 교체 가능​

 

 

 

 

객체 & 클래스

클래스 이름 대문자로 시작
메인 메소드 없이 생성 => ru​n 안 됨

 

구성 멤버 : 필드, 생성자, 메소드

 

 

  • 클래스 선언
public class Account { //클래스 선언
    //필드
    String accountNo; 
    String ownerName;    
    int balance;
    
    //생성자
    
    //메서드: 예금
    void deposit (int amount) { //void : 리턴값 없음 //괄호 안: 매개변수 ex.주스 받을 컵
        balance+=amount;
    }    
    
    //메서드: 인출
    int withdraw(int amount) { //리턴값 : int
        if (balance<amount) {
            return 0;
        } 
        balance-=amount;
        return amount;
    }    
}

 

 

  • 객체 생성
Account chulsu;  //클래스 변수 선언
chulsu= new Account();  //새 객체 생성, 변수에 저장

=>축약
Account chulsu = new Account();  //Account 클래스의 객체(인스턴스) 생성

 

public class AccountEx1 {
 
    public static void main(String[] args) {
        Account chulsu = new Account();  //객체(인스턴스) 생성
        chulsu.accountNo = "0101-10101-1010";  //해당 클래스 내 필드, 메서드 사용 가능
        chulsu.ownerName = "김철수";
        chulsu.balance = 1000;
        
        Account gildong = new Account();
        gildong.accountNo = "0202-020202-0202";
        gildong.ownerName = "홍길동";
        gildong.balance = 0;
        
        chulsu.deposit(5000);
        gildong.deposit(30000);
        chulsu.deposit(20000);
    
        int amount = gildong.withdraw(7000);
        System.out.println("찾은 금액: "+amount);
        System.out.println("잔액: "+gildong.balance);
    }
}

 

괄호 O => 메소드

괄호 X => 필드

 

 

라이브러리 클래스 : 다른 클래스에서 이용하는 클래스 ex. Account

실행 클래스 : main() 메소드 제공하여 프로그램을 실행하는 클래스 ex. AccountEx1

 

 

 

 

필드 (=변수)

: 객체의 정보 저장하는 곳

 

객체 생성 시 초기값 설정 안 된 필드는 자동으로 기본 초기값 (0,false,null..) 설정됨

 

 

 

 

생성자

 : 객체 생성 시 객체 초기화(필드 초기화, 메소드 호출-> 객체 사용할 준비함)를 위해 가장 처음 실행되는 메소드

 

생성자 생략 -> 중괄호 {} 블록 비어있는 기본 생성자 자동 생성  => 객체 생성에 생성자 필수

생성자 명시적으로 선언 시 기본 생성자 자동 생성 X

 

리턴 타입 X, 클래스 이름과 동일

 

 

  • 생성자 선언 및 호출
public class Account { //클래스
    //필드
    String accountNo; 
    String ownerName;    
    int balance;
    
    //생성자
    //public Account(String accNo, String ownerNa, int bal) { //생성자 선언
        //accountNo=accNo;  //accountNo : 필드, accNo : 매개변수
        //ownerName=ownerNa;
        //balance=bal;
    //}

   // => 코드 작성 편의 위해 매개변수명, 필드명 같도록 수정

    public Account(String accountNo, String ownerName, int balance) {   
        this.accountNo=accountNo;  //매개변수 String accountNo 받아서 객체 자신의 필드 accountNo에 전달
        this.ownerName=ownerName;
        this.balance=balance;
    }
    
    //메서드: 예금
    void deposit (int amount) { 
        balance+=amount;
    }    
    
    //메서드: 인출
    int withdraw(int amount) {
        if (balance<amount) {
            return 0;
        } 
        balance-=amount;
        return amount;
    }    
}

 

public class AccountEx2 {
 
    public static void main(String[] args) { 
        Account younghee = new Account("222-222-222","이영희",100);  //생성자 호출
        Account chanho = new Account("111-222-3333", "박찬호" , 0);
        
        younghee.deposit(50000);
        chanho.deposit(30000);
        younghee.deposit(40000);
        chanho.withdraw(12000);
 
        printAccount(younghee);
        printAccount(chanho);
    }
 
    //통장 정보 출력 메서드 => 메소드의 분업화
    static void printAccount(Account obj) { //매개변수=>Account 클래스 객체만 받음
        System.out.println("계좌번호: "+obj.accountNo);
        System.out.println("예금주이름: "+obj.ownerName);
        System.out.println("잔액: "+obj.balance);
        System.out.println("-------------------------");
    }
}

//
계좌번호: 222-222-222
예금주이름: 이영희
잔액: 90100
-------------------------
계좌번호: 111-222-3333
예금주이름: 박찬호
잔액: 18000
-------------------------

 

 

  • 생성자 오버로딩

: 매개변수 타입, 개수, 순서 다르게 선언

 

=> 다양한 방법으로 객체 생성 가능해짐

 

public class Car {
    Car(){..}
    Car(String model){..}
    Car(String model, String color){..}
    Car(String model, String color, int speed){..}
}

 

 

  • this() - 다른 생성자 호출

생성자 오버로딩 많아지면 중복 코드 발생

=> 필드 초기화 내용을 한 생성자에만 작성하고 나머지 생성자에서는 해당 생성자 호출

 

생성자 첫 줄에서만 사용 가능

 

 

public class Car{
    //필드
    String compnay="현대";
    String model;
    String color;
    int maxSpeed;
    
    //생성자
    Car(){}
    Car(String model){
        this(model, "은색", 250);  //호출
    }
    Car(String model, String color){
        this(model, color, 250);  //호출
    } 
    Car(String model, String color, int maxSpeed){  //공통 실행 코드
        this.model=model;
        this.color=color;
        this.maxSpeed=maxSpeed;    
    }
}

 

 

 

 

 

메소드

: 객체의 동작(기능, 일)에 해당하는 중괄호 { } 블록

 

=> 객체 간 상호작용의 수단, 객체가 다른 객체 기능 이용하도록 함

 

 

  • 메소드 오버로딩

클래스 내에 같은 이름의 메소드를 여러 개 선언


1. 매개변수 개수 달라야 함
2. 매개변수 개수 같으면 타입 or 순서 달라야

 

 

public class PhysicalInfo {
    //필드
    String name;
    int age;
    float height, weight;
    
    //생성자
    public PhysicalInfo(String name, int age, float height, float weight) {
        this.name=name;
        this.age=age;
        this.height=height;
        this.weight=weight;
        //매개변수 이름=필드 이름 편리, but 구분 필요 => 필드값에는 this 추가
    }
    
    //메소드
    void update (int age, float height, float weight) {
        this.age=age;
        this.height=height;
        this.weight=weight;
    }    
    
    //메소드 오버로딩
    void update (int age, float height) {
        this.age=age;
        this.height=height;
    }
}

 

//PhysicalInfoEx

    public static void main(String[] args) {
        PhysicalInfo younghee = new PhysicalInfo("이영희", 10, 135.5f, 38.0f);
        printPhyiscalInfo(younghee);
        younghee.update(11, 145.0f, 44.2f); //기존 메소드
        printPhyiscalInfo(younghee);
        younghee.update(12, 157.9f); //오버로딩한 메소드
        printPhyiscalInfo(younghee);
    }
    
    public static void printPhyiscalInfo(PhysicalInfo obj) {
        System.out.println("이름 : "+obj.name);
        System.out.println("나이 : "+obj.age);
        System.out.println("키 : "+obj.height);
        System.out.println("몸무게 : "+obj.weight);
        System.out.println("---------------------------");
    }

//
이름 : 이영희
나이 : 10
키 : 10.0
몸무게 : 38.0
---------------------------
이름 : 이영희
나이 : 11
키 : 145.0
몸무게 : 44.2
---------------------------
이름 : 이영희
나이 : 12
키 : 157.9
몸무게 : 44.2
---------------------------

 

 

  • 매개변수 없는 메소드
public class Rectangle {

    int width;
    int height;
    
    public Rectangle(int width, int height) {
        this.width=width;
        this.height=height;
    }
        
    int getArea() { //매개변수 없음 => 호출 시 내부 코드 실행해 값 리턴
        return width*height;
    }
    
}

public class RectangleEx1 {
 
    public static void main(String[] args) {
        Rectangle rect1 = new Rectangle(20, 30);
        int area = rect1.getArea(); //내부 계산 실행해 리턴한 값을 변수에 전달
        System.out.println("사각형 너비 : "+rect1.width );    
        System.out.println("사각형 높이 : "+rect1.height );
        System.out.println("사각형 면적 : "+area );
    }
    
}

 

 

  • 매개변수 개수 모를 때

매개변수를 "..."으로 선언 => 메소드 호출 시 배열 요소들만 나열 

 

 

public class Calculator {
    
    //배열을 매개변수로 받아 처리하는 메소드
    int sum1(int[] values) {
        int sum=0;
        for (int i=0;i<values.length;i++) {
            sum+=values[i];
        }
        return sum;
    }
 
    //매개변수로 데이터를 받아서 처리하는 메소드
    int sum2(int num1, int num2, int num3) {
        int sum=0;
        sum=num1+num2+num3;
        return sum;
    }
    
    //매개변수의 수를 모를 경우 처리하는 메소드
    int sum3(int ...nums) {    
        int sum=0;
        for (int i=0;i<nums.length;i++) {
            sum+=nums[i];
        }
        return sum;
    }
}

public class CalculatorEx1 {
 
    public static void main(String[] args) {
        Calculator myCalc = new Calculator();
        
        int[] value1 = {10,85,31,64,33};
        int result1=myCalc.sum1(value1); //배열 자체 대입
        System.out.println("배열의 총합 : "+result1);
        
        int result2 = myCalc.sum1(new int[] {85,90,40});  
        System.out.println("배열의 총합 : "+ result2);
        
        int result3 = myCalc.sum3(20, 80, 60); //배열 요소만 대입
        System.out.println("자료의 총합 : "+result3);
        
        int result4 = myCalc.sum3(20, 80, 60,85,90);   
        System.out.println("자료의 총합 : "+result4);        
    }
}

 

 

 

 

인스턴스 멤버 & this

인스턴스 멤버 : 객체(인스턴스) 생성해야 사용 할 수 있는 필드, 메소드 (인스턴스 필드, 인스턴스 메소드)

 

 

  • this => 객체 내부에서 인스턴스 멤버에 접근
Car(String model){
    this.model = model;  //this 통해 객체의 필드에 접근
}

 

 

정적 멤버 (static)

정적 멤버(=클래스 멤버) : 클래스에 고정된 멤버 / 객체 생성하지 않아도 사용할 수 있는 필드와 메소드

 

정적 블록 안에서 인스턴스 멤버, this 사용 불가 

=> 객체 생성, 참조변수로 접근하면 인스턴스 멤버 사용 가능

 

메인 메소드도 정적 메소드 ex. public static void main(String[] args){}

 

 

  •  
public Class ClassType {
    //정적 멤버
    static int field();
    static void method(){}
    
    //인스턴스 멤버
    int field2;
    void method2(){}
    
    //정적 블록
    static {
        field=20;
        method();
        field2=10; //컴파일 에러 (인스턴스 멤버 사용 불가)
        method2(); //컴파일 에러
    }
    
    static void method3(){
        this.field2=100; //컴파일 에러 (this 사용불가)
        ClassType obj = new ClassType(); //객체 생성 후 참조변수로 접근하면 인스턴스 멤버 사용 가능
        obj.field2=20;  //O
        obj.method1();  //O
    }
}

 

 

  •  
public class Printer {
    //정적 메소드
    static void println(int value) {
        System.out.println(value);
    }
    static void println(boolean value) {
        System.out.println(value);
    }
    static void println(double value) {
        System.out.println(value);
    }
    static void println(String value) {        
        System.out.println(value);
    }
}


public class PrinterExample {
 
    public static void main(String[] args) {
        Printer.println(10);  //static => 객체 생성 없이 클래스 통해 바로 메소드 구현
        Printer.println(true);
        Printer.println(4.6);
        Printer.println("홍길동");
    }
}

 

 

 

 

final 필드 & 상수
  • final 필드

: 초기값이 최종값이 되어 수정 불가한 필드

 

객체마다 저장되며, 생성자의 파라미터를 통해 값 가질 수 있음

 

 

  • 초기값 부여하는 방법

1. 필드 선언 시 부여

2. 생성자에서 부여

 

public class Person{
    final String name="a";  //필드로 초기값 부여
    final int age=12;
    
    public Person(int age){ //생성자로 초기값 부여
        this.age=age;
    }
}

 

 

  • 상수(static final) : 변하지 않는 값

객체마다 저장되지 않고 클래스에만 포함됨

=> 객체 생성되지 않아도 원본클래스 자체에서 접근 가능

 

초기값 수정 불가

 

필드명 전체 대문자 권장

 

 

public class Account {
    //상수 필드
    static final String BANKNAME = "신한은행";   
    
    //인스턴트 필드 : 변수 
    String accountNo;    
    String ownerName;    
    int balance;
    
    public Account(String accountNo, String ownerName, int balance) {
        this.accountNo=accountNo;  //this=> 필드
        this.ownerName=ownerName;
        this.balance=balance;
    }
    
    public Account() {
    }
    
    
    void deposit (int amount) {
        balance+=amount;
    }    
    
    int withdraw(int amount) throws Exception {
        if (balance<amount) {
            throw new Exception("잔액 부족");
        } 
        balance-=amount;
        return amount;
    }    
}


public class AccountEx2 {
 
    public static void main(String[] args) { 
        Account younghee = new Account("222-222-222","이영희",100);
        System.out.println(Account.BANKNAME); //객체 없이 클래스로만 접근
        ~

 

 

 

 

패키지

클래스 관리하기 위한 폴더

클래스 식별자 역할 => 다른 패키지에 있으면 클래스 이름 같아도 다른 클래스로 인식됨

 

  • import

다른 패키지 클래스 사용하려면 import문 작성

 

 

import 패키지명.클래스명;

 

import 패키지명.*; //패키지의 모든 클래스 import

 

 

 

 

접근 제한자
접근제한 적용 대상 접근 가능/불가 클래스
public 클래스, 필드, 생성자, 메소드 모두 접근 가능
protected 필드, 생성자, 메소드 같은 패키지 + 다른 패키지 자식클래스 접근 가능
default 클래스, 필드, 생성자, 메소드 같은 패키지만 접근 가능 (다른 패키지 접근 불가)
private 필드, 생성자, 메소드 모든 외부 클래스 접근 불가

 

 

  • private
public class Rectangle {
    private int width; //private 접근 제한 생성자
    private int height;
}

public class RectangleEx1 {
 
    public static void main(String[] args) {
        Rectangle rect1 = new Rectangle(20, 30);
//      rect1.width=-10;
        int area = rect1.getArea();
//      System.out.println("사각형 너비 : "+rect1.width );    
//객체 생성 -> 필드, 메소드에 접근 가능
//      System.out.println("사각형 높이 : "+rect1.height );
        System.out.println("사각형 면적 : "+area );
    }
}

=> 다른 클래스에서 필드 단독 사용 불가, 에러 발생

 

 

 

 

=> 해결

getter, setter 메소드

: 두 메소드 통해 접근 제한된 객체의 값 가져옴

 

 

  • getter : 필드값 가공, 외부로 전달
public class Rectangle {
    private int width;
    private int height;
    
    public Rectangle(int width, int height) {
        this.width=width;
        this.height=height;
    }
        
    int getArea() { //
        return width*height;
    }
 
    public int getWidth() { //
        return width;
    }
 
    public int getHeight() { //
        return height;
    }
}

public class RectangleEx1 {
 
    public static void main(String[] args) {
        Rectangle rect1 = new Rectangle(20, 30);
        int area = rect1.getArea();
        System.out.println("사각형 너비 : "+rect1.getWidth());   
        System.out.println("사각형 높이 : "+rect1.getHeight());
        System.out.println("사각형 면적 : "+area );
    }
}

 

 

필드에 음수값, 0 비허용 설정

public class Rectangle {
    private int width;
    private int height;
    
    public Rectangle(int width, int height) throws Exception { // 
        if (width<=0 || height<=0) {    
            throw new Exception("너비와 높이는 양수만 가능");
        }
        this.width=width;
        this.height=height;
    }
        
    int getArea() {
        return width*height;
    }
 
    public int getWidth() {
        return width;
    }
 
    public int getHeight() {
        return height;
    }
 
    public int getHeight() {
        return height;
    }
}

public class RectangleEx1 {
 
    public static void main(String[] args) {
        try {
        Rectangle rect1 = new Rectangle(20, 30);
        int area = rect1.getArea();
        System.out.println("사각형 너비 : "+rect1.getWidth());  
        System.out.println("사각형 높이 : "+rect1.getHeight() );
        System.out.println("사각형 면적 : "+area );
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
    }
}

=> throws Exception 설정 => ex 클래스에 오류 대응책으로 try catch문 작성 필수 

 

 

  • setter : 매개값 필드에 저장
public class Rectangle {
    private int width;
    private int height;
    
    public Rectangle(int width, int height) throws Exception {
        if (width<=0 || height<=0) {
            throw new Exception("너비와 높이는 양수만 가능");
        }
        this.width=width;
        this.height=height;
    }
        
    int getArea() {
        return width*height;
    }
 
    public int getWidth() {
        return width;
    }
 
    public int getHeight() {
        return height;
    }
 
    public void setWidth(int width) { //
        this.width = width;
    }
 
    public void setHeight(int height) { //
        this.height = height;
    }
}

public class RectangleEx1 {
 
    public static void main(String[] args) {
        try {
            Rectangle rect1 = new Rectangle(20, 30);
            int area = rect1.getArea();
            System.out.println("사각형 너비 : "+rect1.getWidth());   
            System.out.println("사각형 높이 : "+rect1.getHeight() );
            System.out.println("사각형 면적 : "+area );
            rect1.setWidth(50);   
            rect1.setHeight(70);   
            area=rect1.getArea();
            System.out.println("사각형 너비 : "+rect1.getWidth());   
            System.out.println("사각형 높이 : "+rect1.getHeight() );
            System.out.println("사각형 면적 : "+area );
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
    }
}

 

 

 

 

싱글톤

: 클래스 외부에서 new 연산자로 생성자 호출할 수 없도록 막아 만들어지는 단 하나의 객체
생성자 앞에 private 제한자 붙임
정적 필드, 정적 메소드

 

 

public class Cheomseongdae {
    
    //정적 필드
    private static Cheomseongdae cheom = new Cheomseongdae();  //클래스 자체가 필드가 됨
    
    //private 생성자
    private Cheomseongdae() {
    }
    
    //정적 메서드
    static Cheomseongdae getInstance() {  //Cheomseongdae: 타입 이름 / getInstance: 메소드 이름
        return cheom;
    }    
 
    void history() {
        System.out.println("경주");
    }
}

public class CheomseongdaeEx1 {
 
    public static void main(String[] args) {
        //Cheomseongdae cheom1 = new Cheomseongdae(); //싱글톤이므로 새 객체 생성 불가
        //Cheomseongdae cheom2 = new Cheomseongdae();   
        
        Cheomseongdae cheom1 = Cheomseongdae.getInstance();  //getInstance()로 외부에서 객체 받기
        Cheomseongdae cheom2 = Cheomseongdae.getInstance();
        if (cheom1==cheom2) {
            System.out.println("같은 첨성대 객체");
        }else {
            System.out.println("다른 첨성대 객체");   
        }
        cheom1.history();
        cheom2.history();
        
    }
}

//
같은 첨성대 객체

경주

경주

 

=> 하나의 객체(싱글톤) 가리킴

 

 

 

 

어노테이션

= 메타데이터 (정보)

 

1. 컴파일러에 문법 에러 체크하도록 정보 제공

2. 소프트웨어 개발 툴이 코드 자동 생성하도록 정보 제공

3. 실행 시 기능 실행하도록 정보 제공

 

 

https://velog.io/@jkijki12/annotation

 

[Java] 어노테이션이 뭔데??

자바 어노테이션에 대해서 공부하자!!

velog.io

 

 

  • 내장 어노테이션

@Override 
int witdhraw(int amount) throws Exception {   //오류 발생 => 오타 방지

 

 

 

 

  • 커스텀 어노테이션

new - Annotation - Add @Retention-Runtime & Add @Target

 

 

  •  
import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
 
@Target(ElementType.METHOD)
@Retention(RUNTIME)
public @interface PrintAnnotation {
    String value() default "#";  //값 전달받지 않으면 default로 # 출력
    int number() default 20;
}


public class Service {
 
    @PrintAnnotation
    public void corona() {
        System.out.println("코로나 박멸!");
    }
    
    @PrintAnnotation("*")  //PrintAnnotation.class value값 변경
    public void corona2() {
        System.out.println("오미크론 박멸!");
    }
    
    @PrintAnnotation(value="$", number=30)  //PrintAnnotation.class value, number 값 변경
    public void corona3() {
        System.out.println("변이 코로나 박멸!");
    }
}


import java.lang.reflect.Method;
 
public class ServiceEx1 {
 
    public static void main(String[] args) {
        Method[] methods = Service.class.getDeclaredMethods();  
        //서비스 클래스에서 만들어진 메소드 정보 얻음
        for (Method m : methods) {
            if (m.isAnnotationPresent(PrintAnnotation.class));
                PrintAnnotation print = m.getAnnotation(PrintAnnotation.class);
                System.out.println("***"+m.getName()+"***");  //메소드이름 (corona) 출력
                for (int i=0;i<print.number();i++) {
                    System.out.print(print.value());    
                }
                System.out.println();
                
                try{
                    //메소드 호출
                    m.invoke(new Service());  
                   //메소드 안 내용 출력 요구  //try catch 필수(null의 가능성)
                }catch(Exception e) {
                    System.out.println("메소드 처리 에러");
                }        
        }//외부for        
    }    
}

//

***corona***
####################
코로나 박멸!
***corona3***
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
변이 코로나 박멸!
***corona2***
********************
오미크론 박멸!

 

'Programming > 자바' 카테고리의 다른 글

자바 재정리 - 인터페이스  (0) 2022.08.25
자바 재정리 - 상속  (0) 2022.08.23
자바 재정리 - 참조  (0) 2022.08.05
생활코딩 자바 - Collections framework  (0) 2022.04.24
생활코딩 자바 - 제네릭  (0) 2022.04.20