자바수업 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 인터페이스의 추상메소드만 사용가능
}
}
Author And Source
이 문제에 관하여(자바수업 7일차), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@0829kuj/자바수업-7일차저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)