abstract 키워드
1. abstract (추상적)은 실제 코드가 존재하지 않지만 개념만 존재하는 멤버를 가지고 있는 상태.
추상: 여러가지 사물이나 개념에서 공통되는 특성이 속성따위를 추출하여 파악하는 작용
<=반댓말=>
구상: 사물, 특히 예술작품 따위가 직접 경험하거나 지각할 수 있도록 일정한 형태와 성질을 갖춤.
2. 멤버중 abstract인 메소드를 가지고 있는 클래스를 abstract 클래스라고 한다.
public abstract class 클래스명 { //추상 클래스
접근지정자 반환자료형 메소드명() {
//실행문;
}
접근지정자 abstract 반환자료형 메소드명(매개변수 리스트);
접근지정자 abstract 반환자료형 메소드명(매개변수 리스트);
}
3. abstract 멤버는 상속 받은 서브 클래스에서 반드시 오버라이딩 하도록 강제하는 역할.
4. abstract 클래스는 객체 생성 불가.
abstract 클래스에서 abstract이 아닌 일반 멤버는 서브 클래스에서 상속받은 후 객체 생성을 하고 멤버 접근.
//Class50.java
package com.test;
abstract class Super { // 추상 클래스
public void method1(){
System.out.println("Super클래스의 method1() 메소드 호출");
}
public abstract void method2(); // 추상 메소드
}
class Sub extends Super {
// @Override // 선택사항
// public void method1() {
// System.out.println("Sub클래스의 method1() 메소드 호출");
// }
@Override // 필수 의무 사항
public void method2() {
System.out.println("Sub클래스의 method2() 메소드 호출");
}
}
public class Class50 {
public static void main(String[] args) {
Sub obj = new Sub();
obj.method1(); //Super클래스의 method1() 메소드 호출
obj.method2(); //Sub클래스의 method2() 메소드 호출
}
}
추상 클래스를 이용한 정렬 프로그램
- Arrays.sort() 메소드에 대한 사용자 정의
//SuperSort.java -> 수퍼클래스. 추상클래스로 구현
//SubSort.java -> SuperSort 클래스를 상속받을 서브 클래스
//Class51.java -> main() 메소드 포함
package com.test;
public abstract class SuperSort { // 수퍼클래스. 추상클래스로 구현
//멤버변수
private int[] arr; // 참조형이므로 초기값은 null
//추상 메소드
protected abstract void sorting();
public void sort(int[] arr) {
this.arr = arr;
sorting();
}
protected int length() {
if(arr == null) {
return 0;
}
return arr.length;
}
//final 키워드가 있으므로 오버라이딩 불가. 즉, 재정의 금지.
protected final int compare(int i, int j) {
if (arr[i] == arr[j]) {
return 0;
} else if (arr[i] > arr[j]) {
return 1;
} else {
return -1;
}
}
//final 키워드가 있으므로 오버라이딩 불가. 즉, 재정의 금지.
protected final void swap(int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//Object 클래스의 toString()메소드를 오버라이딩
@Override
public String toString() {
String result = "";
if(arr == null) {
return result;
}
for (int a=0; a<arr.length; a++) {
result += String.format("%d ", arr[a]);
}
return result;
}
}
package com.test;
public class SubSort extends SuperSort { //SuperSort 클래스를 상속받는 서브 클래스
@Override
protected void sorting() {
for (int a=0; a<this.length()-1; a++) {
for (int b=a+1; b<this.length(); b++) {
if (this.compare(a, b) == 1) {
this.swap(a, b);
}
}
}
} //Super 클래스 상속
}
package com.test;
public class Class51 {
public static void main(String[] args) {
int[] arr = {9, 0, 1, 5, 2, 4, 3, 6, 7, 8};
//정렬 전 출력
System.out.print("정렬 전 : ");
for (int a=0; a<arr.length; a++) {
System.out.printf("%d ", arr[a]);
}
System.out.println();
//정렬
SubSort obj = new SubSort();
obj.sort(arr); //Call by Reference
//정렬 후 출력
System.out.print("정렬 후 : ");
//toString()의 오버라이딩 전 -> 객체 이름이 출력. 즉, 해시 코드
//toString()의 오버라이딩 후이므로 재정의된 내용으로 출력.
System.out.println(obj.toString());
}
}
final 키워드
1. 클래스에 final 사용시 -> 상속 불가 클래스
2. 메소드에 final 사용시 -> 오버라이딩 불가 메소드
3. 멤버변수에 final 사용시 -> 초기값 외에 값 재지정 불가 변수 -> 상수(constant)
//Class52.java
abstract class Super2 {
public void method1(){ }
public final void method2(){ } // 오버라이딩 불가 메소드
public abstract void method3(); // 추상 메소드이므로 클래스도 추상클래스로 만들어야함.
}
final class Super3 { //파이널 클래스(최종 클래스)
}
class Sub2 extends Super2 {
//final 멤버변수는 초기화 필수. 이후 값 재지정 불가. 즉, 상수(constant)
//1. 자동초기화
//2. 초기화 수식
//3. 초기화 블럭
//4. 생성자
private final int a = 10;
@Override
public void method1() { } // 선택적 오버라이딩
// @Override
// public void method2() { } // 오버라이딩 불가상태
@Override
public void method3() { } // 필수 오버라이딩
/* public void setA(int a) { // 멤버변수 a는 final 즉, 재지정이 불가능한 변수(상수)이므로 에러발생
this.a = a;
} */
public int getA() {
return a;
}
}
/*
class Sub3 extends Super3 { // 상속 불가
}
*/
interface 키워드
1. interface는 클래스의 템플릿(template) 기능을 수행하는 추상 전용 클래스.
템플릿 : 어떤 도식이나 서식에서 자주 사용되는 기본 골격.
2. class 키워드 대신 interface 키워드 사용.
3. interface의 멤버는
멤버변수인 경우 public final static 이며
메소드인 경우 public abstract 이다.
(코딩 생략가능)
4. interface는 수퍼클래스로만 사용 가능하며, 다중 상속을 허용한다. 상속 표현시 extends 대신 implements 키워드 사용.
5. 형식
interface 인터페이스명 {
자료형 멤버변수명 = 초기값; //public final static 이 앞에 생략되어 있는 상태. 주로, 변수명은 대문자로 표기
반환자료형 메소드명(); //public abstract 이 앞에 생략되어 있는 상태.
}
class 클래스명 implements 인터페이스명 {
@Override
반환자료형 메소드명() { // 상속받은 추상클래스 내 추상 메소드는 필수로 오버라이딩.
}
}
//Class53.java
package com.test;
interface Fruit {
String WON = "원"; //public final static 생략
int getPrice(); //public abstract 생략
String getName(); //public abstract 생략
}
class Apple implements Fruit {
//오버라이딩 필수
@Override
public int getPrice() {
return 1000;
}
//오버라이딩 필수
@Override
public String getName() {
return "사과";
}
}
class Grape implements Fruit {
//오버라이딩 필수
@Override
public int getPrice() {
return 500;
}
//오버라이딩 필수
@Override
public String getName() {
return "포도";
}
}
public class Class53 {
public static void main(String[] args) {
Apple apple = new Apple();
System.out.printf("%s %d%s %n", apple.getName(), apple.getPrice(), Fruit.WON); // 사과 1000원
Grape grape = new Grape();
System.out.printf("%s %d%s %n", grape.getName(), grape.getPrice(), Fruit.WON); // 포도 500원
// Fruit fruit = new Fruit(); // interface 클래스는 추상 클래스이므로 객체 생성불가.
//서브클래스의 객체를 수퍼 클래스 자료형 변수에 저장 가능
Fruit fruit1 = new Apple();
Fruit fruit2 = new Grape();
System.out.printf("%s %d%s %n", fruit1.getName(), fruit1.getPrice(), Fruit.WON); // 500원
}
}
참조형 변수의 형 변환
1. 참조형 변수의 형 변환은 상속 관계에 있는 수퍼, 서브 클래스 간에서만 형변환이 가능하다.
2. 서브 클래스 객체를 수퍼 클래스 자료형 변수에 저장하는 경우는 묵시적으로 가능. -> 업캐스팅
수퍼클래스명 변수1 = new 서브클래스명();
3. 수퍼 클래스 자료형 변수에 저장된 서브 클래스 객체를 다시 원래의 자료형으로 되돌려야 할때는 명시적으로만 가능. -> 다운캐스팅
서브클래스명 변수2 = new (서브클래스명)변수1;
//Class54.java
package com.test;
//Object 클래스 자동 상속
class Super4 {
public void method1(){
System.out.println("Super4의 method1() 호출");
}
}
//Super4 클래스 상속
class Sub4 extends Super4 {
public void method2() {
System.out.println("Sub4의 method2() 호출");
}
}
public class Class54 {
public static void main(String[] args) {
Super4 obj1 = new Super4();
obj1.method1();
Sub4 obj2 = new Sub4();
obj2.method1();
obj2.method2();
Super4 obj3 = new Sub4(); //업캐스팅. 묵시적.
obj3.method1(); //O. Super4의 method1()호출
// obj3.method2(); //X. obj3는 Super4 클래스에서 멤버확인.
Sub4 obj4 = (Sub4)obj3; // 다운캐스팅. 명시적
obj4.method1(); //O. Super4의 method1()호출
obj4.method2(); //O. Sub4의 method2()호출
}
}
//Class55.java
package com.test;
//Object 클래스 자동 상속
class Super5 {
public void method1(){
System.out.println("Super5의 method1() 호출");
}
}
//Super4 클래스 상속
class Sub5 extends Super5 {
//오버라이딩 추가
@Override
public void method1(){
System.out.println("Sub5의 method1() 호출");
}
public void method2() {
System.out.println("Sub5의 method2() 호출");
}
}
public class Class55 {
public static void main(String[] args) {
Super5 obj1 = new Super5();
obj1.method1(); //Super5의 method1() 호출
Sub5 obj2 = new Sub5();
obj2.method1(); //Sub5의 method1() 호출
obj2.method2(); //Sub5의 method2() 호출
Super5 obj3 = new Sub5(); //업캐스팅. 묵시적.
// 컴파일할때는 Super5 검사. 실행할때는 Sub5 출력.
// ojb3 변수의 자료형은 Super5이므로 method1()은 Super5의 멤버인것 처럼 해석되지만
// 실행시에는 변수가 실제로 가지고 있는 객체인 Sub5의 멤버인 오버라이딩된 method1이 호출된다.
obj3.method1();
// obj3.method2();
Sub5 obj4 = (Sub5)obj3; // 다운캐스팅. 명시적
obj4.method1();
obj4.method2();
}
}
중첩 클래스
1. 클래스 선언 내부에 클래스 선언이 되는 경우 중첩 클래스라고 함.
2. static nested class, inner class, local class, anonymous class
◆ static nested class
- 형태
접근지정자 class 외부 클래스명 {
//인스턴스 멤버
//스태틱 멤버
접근지정자 static class 내부 클래스명{ //자기 자신도 스택틱 멤버임
//외부 클래스의 스태틱 멤버 접근 가능.
}
}
- static으로 선언된 내부 클래스이다.
- 중첩 클래스의 객체는 중첩 클래스를 포함하고 있는 외부 클래스의 객체와 동일하다.
- 외부 클래스의 클래스 변수와 클래스 메소드는 바로 접근하여 사용가능하다.
- 중첩 클래스와 중첩 클래스를 포함하고 있는 외부 클래스의 인스턴스 변수와 인스턴스 메소드는
객체를 생성해서 서로 접근이 가능하다.
- 중첩 클래스를 외부에서 단독으로 접근 가능하다.
//Class56.java
package com.test;
class Outer1 {
//인스턴스 멤버
public void method1(){
Inner1.method4(); //O
Inner1 obj = new Inner1();
obj.method3();
}
//스태틱 멤버
public static void method2(){
Inner1.method4(); //O
Inner1 obj = new Inner1();
obj.method3();
}
//자기 자신도 static멤버
static class Inner1 {
public void method3(){
// method1(); //X
method2(); //O
method4(); //O
}
public static void method4(){
// method1(); //X
method2(); //O
// method3(); //X
}
}
}
public class Class56 {
public static void main(String[] args) {
Outer1 obj = new Outer1();
obj.method1(); //O
Outer1.method2(); //O
//static nested class의 멤버 접근 방법
//인스턴스 멤버인 경우
Outer1.Inner1 obj2 = new Outer1.Inner1();
obj2.method3(); //O
//static nested class의 멤버 접근 방법
//스태틱 멤버인 경우
Outer1.Inner1.method4(); //O
}
}
◆ inner class
- 형태
접근지정자 class 외부 클래스명 {
//인스턴스 멤버
//스태틱 멤버
접근지정자 class 내부 클래스명{ //자기 자신도 인스턴스 멤버임
}
}
- static 키워드가 없는 내부 클래스
- 내부 클래스 내부에 스태틱 멤버를 가질 수 없다.
- 외부클래스의 멤버 참조시 외부클래스명.this 키워드 사용.
//Class57.java
package com.test;
class Outer2 {
public void method1() { //인스턴스 멤버
Inner2 obj = new Inner2();
obj.method3();//O
}
public static void method2() { // 스태틱 멤버
//Inner2 obj = new Inner2(); // X. 내부 클래스가 인스턴스 멤버이므로 static입장에서는 접근 불가
//obj.method3();
}
//자기 자신도 인스턴스 멤버
class Inner2 {
public void method3() {// 인스턴스 멤버
Outer2.this.method1(); // O
method1(); // O
method2(); // O
}
//public static void method4() { } //X. 스태틱 멤버 -> 불가
}
}
public class Class57 {
public static void main(String[] args) {
Outer2 obj = new Outer2();
obj.method1(); // O
Outer2.method2(); // O
//inner class 객체 접근을 위해서는 외부클래스의 객체가 먼저 생성되어야 한다.
Outer2 obj2 = new Outer2();
Outer2.Inner2 obj3 = obj2.new Inner2();
obj3.method3(); // O
Outer2.Inner2 obj4 = new Outer2().new Inner2();
obj4.method3(); // O
}
}
◆ local class
- 형태
class 외부클래스명 {
//인스턴스 멤버
//스태틱 멤버
접근지정자 반환자료형 메소드명 (매개변수 리스트){
//지역 변수
//자기 자신이 지역 변수와 같은 멤버이다.
class 로컬클래스명{
//멤버
}
로컬클래스명 변수 = new 로컬 클래스명();
변수.멤버명();
}
}
- 메소드 내부에서 선언된 클래스
- 접근지정자는 붙일 수 없다.
- 로컬클래스의 객체 활동 범위는 메소드 내부에서만 가능.
//Class58.java
package com.test;
class Outer3 {
//인스턴스 멤버
public void method1() {
int a = 0;
final int B = 0;
class Local {
private int a = 10; //로컬클래스의 멤버변수
//private int B = 10; //로컬클래스의 멤버변수
public void method3(){
System.out.println(this.a); // 10
//System.out.println(a); //로컬클래스의 멤버변수가 없을 경우 접근 불가
System.out.println(B); // 0. final 키워드가 있는 지역변수만 local 클래스에서 접근 가능
}
//public static void method4() { // 스태틱멤버이기 때문에 생성불가
//}
}
Local obj = new Local();
obj.method3();
}
public static void method2() {
int a = 0;
class Local {
private int a = 10;
public void method3(){
System.out.println(this.a); // 10
}
//public static void method4(){ // 로컬 클래스 자신이 지역변수이기 때문에 스태틱 멤버 생성 불가
//}
}
Local obj = new Local();
obj.method3();
}
}
public class Class58 {
public static void main(String[] args) {
Outer3 obj1 = new Outer3();
obj1.method1(); //O
Outer3.method2(); //O. main에서 메소드3을 직접 호출할 수 있는 방법은 없음.
}
}
◆ anonymous class (익명 클래스)
- 형태
class 외부클래스명 {
접근지정자 반환자료형 메소드명() {
return new 상위클래스명() {
//오버라이딩 메소드만 구현 가능
};
}
}
//Class59.java
package com.test;
class Super6 {
public void method3(){
System.out.println("Super6 클래스의 method3() 호출");
}
}
class Outer4 {
public Object method1() {
return new Object();
}
public Object method2() {
//익명 클래스 정의
//Object 클래스의 상태를 재정의 할 수 있다.
//오버라이딩은 상속관계에서의 서브 클래서 내에서 수퍼클래스의 메소드를 재정의하는 것인데,
//Object의 경우 모든 클래스에서 자동 상속이 되므로 여기서 사용이 가능한 것임.
return new Object() {
@Override
public String toString() {
String result = "";
result = "Object 클래스의 오버라이딩 toString() 메소드 호출";
return result;
}
}; // -> 익명클래스
}
public Super6 method3() {
return new Super6() {
@Override
public void method3() {
System.out.println("anonymous 클래스의 Super6 클래스 호출");
}
};
}
}
public class Class59 {
public static void main(String[] args) {
Outer4 obj = new Outer4();
System.out.println(obj.toString()); //Outer4 클래스의 객체명 출력
//new 키워드 없이 객체생성 가능
Object obj2 = obj.method1();
System.out.println(obj2.toString()); //Object 클래스의 객체명 출력
//new 키워드 없이 객체 생성 가능.
Object obj3 = obj.method2();
System.out.println(obj3.toString());
Super6 obj4 = new Super6();
obj4.method3(); //Super6 클래스의 method3() 호출 출력
Super6 obj5 = obj.method3();
obj5.method3(); //anonymous 클래스의 Super6 클래스 호출
}
}