자바수업 7일차

한 일

  • 메서드 오버로딩
  • 디폴트 생성자
  • this()
  • 변수의 초기화
  • super()
  • gui
  • 추상클래스
  • 인터페이스
  • 인터페이스의 구현
  • 인터페이스 Default 메소드
  • 인터페이스 다중구현

메서드 오버로딩 Ch12_Constructor

  • 자바의 한 클래스 내에 사용하려는 이름과 같은 이름의 메서드가 이미 있더라도 매개변수의 개수 또는 타입이 다르면 같은 이름을 사용해 메서드를 정의할 수 있다.
  • 조건 : 메서드의 이름이 같고 매개변수가 다를 때
  • 메서드는 이름과 매개변수가 모두 같아야 같은 메소드이다
    (= 이름이 같아도 매개변수가 다르면 다른 메소드)

Person.class

public class Person {
	// 이름이 같은 greet메소드가 2개, 매개변수가 다름(같은땐 에러)
	// 매개변수가 다르면 다른 메소드임
	public void greet() {
		System.out.println("헬로우!");
	}
	public void greet(String name) {
		System.out.println("헬로우~" + name);
	}
	public void greet(int height) {
		if(height > 185) {
			System.out.println("키가 크군요!");
		}
		System.out.println("안녕~!");
	}
	public void greet(String name, int height) {
		if(height > 185) {
			System.out.println("키가 크군요!");
		}
		System.out.println("안녕~! " + name);
	}
}

App.class

public class App {
	public static void main(String[] args) {
		// 메소드 오버로딩 : 메소드의 이름은 같지만 매개변수가 다를때
		// 메소드는 이름과 매개변수가 모두 같아야 동일한 메소드임
		Person p = new Person();
		p.greet();			// 매개변수 없음
		p.greet("펭수");		// 매개변수 문자열
		p.greet(175);		// 매개변수 정수형
		p.greet("펭순이", 190);	// 매개변수 문자열, 정수형
		System.out.println(123);	// 매개변수 정수
		System.out.println(1.23);	// 매개변수 실수
		System.out.println("123");	// 매개변수 문자열
	}
}

~ 오버로딩과 오버라이딩 ~

오버로딩 (overloading)

  • 자바의 한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메서드가 있더라도 매개변수의 개수 또는 타입이 다르면 같은 이름을 사용해 메서드를 재정의 할 수 있다.
  • 목적 : 이름이 같은 여러 개의 메서드를 중복 선언하여 사용의 편의성 향상.
  • 조건 : 메서드의 이름이 같고, 매개변수의 개수나 타입이 다를 때.
  • 관계 : 동일한 클래스 내 혹은 상속관계.
  • 기존에 없던 새로운 메서드를 정의하는 것. (new)

오버라이딩 (overriding)

  • 부모 클래스(슈퍼 클래스)로부터 상속받은 메서드를 자식 클래스(서브 클래스)에서 재정의하는 것.
  • 상속받은 메서드를 자식 클래스에서 상황에 맞게 변경해야하는 경우 사용.
  • 목적 : 부모 클래스에 구현된 메소드를 무시하고 자식 클래스에서 새로운 기능의 메서드를 재정의함. 코드의 재사용성이 높다.
  • 조건 : 자식 클래스에서 오버라이딩 하고자 하는 메소드의 이름, 매개변수, 리턴 값이 모두 같아야 함.
  • 관계 : 상속 관계.
  • 상속받은 매서드의 내용을 변경하는 것. (change)

디폴트 생성자

  • 매개변수와 내용이 없는 간단한 생성자.
  • 원래는 모든 클래스에 반드시 하나의 생성자가 정의되어있어야 하지만, 컴파일러가 제공하는 '기본 생성자(default constructor)'덕에 직접 정의하지 않아도 인스턴스(객체)를 생성할 수 있었던 것임.
  • 생성자가 없을 때 자동적용됨, 생성자가 하나 이상 있으면 적용되지 않음.
  • 형태: 클래스이름(){} : 굳이 작성해줄 필요 없이 컴파일러가 알아서 자동제공.

~ 생성자 ~ (4일차 참고)

이름이 클래스의 이름과 같고 리턴값이 없는 메서드.

default constructor 예제 1

package default_Constructor;
public class Person {
	private String name;	// 이름변수
	private int age;		// 나이변수
	
	public Person() {		// 나이이름을 둘 다 모를때 사용할 기본생성자
		System.out.println("디폴트 생성자로 생성됨");
		name = "모름";
		age = 0;
	}
	
	public Person(String name) {	// 생성자는 클래스 이름과 같고 리턴타입이 없음
		// 이름만 알 때
		System.out.println("새 person이 생성됨");
		this.name = name;
		age = 0;
		// ㄴ앞의 name은 private name의 name, 뒤의 name은 public Person(String name) 의 name
	}
	public Person(String name, int age) {	// 이름과 나이가 동시에 들어가는 메소드
		// 둘 다 알 때
		System.out.println("새 person이 생성됨");
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {		// 객체의 정보를 출력한다
		return "Person [이름= " + name + ", 나이= " + age + "]";
	}
}
package default_Constructor;
public class App {
	public static void main(String[] args) {
		// 디폴트 생성자 : 생성자가 없을 때 적용됨, 생성자가 있으면 더 이상 적용안됨
		Person p1 = new Person();	// p1은 기본생성자
		System.out.println(p1);		// toString메소드가 생략되어있음
		Person p2 = new Person("펭수");	// 이름만 알 때
		System.out.println(p2);
		Person p3 = new Person("라이언", 5);	// 둘 다 알때
		System.out.println(p3);
	}
}

default constructor 예제 2

class Data_1 {
	int value;
}
class Data_2 {
	int value;
	
	Data_2 (int x) {    // 매개변수가 있는 생성자를 만들었으므로 기본생성자는 적용되지 않음.
		value = x;
	}
}
public class Ex6_11 {
	public static void main(String[] args) {
		Data_1 d1 = new Data_1();
//		Data_2 d2 = new Data_2();	// 컴파일 오류발생. 
		Data_2 d2 = new Data_2(10);
        	// 매개변수가 있는 생성자이므로 인스턴스(객체) 생성시에도 매개변수 반드시 필요.	
	}
}

this()

  • 현재 클래스의 생성자를 가리킴.
  • 목적: 현재 클래스에 정의된 생성자들이 서로를 호출할 때 사용.
  • 조건
    1) 생성자의 이름으로 클래스이름 대신 this를 사용.
    2) 한 생성자에서 다른 생성자 호출 시 반드시 첫 줄에서만 호출가능.
  • 사용: this(), this(매개변수1, 매개변수2 ...)
package this_Constructor;
public class Person {
	private String name;
	private int age;	
	
	public Person() {	
		// this() 는 현재 클래스의 생성자를 가리킨다
		this("익명", 0);	// 이름과 나이 즉, 매개변수가 2개이므로 아래의 public Person(String name, int age)를 가리킨다
	}
	public Person(String name) {	// 이름만 알 때
		this(name, 0);	// 마찬가지로 매개변수가 2개이므로 아래의 public Person(String name, int age)를 가리킨다
	}
	public Person(String name, int age) {	// 둘 다 알 때
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {		// 객체의 정보를 출력한다
		return "Person [이름= " + name + ", 나이= " + age + "]";
	}
}
package this_Constructor;
public class App {
	public static void main(String[] args) {
		// this() 생성자
		Person p1 = new Person();
		System.out.println(p1);
		Person p2 = new Person("펭수");
		System.out.println(p2);
		Person p3 = new Person("라이언", 5);
		System.out.println(p3);
	}
}


~ this ~

객체 자신을 가리키는 참조변수.
현재클래스의 멤버변수를 지정할때 사용한다.

변수의 초기화

  • 변수를 선언하고 처음 값을 선언하는 것.
  • 멤버변수(클래스 변수와 인스턴스 변수)와 배열의 초기화는 선택이지만,
    지역변수의 초기화는 필수임!
    => 지역변수는 초기화 하지 않으면 사용불가.
class InitTest {
	// 인스턴스 변수 x 선언, y 선언 및 초기화 
	int x;	
	int y = x;	// y를 선언하는데 초기화되지 않은 인스턴스 변수 x 사용가능
	// 멤버변수는 초기화할 떄 초기화가 안 된 인스턴스 변수를 사용할 수 있다.
	void method1() {
		// 지역변수 i 선언, y 선언 및 초기화
		int i;	
//		int j = i;	// 에러 발생.
		// 지역변수는 초기화를 시켜주지 않으면 사용할 수 없다. 
	}
}

멤버변수의 초기화

  • 지역변수와 달리 멤버변수는 각 타입의 기본값으로 자동 초기화됨.

super()

  • this()처럼 super()도 생성자임.
  • 자식 클래스가 자신을 생성할때 부모 클래스의 생성자를 불러 초기화할 때 사용.
    => 조상의 생성자를 호출할 때 사용.
  • 기본적으로 자식 클래스의 생성자에 추가되어있음(평소엔 생략됨)

Person.class

package super_constructor;
public class Person {
	private String name;
	public Person(String name) {
		System.out.println("Person 생성자");
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String toString() {
		return name;
	}
}

Employee.class

package super_constructor;
public class Employee extends Person {	// Person을 상속받음
	public Employee() {
		super("익명");	// 부모클래스의 생성자, 평소에는 생략되어있음
		// ㄴ부모클래스의 생성자에 매개변수가 있기때문에 super에도 매개변수를 넣어줘야 오류가 안남
		System.out.println("Employee 생성자");
	}	// 이렇게되면 부모클래스의 생성자(Person)를 먼저 실행항 후 Employee의 생성자가 실행됨
	public Employee(String name) {
		super(name);
		System.out.println("Employee 생성자");
	}
}

App.class

package super_constructor;
public class App {
	public static void main(String[] args) {
		// super() 생성자
		Employee e1 = new Employee();
		System.out.println(e1);

		Employee e2 = new Employee("김펭수");
		System.out.println(e2);
	}
}

~ super ~

  • 자식 클래스에서 부모 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수.
  • 멤버변수와 지역변수의 이름이 같을 때 this를 사용해 구별하듯 상속받은 멤버와 자신의 멤버가 이름이 같을 때 super를 붙여 구분할 수 있다.
public class Ex7_2 {
	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() {  // 부모클래스의 int x와 자식클래스int x의 이름이 같음
		System.out.println("x = " + x);
		System.out.println("this.x = " + this.x);
		System.out.println("super.x = " + super.x);
	}
}

gui

App.class => 스윙 앱을 실행

public class App {
	public static void main(String[] args) {
		SwingUtilities.invokeLater(() -> {	// 프로그램의 안정성을 위해 권장하는 코드. 이 코드블럭안에 코드를 넣어준다.
			new MainFrame("테스트 스윙 앱");	// 새 창 생성
		});
	}
}

MainFrame.class => 프레임을 생성

public class MainFrame extends JFrame{
	public MainFrame(String title) {
		super(title);
		
		setLayout(new BorderLayout()); // 창에 컴포넌트(버튼들)을 붙이기 위함
		
//		JPanel panel = new JPanel();	// JPanel 패널을 생성 => MainPanel으로 옮김
//		panel.setBackground(Color.LIGHT_GRAY);	// 패널 색 지정 => MainPanel으로 옮김
		add(new MainPanel(), BorderLayout.CENTER);	// 메인프레임에 붙이기 (중앙 가운데 위치)
		
		setSize(600, 400); // 창 사이즈 설정
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 창 닫으면 프로그램 종료
		setVisible(true);  // 창 보이게 설정변경
	}
}

MainPanel.class => 패널을 생성

public class MainPanel extends JPanel {
	private static final long serialVersionUID = 1L;
	
	public MainPanel() {
		setBackground(Color.lightGray); // 패널 색 설정
	}
}

추상 클래스

  • 선언부만 작성하고 구현부는 작성하지 않은 채로 남겨둔 클래스.
    (클래스는 설계도, 추상 클래스는 미완성 설계도와 유사함)
  • 세부사항은 다르되 큰 틀은 동일할 때 사용하기 위함.
  • 키워드 : abstract
  • 추상 클래스는 new를 통해 객체(인스턴스)를 직접 생성할 수 없다.
  • 추상 클래스에 선언된 추상 메소드는 상속받은 하위 클래스에 강제적으로 구현하도록 한다.

추상 메서드

  • 선언부만 작성하고 구현부는 미구현된 메서드.
  • 설계만 있고 실제 수행될 내용이 빠져있음.
  • 메서드의 내용이 상속받는 클래스에 따라 달라질 수 있으므로 부모 클래스에는 선언부만 작성, 실제 내용은 자식 클래스에서 완성한다.
  • 키워드 : abstract
  • 구현부가 없으므로 코드블럭{} 대신 문장의 끝을 알리는 ;을 붙여줌.

App.class

public class App {
	public static void main(String[] args) {
		// 추상 클래스
		
//		GameObject obj = new GameObject();	// 추상 클래스는 객체를 만들 수 없다
		GameObject[] objs = { new Player(), new Monster() };
		
		for(GameObject ob : objs) {
			System.out.println(ob);		// toString()받은게 없으므로 주소값이 출력됨
			ob.describe();		// 구현된 추상 메소드	
			// ㄴ추상 메소드로 GameObject에는 이름만 있고 자식클래스인 Monster와 Player에서 코드를 작성해줌 
		}
	}
}

GameObject.class

public abstract class GameObject {	// 추상클래스는 클래스앞에 abstract를 붙임
	public abstract void describe();
    	// ㄴ 추상 메소드는 메소드 몸체(내부 코드)이 없다 => 상속받은 클래스에서 작성	
}

Monster.class

public class Monster extends GameObject {
	@Override
	public void describe() {
		System.out.println("몬스터입니다.");
        		// 부모클래스에서 미구현된 메서드를 자식클래스에서 구현
	}
}

Player.class

// 추상 메소드를  상속받았을 경우 추상 메소드를 구현(만들어야)해야 함
public class Player extends GameObject {
	@Override
	public void describe() {
		// 추상 클래스의 추상 메소드 describe()를 완성시킨다.
		System.out.println("플레이어입니다.");	
	}
}

describe()메서드는 GameObject클래스의 추상 메서드임.

-출력결과-
abstract_Class.Player@6f75e721
=> System.out.println(new Player) 의 결과. 리턴값이 없으므로 가리키는 주소값이 출력된다.
플레이어입니다.
=> new Player.describe() 메서드의 실행결과.
abstract_Class.Monster@69222c14
=> System.out.println(new Monster) 의 결과. 리턴값이 없으므로 가리키는 주소값이 출력된다.
몬스터입니다.
=> new Monster.describe() 메서드의 실행결과.

~ 참고 ~
abstract 가 사용될 수 있는 곳: 클래스, 메서드

  • 추상 클래스: 추상 메서드를 포함한 클래스
  • 추상 메서드: 선언부만 작성하고 구현부가 없는 메서드

인터페이스

  • 추상클래스와 비슷한 개념.
  • 추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화의 정도가 높아 오직 추상메서드와 상수만을 멤버로 가질 수 있고, 그 외 다른 요소는 일절 허용하지 않는다.
  • 추상클래스는 상속의 개념이나, 인터페이스는 상속과 관계없이 그 기능만을 동일하게 구현한다는 차이가 있음.
  • 인터페이스를 사용하면 서로 관계없는 클래스들(상속관계아님, 공통된 조상클래스 없음)에게 관계를 맺어줄 수 있음.
  • 조건 1. 모든 멤버변수는 public static final이어야하며 생략가능.
    조건 2. 모든 메서드는 public abstract이어야 하며 생략가능. (단, static메서드와 default메서드는 예외)
    => 모든 멤버에 공통적으로 적용되는 사항이므로 생략이 가능한 것.
  • 인터페이스의 이름은 ~ able로 끝남.

Describable.interface

public interface Describable {	// 인터페이스 생성
	String getDescription();
    	// 추상 메소드. 인터페이스 안의 모든 메소드는 public abstract를 생략한 주상 메소드임
}

Person.class

// 인터페이스를 구현(상속) 할 때 extends가 아닌 implement사용
// 상속한 클래스에서 추상 메소드 완성(구현)
public class Person implements Describable {
	@Override
	public String getDescription() {
		return "사람 입니다.";
	}
}

Computer.class

public class Computer implements Describable {
	@Override
	public String getDescription() {
		return "컴퓨터 입니다.";
	}
}

App.class

public class App {
	public static void main(String[] args) {
		// 인터페이스
//		Describable ds = new Describable();		// 객체를 만들 수 없다
		Describable[] objs = { new Person(), new Computer() };	// object는 모든 클래스의 부모 클래스라 주소값이 저장됨
		
		for(Describable ob : objs) {
			System.out.println(ob.getDescription());	
		}
	}
}

인터페이스의 구현

  • 인터페이스를 구현할때는 extends가 아닌 implements를 사용.
  • 인터페이스도 추상클래스처럼 자신에게 정의된 추상메서드를 구현해주는 클래스를 작성해야하며, 이 부분은 추상클래스와 비슷함.
  • 인터페이스는 인터페이스끼리 상속이 가능함. (상속과 구현은 비슷하되 다른 개념.)
  • 만약 구현하는 인터페이스의 메서드 중 일부만을 구현한다면 abstract를 붙여 추상클래스로 선언해야 함.
  • 상속과 구현을 동시에 가능.

DefaultRunnable.interface

// 인터페이스끼리 상속가능
public interface DefaultRunnable extends Runnable {	// 기본적으로 존재하는 인터페이스인 Runnable을 상속받음
	default void displayDetails() {	
	};
}

Machine.class

public class Machine implements DefaultRunnable {
	@Override
	public void run() {	// DefaultRunnable 가 상속받은 Runnable 속에 있는 추상메소드라 이것도 구체화해줘야함 
		System.out.println("머신 러닝!");
	}
	@Override
	public void displayDetails() {
		System.out.println("표시할 디테일 없음");
	}
}

App.class

public class App {
	public static void main(String[] args) {
		// 인터페이스는 인터페이스를 상속
		DefaultRunnable m1 = new Machine();	// 인터페이스를 Machine이 구현했기때문에 객체를 만들 수 있음
		m1.run();
		m1.displayDetails();
	}
}

인터페이스의 Default메서드와 static메서드

  • Default메서드와 static메서드는 인터페이스에서 구현가능.
  • 원래 인터페이스는 추상메서드만 선언할 수 있지만 JDK1.8부터는 디폴트 메서드와 static메서드도 추가할 수 있음.

default 메서드

  • 인터페이스에 메서드(인터페이스의 메서드는 무조건 추상메서드임)를 추가할 때 해당 인터페이스를 구현한 기존의 모든 클래스에 새로 추가된 메서드를 추가해야하는 수고를 덜기위해 사용.
  • 추상메서드의 기본적인 구현을 제공하는 메서드.
  • 추상메서드가 아니기때문에 디폴트 메서드가 새롭게 추가되어도 해당 인터페이스를 구현한 클래스를 변경하지 않아도 됨.
  • 추상메서드와는 달리 코드블럭 {}가 필요함.
  • 접근제어자는 public으로, 생략가능.

~ static 메서드 ~

  • 객체(인스턴스)생성없이 클래스를 통해 바로 사용하는 메서드. ('클래스명.메서드명(매개변수)'의 형식으로 호출)
  • static 메서드는 인스턴스와 관계없이 독립적인 메서드이므로 인터페이스에 추가하는데 번거로운 과정이 불필요함.
    자세한 개념은 자바수업 5일차 참고.

-default메서드 예제-

DefaultRunnable.interface

// 인터페이스끼리 상속가능
public interface DefaultRunnable extends Runnable {	// 기본적으로 존재하는 인터페이스인 Runnable을 상속받음
	default void displayDetails() {		// 디폴트 메소드는 구현가능 
    		System.out.println("표시할 디테일 없 음");
	};
}

Machine.class

public class Machine implements DefaultRunnable {
	@Override
	public void run() {	// DefaultRunnable 가 상속받은 Runnable 속에 있는 추상메소드라 이것도 구체화해줘야함 
		System.out.println("머신 러닝!");
	}
}

App.class

public class App {
	public static void main(String[] args) {
		// 인터페이스는 인터페이스를 상속
		DefaultRunnable m1 = new Machine();	// 인터페이스를 Machine이 구현했기때문에 객체를 만들 수 있음
		m1.run();
		m1.displayDetails();
	}
}

실행결과는 위의 예제와 동일.

인터페이스 다중구현

  • 상속받는 개념의 클래스와는 달리 인터페이스는 다중구현이 가능하다.
  • 자바의 인터페이스는 구현코드가 없으므로 하나의 클래스가 여러 인터페이스를 구현할 수 있음.
  • 여러 인터페이스를 구현한 클래스는 인터페이스 타입으로 형 변환 되는 경우 해당 인터페이스에 선언된 메소드만 사용가능

Person.class

package multi_Inheritance;
public class Person implements Speaker, Greeter {
	// Speaker, Greeter를 하나의 클래스에 모두 구현
	@Override
	public void greet() {
		System.out.println("환영합니다.");
	}
	@Override
	public void speak() {
		System.out.println("나는 사람입니다.");
	}
}

App.class

package multi_Inheritance;
interface Speaker {
	void speak();	// 선언부만 있고 구현부가 없는 추상 메소드
}
interface Greeter {
	void greet();	// 선언부만 있고 구현부가 없는 추상 메소드
}

public class App {
	public static void main(String[] args) {
		// 인터페이스는 다중 구현이 가능
		Person p1 = new Person();
        // Person은 인터페이스 Speaker와 Greeter를 모두 구현하고 있으므로
        // greet()메서드와 speak()메서드를 모두 사용가능
		p1.greet();
		p1.speak();
		
		Speaker p2 = new Person();	// Person이 구현한 인터페이스 Speaker로 선언
		p2.speak();
//		p2.greet();	// Speaker 인터페이스의 추상메소드만 사용가능, greet 사용불가
		Greeter p3 = new Person();	// Person이 구현한 인터페이스 Greeter로 선언
		p3.greet();
//		p3.speak();	// Greeter 인터페이스의 추상메소드만 사용가능
	}
}

좋은 웹페이지 즐겨찾기