ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 객체지향프로그래밍 (자바의정석)
    Java 2021. 11. 22. 15:26

    객체의 생성과 사용
    - main메소드가 있는 클래스명과 소스파일명이 같아야 자동으로 실행됨

    public class Ex6_1 {
    	public static void main(String[] args) {
    		Tv t = new Tv();  // 참조변수 t에 Tv 인스턴스를 생성
    		t.channel = 7;    // 참조변수를 통해 변수사용
    		t.channelDown();  // Tv인스턴스의 channelDown 메소드 호출
    		System.out.println("현재채널=" + t.channel);
    	}
    
    }
    
    // Tv인스턴스 생성
    class Tv{
    	// 멤버변수 (속성)
    	String color;
    	boolean power;
    	int channel;
    	
    	// 기능(메소드)
    	void power() { power = !power; }
    	void channelUp() { ++channel; }
    	void channelDown() { --channel; }
    }

     

    • 객체배열
      - 객체 배열 == 참조변수 배열
      - 참조변수 여러개를 묶어서 하나의 배열에 넣는 것

     

    • 클래스의 정의

    1) 설계도              --> Tv 객체로 이해

    2) 데이터 + 함수

    3) 사용자 정의 타입

    이렇게 3가지로 정의할 수 있음

    데이터 + 함수 관점                                                       사용자정의 타입 관점

     

    // 비객체지향적 코드
    int hour = 12;
    int minute = 34;
    int second = 12
    
    // 객체지향적 코드 -> 동일한 기능이지만 코드가 깔끔하고 유지보수 용이
    class Time{
    	int hour;
    	int minute;
    	int second;
    }
    
    Time t = new Time();
    t.hour = 12;
    t.minute = 34;
    t.second = 56;

     

    • 선언위치에 따른 변수의 종류
    class Variables{
    	int iv;         // 인스턴스 변수 : 객체생성을 해야지만 사용 가능
    	static int cv;  // 클래스변수 : 아무때나 사용 가능
    	
    	void method() {
    		int lv = 0;  // 지역변수 : 메소드 한번 실행되면 자동 삭제
    	}
    	
    	// 객체란 iv변수들을 묶어놓은 것 --> 객체를 만들면 iv들이 생성됨
    }

    - 클래스변수 vs 인스턴스 변수

    1) 객체의 속성 중 개별 객체마다 갖는 특성은 인스턴스 변수

    2) 모든 객체가 갖는 공통의 속성은 클래스 변수 

    (속성 중에서 공통적으로 유지되어야 하는 속성에 static 붙이면 됨)

    - 클래스변수는 클래스이름을 붙이고 쓰는 것을 권장 (참조변수로 해도 실행은 됨)

     

     

    • 기본형 매개변수 vs 참조형 매개변수  - 강의 다시보기

    기본형 매개변수: 변수의 값을 읽을수만 있음 (read only)

    참조형 매개변수: 변수 값을 읽고 변경할 수 있음 (read & write)

    // 참조형 매개변수
    class Data2 {int x;}
    
    public class Ex06
    
        public static void main(String[] args)
        {
            Data2 d = new Data2();
            d.x = 10;
            System.out.println("main() : x = " +d.x);
    
            change(d);
            System.out.println("After change(d)");
            System.out.println("main() : x = " +d.x);
        }
        static void change(Data2 d){ // 참조형 매개변수
            d.x = 1000;
            System.out.println("change() : x = " +d.x);
        }
    }
    //예시2
    
    class Data2 {int x;}
    
    class Ex06{
    
        public static void main(String[] args)
        {
            Data3 d = new Data3();
            d.x = 10;
            
            Data3 d2 = copy(d);
            System.out.println("d.x= " +d.x);
            System.out.println("d2.x = " +d2.x);
        }
    
        static Data3 copy(Data3 d){ // 참조형 매개변수
           Data3 tmp = new Data3();
           tmp.x = d.x;
           return tmp;
        }
    }

    결과1: 

    main() : x = 10

    change() : x = 1000

    After change(d)

    main() : x = 1000

     

    결과2:

    d.x = 10

    d2.x = 10

     

     

     

    • static메서드 vs 인스턴스 메서드
      - iv(인스턴스 변수) 사용여부로 갈림

    1) 인스턴스 메서드

    - 인스턴스 생성 후, '참조변수.메서드이름()' 으로 호출

    - 인스턴스 멤버(iv,im)와 관련된 작업을 하는 메서드

    - 메서드 내에서 인스턴스변수(iv) 사용 가능

     

    2) static메서드

    - 객체생성 없이 '클래스이름.메서드이름()'으로 호출

    - 인스턴스멤버(iv,im)와 관련 없는 작업을 하는 메서드

    - 메서드내에서 인스턴스변수(iv) 사용 불가

    class MyMathe2{
    	long a, b;      // 인스턴스변수 : 클래스전체에서 사용 가능
        
        long add(){     // 인스턴스메서드
        	return a+b;
         }
    
    	static long add(long a, long b) {   // static 메서드
        	return a+b;  
        }
    }
    
    // 메소드 호출
    class MyMathTest2{
    
        public static void main(String[] args){
            System.out.println(MyMath2.add(200L, 100L));  // static메서드는 객체생성없이 클래스명으로 호출
    
            MyMath2 mm = new MyMath2(); // 인스턴스 생성
            mm.a = 200L;
            mm.b = 100L;
            System.out.println(mm.add());  // 인스턴스메서드 호출
        }
    }

    Q. 언제 static붙여야 할까?

    - 인스턴스 멤버를 사용하지 않는 메서드에 static을 붙인다

    (멤버 변수의 경우에서는 공통 속성에 static을 붙이는데 메소드는 개념이 다름)

    class MyMath2{
    	long a,b;
        
        long add() {return a+b;}  // a,b는 인스턴스 변수
        static long add(long a, long b) {return a+b;} // a,b는 지역변수
        
    }

     

     

    Q. static메소드는 static메서드 호출 가능?

     yes 

     

    Q. static메소드는 인스턴스 변수 사용 가능?

     no

      - 인스턴스변수는 객체를 생성해야지 사용가능한데, static메소드는 언제가 호출 가능하기 때문에

     

    Q. static메소드는 인스턴스 메소드 사용 가능?

    no

     

    Q. 왜 static메서드는 인스턴스 멤버를 쓸수 없나요?

    static메서드는 객체생성 없이 사용가능한 반면 인스턴스 멤버는 객체를 생성해야지만 활용 가능

    따라서 static메소드 호출 시 객체(iv묶음)가 없을수도 있어서

     

     

    • 오버로딩
      한 클래스 안에 같은 이름의 메서드를 여러 개 정의하는 것
      - 메소드 하나로 여러개의 기능을 수행할 수 있음
      - 매개변수는 다르지만 같은 의미의 기능을 수행 (하는 작업은 동일함)

    대표 예) println  --> 하나의 메소드로 char형 출력, double형 출력 등 여러 형태의 문자열을 출력 가능함

     

    <오버로딩이 성립하기 위한 조건>

    1. 메서드 이름이 같아야함

    2. 매개변수의 개수 or 타입이 달라야 함

    3. 반환 타입은 영향 없음

     

    • 생성자(constructor)
      - 인스턴스가 생성될 때마다 호출되는 인스턴스 초기화 메서드
    Time t = new Time();   // 1. 객체 생성
    t.hour = 12;
    t.minute = 34;
    t.second = 56;  // iv초기화
    
    // 생성자로 한번에 수행 가능
    Time t = new Time(12,34,56);
    
    
    클래스이름(타입변수명, 타입변수명...){
    	// 인스턴스 생성 시 수행될 코드
        // 주로 인스턴스 변수의 초기화 코드를 적는다
    }

    < 생성자의 조건>

    1. 생성자 이름이 클래스 이름과 같아야 함

    2. 리턴값이 없다 

    3. 모든 클래스는 반드시 생성자를 가져야 함

    // 예시
    class Car{
    	String color;
        String gearType;
        int door;
        
        Car(){} // 기본생성자
        Car(String c, String g, int d) { // 매개변수가 있는 생성자
        	color = c;
            gearType = g;
            door = d;
        }
    }
    
    // 생성자를 호출하여 인스턴스 변수 초기화
    Car c = new Car("white", "auto", 4);

     

    • 생성자 this()
      - 생성자에서 다른 생성자를 호출할 때 사용
      - 다른 생성자 호출 시 첫줄에서만 사용 가능
    class Car{
    	String color;
        String gearType;
        int door;
        
        Car(){
        color = "white";
        gearType = "auto";
        door = 4;
        }
        
        Car(String c, String g, int d) { // 매개변수가 있는 생성자
        	color = c;
            gearType = g;
            door = d;
        }
        
        // this()생성자를 사용하여 코드의 중복 제거
        Car(){
        	this("white", "auto", 4);
        }
    }

     

    • 참조변수 this
      - 인스턴스 자신을 가리키는 참조변수
      - 지역변수(lv)와 인스턴스변수(iv) 이름이 동일할 때 둘을 구별하기 위해 사용
      - this가 붙으면 인스턴스변수
      - 인스턴스메소드 에서만 활용 가능 / static메소드는 불가

     

    class MyMath2{
    	long a, b;  // this.a, this.b : 진짜이름 but this생략 가능
        
        MyMath2(int a, int b){
        	this.a = a;  // iv와 lv의 이름이 동일하므로 구별하기 위해 iv에 this사용
            this.b = b; 
        }
        
        long add(){
        	return a+b;  // return this.a + this.b
        }
    }

     

    • 상속관계

     

    • 포함관계
      - 클래스의 멤버로 참조변수를 선언하는 것
      - 작은단위의 클래스를 만들고, 이들을 조합해서 클래스를 만든다

    Q. 언제 상속을 쓰고 언제 포함관계를 써야하나?

     - 문장을 만들어보기 (절대적인것은 아님) 

     - 상속은 제약사항이 많기 때문에 대부분 90%은 포함관계를 사용함

     

     

    - 예제

    // 상속관계
    class MyPoint {
    	int x;
    	int y;
    }
    
    class Circle extends MyPoint{
    	int r;  
    }
    
    public class InheritanceTest{
    	public static void main(String[] args) {
    		Circle c = new Circle();
    		c.x = 1;
    		c.y = 2;
    		c.r = 3;
    	}
    	
    }

     

    // 포함관계
    class MyPoint {
    	int x;
    	int y;
    }
    
    class Circle {
    	MyPoint p = new MyPoint(); // 참조변수의 초기화
    	int r;  
    }
    
    public class InheritanceTest{
    	public static void main(String[] args) {
    		Circle c = new Circle();
    		c.p.x = 1;
    		c.p.y = 2;
    		c.r = 3;
    	}
    	
    }

     

    • 단일상속
      - Java는 단일상속만 허용
      - 비중이 높은 클래스 하나만 상속관계로, 나머지는 포함관계로 
      - 인터페이스를 활용하면 다중상속과 같은 효과를 낼 수 있음

     

    • Object클래스  - 모든 클래스의 조상

    1) 부모가 없는 클래스는 자동적으로 object클래스를 상속받게 됨 (컴파일러가 자동 추가)

    2) 모든 클래스는 object클래스에 정의된 11개의 메서드를 상속받음

    ex. toString, equal 등..

     

     

    • 오버라이딩
      - 상속받은 부모클래스의 메소드를 자신에 맞게 변경하는것
      - 선언부는 변경X  /  내용( 구현부 { } )만 변경 가능
    class MyPoint {
    	int x;
    	int y;
    	String getLocation() {
    		return "x:"+x+", y:"+y;
    }
    
    class MyPoint3D extends MyPoint {
    	int z;
    	
    	// 부모의 getLocation을 오버라이딩
    	String getLocation() {
    		return "x:"+x+", y:"+y+", z:" + z;
    	}
    }
    
    public class OverrideTest{
    	public static void main(String[] args) {
    		MyPoint3D p = new MyPoint3D();
    		p.x = 1;
    		p.y = 2;
    		p.z = 3;
    		System.out.println(p.getLocation());
    	}
    }

     

    - Object클래스의 toString 활용  &  앞에서 배운 생성자를 활용하여 변수초기화

    class MyPoint3 extends Object {
    	int x;
    	int y;
    	
    	// 생성자
    	MyPoint3(int x, int y){
    		this.x = x;
    		this.y = y;
    	}
    	
    	// Object클래스의 toString을 오버라이딩
    	String toString() {
    		return "x:"+x+", y:"+y;
    	}
    }
    
    public class OverrideTest{
    	public static void main(String[] args) {
    		MyPoint3 p = new MyPoint3(3, 5);
    		// p.x = 3; 
    		// p.y = 5
    		System.out.println(p);              // 둘은 동일함
    		System.out.println(p.toString());
    	}
    }

     

    • 오버라이딩의 조건

    1) 선언부가 부모 클래스의 메서드와 일치해야한다

    2) 접근제어자를 부모클래스의 메서드보다 좁은 범위로 변경할 수 없다

    3) 예외는 부모클래스의 메서드보다 많이 선언할 수 없다

     


     

    <ch 7-10,11>

    • 참조변수 super / 생성자 super()

    1) 참조변수 super
    -  객체 자신을 가리킴. 인스턴스메소드(생성자) 내에서만 존재

    - 부모 멤버와 자신 멤버를 구별할때 사용 

    참고) this는 lv와 iv구별에 사용

     

    변수의 이름이 같아도 상속은 가능,

    부모 변수에는 super

    자식 변수에는 this 를 붙여서 구분함

    class Super{
    	public static void main(String args[]) {
        Child c = new Child();
        c.method();
        }
    }
    
    class Parent{ int x = 10; } // super.x
    
    class Child extends Parent{
    	int x = 20;  // this.x
        
        void method(){
        	System.out.println("x=" + x);
            System.out.println("this.x=" + this.x);
            System.out.println("super.x=" + super.x);
        }
    }

    실행결과

    x=20

    this.x = 20

    super.x = 10

     

     

    2) 생성자 super()

    - 부모의 생성자를 호출할때 사용

    - 부모의 멤버는 부모의 생성자를 호출해서 초기화

    (생성자와 초기화블럭은 상속이 불가하므로

    자손이 부모의 멤버까지 초기화 할 수는 없음)

    --> 자손클래스에서 부모클래스 생성자를 호추

    부모클래스에서 선언한 멤버를 초기화하려면 자손이 직접 하는것이 아니라

    부모의 생성자를 호출해서 부모생성자가 직접 부모 멤버를 초기화 하도록 하는 것

     

     

     ** 중요한 규칙) 모든 생성자는 첫줄에 다른 생성자를 호출해야 한다 (기본생성자 생성은 필수!!!)

    그렇지 않으면 컴파일러가 super()를 자동으로 생성해줌

     

    super를 지정하지 않아서 기본생성자인 point()를 자동 호출했는데 Point클래스에 기본생성자 point()가 없어서 에러가 발생함

     

    기본생성자를 호출하지 않도록 super(x,y)를 통해 부모생성자 호출

     


     

    <ch7-12,13,14>

    • 패키지
      - 서로 관련된 클래스의 묶음
      - 클래스는 클래스파일( *.class ) / 패키지는 폴더 / 하위패키지는 하위폴더
      - 클래스의 실제 이름은 패키지를 포함 (java.lang.String)
      - rt.jar 는 클래스 파일들을 압축한 파일 

    • 클래스패스
      - 클래스 파일 (*.class)의 위치를 알려주는 경로
      - 환경변수 classpath로 관리하며, 경로간의 구분자는 세미콜론 ; 사용
      - classpath에 패키지의 루트를 등록해줘야함

    ==> 이클립스가 자동으로 해주기 때문에 크게 신경쓸 필요 없음

     

     

    <ch 7-15,16>

    - import문은 컴파일 시에 처리되므로 프로그램 성능에 큰 영향 없음

    import java.util.Calendar;

    import java.util.Date;

    import java.util.ArrayList;

    →  import java.util.*  이렇게 써도 상관없음

     

    - static import문
     : static 멤버를 사용할 때 클래스의 이름을 생략할 수 있게 해준다

    --> 클래스이름을 생략가능하므로 코드의 복잡성을 줄일 수 있음

     


     

    <ch 7-17~20>

    • 제어자 (modifier)
      -
      클래스와 클래스의 멤버(멤버변수, 메서드)에 부가적인 의미 부여

    1) static 제어자

    대상 의미
    멤버변수 - 모든 인스턴스에 공통적으로 사용되는 클래스 변수가 된다
    - 클래스변수는 인스턴스를 생성하지 않고도 사용 가능하다
    - 클래스가 메모리에 로드 될때 생성된다
    메서드 - 인스턴스를 생성하지 않고도 호출이 가능한 static 메서드가 된다
    - static 메서드 내에서는 인스턴스 멤버들을 직접 사용할 수 없다

    iv멤버들은 객체를 만들고 나서야 가능한데, static 멤버와 static메서드는 객체 호출 없이도 사용가능하므로

    static메서드 내에서는 인스턴스(iv)멤버들을 사용할 수 없음

     

     

    2) final 제어자

    대상 의미
    클래스 변경될 수 없는, 확장될 수 없는 클래스가 된다 
    --> final로 지정된 클래스는 다른 클래스의 조상(부모)가 될 수 없음
    메서드 변경될 수 없는 메서드
    --> final로 지정된 메소드는 오버라이딩을 통해 재정의 될 수 없음
    멤버변수 변수 앞에 final이 붙으면 값을 변경할 수 없는 상수가 된다
    지역변수

     

    3) abstract 제어자

    클래스 클래스 내에 추상메서드가 선언되어 있음을 의미
    메서드 선언부만 작성하고 구현부는 작성하는 않은 추상메서드임을 의미

    추상클래스는 미완성 설계도라고 보면 됨 --> 제품 생성이 불가

    따라서  AbstractTest a = new AbstractTest();   // 에러. 추상클래스의 인스턴스는 생성불가

     

    상속을 받아 추상클래스를 완성시켜주어야 인스턴스 생성(객체 생성)이 가능함

     


     

     

    <ch 7-21>

    • 접근 제어자 (access modifier)

    1) private : 같은 클래스 내에서만 접근이 가능

    2) default : 같은 패키지 내에서만 접근이 가능

    3) protected : 같은 패키지 내에서 + 다른 패키지의 자손클래스에서 접근이 가능

    4) public : 접근제한이 전혀 없다

     

    public            >  protected          > default      >  private

    (접근제한 없음)  (같은패키지+자손)  (같은패키지)  (같은클래스)

     

     

    예제)

    범위

     


     

    <ch 7-22>

    • 캡슐화
      - 접근제어자를 사용하는 이유
      1) 외부로부터 데이터를 보호하기 위함
      2) 외부에는 불필요한, 내부적으로만 사용되는 부분을 감추기 위해서

     

    getHour와 setHour 의 메소드를 통해서 멤버변수에 접근/수정 --> 데이터를 보호함

     

     

    예제) 

    hour는 0~23사이의 값을 가져야하기 때문에 잘못된 값이 입력되는 것을 방지하기 위해

    접근제어자로 캡슐화를 진행

    class Time{
    	private int hour;
        private int minute;
        private int second
        
    	// setter를 통해서 값을 수정(직접호출,수정X)
    	public void setHout(int hour){
        	if(hour<0 || hour>23) return
            this.hour = hour;
        }
        
        // getter를 통해서 값을 호출
        public int getHour() { return hour; }
    }
    
    public class TimeTest{
    	public static void main(String[] args){
        	Time t = new Time();
            // t.hour = 100;      // 이상한 값을 바로 입력X
            
            t.setHour(21);		  // hour값을 21로 변경
            System.out.println(t.getHour()) // 값을 얻고, 출력
        }
    }

    접근제어자의 범위는 최소한 좁히고, 필요할 때 넓히는 것이 좋다

    -> 프로그램 테스트 할때 깨진 부분을 확인할때 최소한의 범위만 확인할 수 있으므로 (..?)

     


    < ch7-23 >

    다형성을 이해하지 못하면 추상클래스/인터페이스를 이해하지 못함. 꼭 이해하고 진도 넘어갈것!

    • 다형성
      - 조상 타입 참조변수로 자손타입 객체를 다루는 것
      -   Tv t = new SmartTv();   // 조상클래스인 Tv와 그 참조변수 t로 자손타입인 SmartTv를 다룬다
      - 즉, 참조변수와 클래스객체의 타입이 불일치

    예시)

    smartTv extends Tv( ){ ~~ }

     

     

               1. 참조변수와 인스턴스 타입이 일치                               2. 조상타입 참조변수로 자손타입 인스턴스 참조
                   smartTv s = new smartTv( );                                                    Tv t = new SmartTv( ) ;

    smartTv 객체는 리모콘(s) 를 통해서 7개의 모든 기능을 사용 가능     Tv 리모콘은 5개버튼(Tv클래스에 정의된 5개 멤버)

    (5개는 부모클래스인 Tv 객체이고 2개는 자손인 smartTv의 객체)       밖에없음. 그래서 실제제품 smartTv객체가 7개

                                                                                             멤버를 갖고있다 하더라도 실제 사용할 수 있는                                                                                             것은 Tv클래스에 정의된 5개뿐 - 버튼이 5개니깐!!

     

    ** 인스턴스에 기능이 아무리 많더라도 리모콘에 버튼이 없으면 리모콘 버튼 갯수만큼의 기능만 사용할수 있음

       일부만 사용 가능.

     

    • 다형성의 특징
      - 자손타입 참조변수로는 조상타입 객체를 가리킬수 없음
      - Tv t  = new smartTv( ) // 가능
      - smartTv s = new Tv( )  // 불가 
          --> 실제 갖고있는 기능보다 리모콘 버튼의 개수가 더 많으면 없는 기능을 호출하므로 에러가 발생 
          --> 기능이 있는데 안쓰는건 괜찮지만 없는 기능을 호출해서 쓰는건 불가능

     


     

    < ch 7-24, 25 >

    • 참조변수의 형변환
      - 사용할 수 있는 멤버의 개수를 조절하는 것 (값이 달라지는 것이 아님!)
      - 조상, 자손 관계의 참조변수 일때만 서로 형변환 가능

     

    ** 참조변수가 가르키는 "실제객체"의 멤버변수 개수가 중요

    -> 실제객체의 멤버변수 개수보다 참조변수의 객체 멤버가 더 많아서는 안됨

     

    예제)

     

    참조변수 c가 가르키는 실제객체인 Car가 가진 멤버변수 4개

    c를 자손인 FireEngine으로 형변환은 가능하나, (컴파일은ok)

    fe참조변수의 멤버변수 개수가 (5개) 실제객체의 멤버변수(4개) 보다 더 크므로 

    에러가 발생함!! - 중요

     


    < ch 7-26 > 

    • instanceof 연산자
      - 참조변수의 형변환 가능여부 확인에 사용. 가능하면 true반환
      - 형 변환시에는 반드시 instanceof로 가능 여부를 확인해야 한다

    Q. 참조변수 형변환을 하는 이유는?

    - 참조변수(리모콘)을 변경함으로써 사용할 수 있는 멤버의 개수를 조절하기 위해서

     

    원래 참조변수 f 가 다룰수 있는 멤버는 5개였으나 Car로 형변환 함으로써 다룰 수 있는 멤버가 4개로 줄어듦 (water메소드 사용 불가)

     

    Q. instanceof연산자는 언제 사용하나요?

    참조변수를 형변환 하기 전에 가능 여부를 확인할 때 사용

     


    < ch 7- 27,28 >

     

    다형성의 장점

    1) 다형적 매개변수

    2) 하나의 배열로 여러종류의 객체 다루기

     

    • 매개변수의 다형성 (다형적 매개변수)
      - 참조형 매개변수는 메서드 호출 시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다

     

    예제)  --> 직접 작성하면서 복습할것

     

    'Java' 카테고리의 다른 글

    예외처리  (0) 2021.11.25
    객체지향 퀴즈  (0) 2021.11.24
    배열  (0) 2021.11.22
    정렬알고리즘  (0) 2021.11.22
    do-while문  (0) 2021.11.22

    댓글

Designed by Tistory.