[TIL 3] 자바 복습 내용 정리

돗치·2024년 1월 31일

메인 클래스 동작 방식

  • JVM이 실행할 클래스 찾음
  • static 키워드가 붙어있는 멤버들을 정해진 메모리 위치에 한 번 자동으로 로딩 → static 멤버들은 클래스를 사용하는 시점에서 딱 한 번 메모리에 로딩 됨 → 여기서 main 메서드가 static이기 때문에 메모리에 자동 로딩
  • JVM이 static-zone에서 main메서드 호출
  • 호출 된 메서드를 Call Static Fame Area에 push한 뒤 동작 시작

static

  • 클래스를 사용하는 시점에서 딱 한번 메모리에 로딩하기 위해 사용하는 키워드

*Call Static Fame Area

  • 메서드 호출 되면 호출 된 기계어 코드가 push되고 실행되는 메모리 공간
  • 현재 프로그램이 실행되고 있는 상태를 파악
  • LIFO구조
package fc.java.part3;

public class StaticTest {
    public static void main(String[] args) {
        int a=10;
        int b=20;
        int sum = StaticTest.hap(a,b);
        System.out.println("sum = " + sum);

    }
    //매개변수로 2개 정수 입력 받아 총합 구해 리턴
    public static int hap(int a, int b){
        int v=a+b;
        return v;
    }
}

static 메서드 접근 방법 = 클래스이름.호출메서드

static 멤버는 클래스를 사용하는 시점에서 자동으로 static - zone에 로딩 됨.

new를 이용해 객체 생성할 필요 없음

none-static 메서드 접근 방법

  • 객체 생성해서 메모리에 접근 시켜야 됨

*Method Area

  • 메서드의 기계어 코드가 할당되는 메모리 공간
  • statix 멤버들의 할당되는 메모리 공간

*Heap Area

  • 객체가 생성되는 메모리 공간

객체 생성을 막는 방법 : 생성자를 private으로

package fc.java.part3;

public class NoneStaticTest {
    public static void main(String[] args) {
        int a=10;
        int b=20;
        NoneStaticTest st = new NoneStaticTest();
        int sum=st.hap(a,b);
        System.out.println("sum = " + sum);
    }
    public int hap(int a, int b){
        int v=a+b;
        return v;
    }
}
package fc.java.model;

public class MyUtil {
    public static int hap (int a, int b) {
        int v = a+b;
        return v;

    }
}
package fc.java.part3;

import fc.java.model.MyUtil;

public class StaticAccess {
    public static void main(String[] args) {
            int a = 10;
            int b = 20;
        int sum = MyUtil.hap(a,b);
        System.out.println(sum);
    }
}
package fc.java.model;
public class MyUtil1 {
    public int hap(int a, int b){
        int v = a+b;
        return v;
    }
}
package fc.java.part3;
import fc.java.model.MyUtil1;
public class NoneStaticAccess {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        MyUtil1 my1 = new MyUtil1();
        int sum = my1.hap(a,b);
        System.out.println("sum = " + sum);
    }
}

JVM의 Memery model (Runtime Data Area)

Method Area

  • 메서드의 바이트코드(기계어 코드)가 할당되는 공간
  • static-zone과 none-static-zone으로 나누어짐
  • static 멤버들은 static-zone에 할당됨

Heap Area Generation

  • 객체가 생성되는 메모리 공간(new연산자)
  • GC(Garbage collector)에 의해 메모리 수집

Stack Area (Call Stack Frame Area)

  • 메서드가 호출 되면 메서드의 기계어 코드를 할당받고 (Native Method Area)메서드가 실행되는 메모리 공간 (Call Stack Frame Area) ( 지역변수, 매개변수들이 만들어지는 공간)
  • PC (Program Counter)에 의해 현재 실행 중인 프로그램의 위치가 관리 됨
  • LIFO구조로 운영이 되는 메모리 공간(메서드의 호출 순서를 알 수 있음)

Runtime Constant Pool (Literal Pool)

  • 상수 값 할당이 되는 메모리 공간
  • 문자열 중 문자열 상수가 할당 되는 메모리 공간
package fc.java.model;

public class AllStatic {
    public static int hap(int a, int b) {
        int v = a + b;
        return v;
    }

    public static int max(int a, int b) {
        return a > b ? a : b;
    }

    public static int min(int a, int b) {
        return a < b ? a : b;
    }
}
package fc.java.part3;
import fc.java.model.AllStatic;
public class AllStaticTest {
    public static void main(String[] args) {
        AllStaticTest st = new AllStaticTest();
        System.out.println(AllStatic.hap(10, 20));
        System.out.println(AllStatic.hap(10, 20));
        System.out.println(AllStatic.hap(10, 20));

        System.out.println(Math.max(30, 60));
        System.out.println(Math.max(40, 10));
    }

}

클래스: 객체를 모델링 하는 도구(설계도)

Object(객체)

  • 클래스를 통해서 선언되는 변수

객체 변수: 변수가 구체적인 실체(대상)을 가리키지 않는 상태, 객체가 서로 구분 안되는 시점

Instance(인스턴스, 실체): 객체 생성에 의해 메모리(Heap Memory)에 만들어진 객체

인스턴스 변수: 객체가 구체적인 실체를 가리키는 상태, 객체가 서로 구분이 되는 시점

package fc.java.part3;
import fc.java.model.Student;

public class ClassObjectInstance {
    public static void main(String[] args) {
        Student st1 = new Student("홍길동", "컴퓨터공학부", 37, "bit@empas.com", 2023110, "010-1111-2222");
        Student st2 = new Student("김길동", "컴퓨터공학부", 27, "bit@empas.com", 2023111, "010-2222-1111");
        Student st3 = new Student("이길동", "컴퓨터공학부", 17, "bit@empas.com", 2023112, "010-2112-1221");

        System.out.println(st1.toString());
        System.out.println(st2.toString());
        System.out.println(st3.toString());
    }
}

상속

  • 클래스를 계층화 하는 것
  • 부모가 자식들에게 자신의 것을 사용하라고 허락해주는 것

객체를 설계하다 보면 비슷한 클래스의 경우 중복 요소 발생 가능

객체를 수평적인 구조로 설계할 시 단점

  1. 코드 중복 발생
  2. 새로운 요구사항 반영 힘듦(유지보수 힘듦)
  3. 확장성이 떨어짐

수직적구조 = 계층화 = 상속 = 클래스와 클래스의 관계 설계

객체를 수직적인 구조로 설계할 시 장점

  1. 코드 중복 최소화
  2. 새로운 요구사항 발생시 반영이 쉬움
  3. 확장성이 좋아짐. VS코드 복잡

상속 : UML(Unified Modeling Language) - 다이어그램

super class(상위 클래스, 부모 클래스) - 일반화, 추상화, 개념화, 포괄적

extends(상속, 확장) = 상속에서 사용하는 키워드

sub class(하위 클래스, 자식 클래스, 파생 클래스) - 구체화, 세분화

super() → 상위클래스의 생성자를 호출

package fc.java.part4;

public class Employee {
    protected String name;
    protected int age;
    protected String phone;
    protected String empDate;
    protected String dept;
    protected boolean marriage;

    public Employee() {
        super();
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", phone='" + phone + '\'' +
                ", empDate='" + empDate + '\'' +
                ", dept='" + dept + '\'' +
                ", marriage=" + marriage +
                '}';
    }
}
package fc.java.part4;

public class RempVO extends Employee{
   public RempVO() {
        super();
    }
}
package fc.java.part4;

public class EmployeeTest {
    public static void main(String[] args) {
        // 사원 한명 객체 생성하고 데이터 저장 후 출력
        RempVO vo = new RempVO();
        vo.name = "홍길동";
        vo.age = 50;
        vo.phone = "010-4444-4445";
        vo.empDate = "2002-QD10-10";
        vo.dept = "홍보부";
        vo.marriage = true;

        System.out.println(vo.name + "\t" + vo.age + "\t" + vo.phone + "\t" + vo.empDate + "\t" + vo.dept + "\t" + vo.marriage);
        System.out.println(vo.toString());
    }
}

상속 관계에서 객체 초기화 (정보은닉 적용)

부모의 생성자에서 초기화 하는 것이 바람직 함.

package fc.java.part4;

public class EmployeeTest {
    public static void main(String[] args) {
        // 사원 한명 객체 생성하고 데이터 저장 후 출력
        RempVO vo = new RempVO("홍길동", 500, "010-1111-1111","2024-01-21", "홍보부", false);

        //System.out.println(vo.name + "\t" + vo.age + "\t" + vo.phone + "\t" + vo.empDate + "\t" + vo.dept + "\t" + vo.marriage);
        System.out.println(vo.toString());
    }
}
package fc.java.part4;

public class EmployeeInitTest {
    public static void main(String[] args) {
        RempVO vo = new RempVO("홍길동", 500, "010-1111-1111","2024-01-21", "홍보부", true);
        System.out.println(vo.toString());
    }
}

Upcasting(업 캐스팅, 자동 형 변환): 부모가 자식을 가리키는 객체 생성 방법 (상속 관계 일 때)

package fc.java.model;

public class Animal extends Object {
    public Animal(){
        super();    // new Object()
    }
    public void eat(){
        System.out.println("동물처럼 먹다");
    }
}
package fc.java.model;

public class Dog extends Animal {
    public void eat() {
        System.out.println("개처럼먹다.");
    }
}
package fc.java.model;

public class Cat extends Animal {
    public void night(){
        System.out.println("밤에 눈에서 빛이 난다.");
    }
}
package fc.java.part4;
import fc.java.model.Animal;
import fc.java.model.Cat;
import fc.java.model.Dog;
public class DogUpcastingTest {
    public static void main(String[] args) {
        Animal ani = new Dog();
        ani.eat();

        ani = new Cat();
        ani.eat();
    }
}

상속체이닝(자신보다 부모가 먼저)

  • 맨 위 부모클래스 부터 객체가 생성되어 자식까지 연결

super()

  • 상위 클래스의 생성자를 호출하는 메서드
  • 생성자의 메서드에서 가장 첫 문장에 사용
  • 상위 클래스의 기본생성자를 호출하는 super()은 생략돼있음

메서드 재정의(Override)

  • 상속관계에서 하위 클래스가 상위 클래스의 동작을 재정의 하는 행위(기능 추가, 변경)

동적바인딩

  • 실행 시점에서 사용될 메서드가 결정되는 바인딩
package fc.java.model;

public class Dog extends Animal {
    public Dog(){
        super();
        int a =10;
    }
    //재정의(Override)
    public void eat(){
        System.out.println("개처럼 먹다.");
    }
}
package fc.java.model;

public class Cat extends Animal {
    public Cat(){
        super();
    }
    public void night(){
        System.out.println("밤에 눈에서 빛이 난다.");
    }
    public void eat(){
        System.out.println("고양이처럼 먹다.");
    }
}
package fc.java.part4;
import fc.java.model.*;
public class DogCatTest {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.eat();

        Cat c = new Cat();
        c.eat();
        c.night();
    }

}
package fc.java.part4;

import fc.java.model.Animal;
import fc.java.model.Dog;
import fc.java.model.Cat;
public class OverrideTest {
    public static void main(String[] args) {
        //Upcasting
        Animal ani = new Dog();
        ani.eat(); // Animal ---(동적바인딩)---> Dog
        ani = new Cat();
        ani.eat();// Animal ---(동적바인딩)---> Cat
    }
}

부모 자식 간 형 변환 가능

  • 부모는 여러 명의 자식을 가리킬 수 있음
  • 부모를 알면 자식을 관리하기 쉬움

Downcasting(다운 캐스팅, 강제 형 변환)

  • 상위클래스의 타입을 하위클래스의타입으로 바꾸는 행위
package fc.java.part4;
import fc.java.model.*;
public class ObjectCasting {
    public static void main(String[] args) {
        Animal ani = new Dog();
        ani.eat();

        ani=new Cat();  //업캐스팅
        ani.eat();
        ((Cat)ani).night();    //다운캐스팅
    }
}

다형성

  • 상위클래스가 동일한 메세지로 하위클래스를 서로 다르게 동작 시키는 객체지향 이론

<다형성 전제조건>

  1. 상속관계
  2. Override(재정의)
  3. 업캐스팅
  4. 동적 바인딩

다형성 인수 - 하나의 타입으로 여러가지 타입을 받을 수 있음. (부모이기 때문)

instanceof: 특정 타입이 어떤 타입으로 부터 생성이 되었는지 타입을 알아보는 연산자

상속관계에서 하위클래스들을 배열에 저장하기 위해서 생성해야하는 배열

다형성 배열, 상위타입 배열

package fc.java.part4;
import fc.java.model.*;
public class PolyTest {
    public static void main(String[] args) {
        //업캐스팅으로 객체 생성
        //상속관계, 재정의, 동적바인딩
        //다형성
        //상위클래스가 동일한 메세지로 하위클래스를 서로다르게 동작시키는 객체지향 원리

        Animal ani = new Dog();
        ani.eat();  // 실행시점에서 사용될(호출될)메서드가 결정되는 바인딩(동적 바인딩)

        ani=new Cat();
        ani.eat();
        //다운캐스팅
        ((Cat)ani).night();
    }
}
package fc.java.part4;

import fc.java.model.*;

public class PolyMethodTest {
    public static void main(String[] args) {
        Dog d= new Dog();
        display(d);
        Cat c = new Cat();
        display(c);
    }
    /* private static void display(Cat c){
        c.eat();
    }
    private static void display(Dog d){
        d.eat();
    } */

    private static void display(Animal ani) {
        ani.eat();
        if(ani instanceof Cat){
            ((Cat)ani).night();
        }

        //Cat타입으로 받은 경우에만 실행
        //((Cat)ani).night();
    }

}

다형성 배열(상위타입배열)

  • 배열은 동일한 자료형에만 저장 가능하지만 부모타입의 배열은 자식타입을 저장 가능(하나의 배열에 서로 다른 타입 저장 가능)
package fc.java.part4;
import fc.java.model.*;
public class PolyArrayTest {
    public static void main(String[] args) {
        Dog d = new Dog();
        Cat c = new Cat();
        //Dog, Cat을 저장할 배열 생성
        //Animal[] ani = {new Dog(), new Cat()};
        //2. 다형성배열
        Animal[] ani = new Animal[2];
        ani[0] = d;
        ani[1] = c;
        display(ani);
    }

    public static void display(Animal[] ani){
            for(int i =0;i<ani.length; i++){
                ani[i].eat();
                if(ani[i] instanceof Cat){
                    ((Cat)ani[i]).night();
                }
            }
        }
    }

다형성 보장?

→ 부모가 명령을 내리면 자식이 반드시 동작(반응)

→ Override(재정의) 하지 않으면 다형성이 보장 안됨

다형성 보장

  1. 다형성 전제조건 4가지 필수
  2. 반드시 재정의
  3. 부모클래스를 추상클래스로 만듦

추상메서드(불안전한 메서드)

→ 메서드의 구현부가 없는 메서드

→ 반드시 자식이 완전하게 재정의 해야 함

추상클래스?

  • 다형성을 일부 보장하기 위해 등장
  • 서로 비슷한 클래스의 공통 부분 묶을 때 사용
  • 단독으로 객체 생성 불가 //ex. Animal ani = new Animal();
  • 부모의 역할로 사용(업캐스팅)
  • 구현된 메서드를 가질 수 있다.
  • 재정의를 해야 동작이 됨 —> 일반클래스는 재정의 하지 않아도 동작은 됨(이상하게)
package fc.java.poly;

public abstract class Animal {
    public abstract void eat();
        public void move(){
            System.out.println("무리를 지어서 이동한다.");

    }
}
package fc.java.poly;

public class Cat extends Animal {
    public void night (){
        System.out.println("밤에 눈에서 빛이 난다.");
    }
    @Override
    public void eat(){
        System.out.println("고양이처럼 먹다.");
    }
}
package fc.java.poly;

public class Dog extends Animal {

    //재정의(Override)
    public void eat(){
        System.out.println("개처럼 먹다.");
    }
}
package fc.java.part4;

import fc.java.poly.*;

public class IsNotOverride {
    public static void main(String[] args) {
        //재정의를 안했기 때문에 -> 부모가 명령(메세지 보내면)을 내리면 오동작
        //다형성 보장x -> 다형성 보장하기 위해 재정의를 강제로 하도록 만듦
        //추상클래스, 인터페이스 등장
        //다형성이 보장 됨
        Animal ani = new Dog();
        ani.eat();

        ani=new Cat();
        ani.eat();
    }
}
package fc.java.part4;

import fc.java.poly.*;

public class AbstractClassTest {
    public static void main(String[] args) {
        Animal ani = new Dog();
        ani.eat();
        ani.move();

        ani=new Cat();
        ani.eat();
        ani.move();
        ((Cat)ani).night();
    }
}

인터페이스

  • 다형성 100% 보장하기 위해 등장
  • 서로 다른 클래스의 공통부분 묶을때 사용
  • 단독 객체 생성 불가
  • 부모의 역할로 사용
  • 추상메서드와 final static 상수만 가질 수 있음(멤버)
  • 구현된 메서드 가질 수 없음

다형성 보장하기 위해 등장한 클래스 - 추상클래스, 인터페이스

추상클래스: 추상메서드+구현메서드

인터페이스: 추상메서드+final statix 변수

<공통점>

  1. 다형성을 보장하기 위해 등장
  2. 추상메서드 가질 수 있음
  3. 단독 객체 생성 불가
  4. 부모의 역할로 사용(업캐스팅)

<차이점>

  1. 서로 비슷한 클래스의 공통 부분 묶을 때 사용: 추상 클래스

→ 추상 메서드와 구현 메서드 가질 수 있음

  1. 서로 다른 클래스의 공통 부분 묶을 때 사용: 인터페이스

→ 추상 메서드와 final static변수(상수)를 가질 수 있음

package fc.java.poly;

public interface RemoCon {
    public void chUp();

    public void chDown();

    public void volup();

    public void volDown();

    public void internet();
}
package fc.java.poly;

public class Radio implements RemoCon {
    @Override
    public void chUp() {
        System.out.println("Radio의 채널이 올라간다.");
    }

    @Override
    public void chDown() {
        System.out.println("Radio의 채널이 내려간다.");
    }

    @Override
    public void volup() {
        System.out.println("Radio의 채널이 올라간다.");
    }

    @Override
    public void volDown() {
        System.out.println("Radio의 채널이 내려간다.");
    }
    @Override
    public void internet() {
        System.out.println("Radio에서는 인터넷이 지원이 안됩니다.");
    }
    //chUp(), chDown(), volUp(), VolDown()

}
package fc.java.poly;

public class TV implements RemoCon {
    @Override
    public void chUp() {
        System.out.println("TV채널이 올라간다.");
    }

    @Override
    public void chDown() {
        System.out.println("TV채널이 내려간다.");
    }

    @Override
    public void volup() {
        System.out.println("TV채널이 올라간다.");
    }

    @Override
    public void volDown() {
        System.out.println("TV채널이 내려간다.");
    }
    @Override
    public void internet() {
        System.out.println("TV에서 인터넷 실행된다.");
    }
    //chUp(), chDown(), volUp(), VolDown()
}
package fc.java.part4;

import fc.java.poly.Radio;
import fc.java.poly.RemoCon;
import fc.java.poly.TV;

public class InterfaceTest {

    public static void main(String[] args) {
        //다형성 100%보장
        //부모가 인터페이스면 자식의 내부 동작 방식 몰라도 동작 시킬 수 있음
        RemoCon remo = new Radio();
        remo.chUp();
        remo.chDown();
        remo.volup();
        remo.volDown();
        remo.internet();

        remo=new TV();
        remo.chUp();
        remo.chDown();
        remo.volup();
        remo.volDown();
        remo.internet();

    }
}

Object클래스 이용해 객체 생성, 다형성 적용, toString메서드 활용 연습

package fc.java.poly;
import java.lang.*;
public class A extends Object {
    public A(){
        super();
    }
    public void display(){
        System.out.println("나는 A입니다.");
    }
    public void printGo(){
        System.out.println("나는 A입니다.");
    }
}
package fc.java.part4;

public class B {
    public void printGo(){
        System.out.println("나는 B입니다.");
    }
}
package fc.java.part4;
import fc.java.poly.*;
public class ObjectPolyArg {
    public static void main(String[] args) {
        A a=new A();
        display(a);
        B b=new B();
        display(b);

    }

    public static void display(Object obj){
        if(obj instanceof A){
            ((A)obj).printGo();
        }else{
            ((B)obj).printGo();
        }
    }
}
package fc.java.part4;
import fc.java.poly.*;
public class ObjectPolyArray {
    public static void main(String[] args) {
        Object[] obj=new Object[2];
        obj[0] = new A();
        obj[1] = new B();
        display(obj);
        /* for(int i=0; i<obj.length;i++){

            if(obj[i] instanceof A){
                ((A) obj[i]).printGo();
            }else{
                ((B) obj[i]).printGo();
            }
        } */
    }
    private static void display(Object[] obj){

    }
}
package fc.java.poly;

public class Board extends Object{
    private String title;
    public String getTitle(){
        return title;
    }

    public void setTitle(String title){
        this.title=title;

    }

    @Override
    public String toString() {
        System.out.println(super.toString());
        return "Board{" +
                "title='" + title + '\'' +
                '}';
    }
}
package fc.java.part4;

import fc.java.poly.Board;

public class ObjectToString {
    public static void main(String[] args) {
        Board b = new Board();
        b.setTitle("게시글 입니다.");
        System.out.println(b.toString());
        System.out.println(b);
    }
}

0개의 댓글