상속이란 기존의 클래스로 새로운 클래스를 작성하는 것을 의미합니다.(코드의 재사용)
두 클래스를 부모와 자식으로 관계를 맺어줍니다.
class 자식클래스 extends 부모클래스 {
//...
}
class Parent {
int age;
}
class Child extends Parent { }
//아무것도 안적었지만 Parent클래스의 age변수를 상속받고 있다.
class Parent {
int age;
}
class Child extends Parent {
void play() { //부모 클래스에 영향이 없다.
System.out.println("play");
}
}
예제)
class Tv {
boolean power; // 전원상태(on/off)
int channel; // 채널
void power() { power = !power; }
void channelUp() { ++channel; }
void channelDown() { --channel; }
}
//SmartTv는 Tv에 캡션(자막)을 보여주는 기능을 추가
//SmartTv의 멤버변수는 부모클래스의Tv까지 전부 상속받았다.
class SmartTv extends Tv {
boolean caption; // 캡션상태(on/off)
void displayCaption(String text) {
if(caption) {
System.out.println(text);
}
}
}
class Ex7_1 {
public static void main(String[] args) {
SmartTv stv = new SmartTv();
stv.channel = 10;
stv.channelUp();
System.out.println(stv.channel);
stv.displayCaption("Hello world");
stv.caption = true;
stv.displayCaption("Hello world");
}
}
포함(composite)이란 클래스의 멤버로 참조변수를 선언하는 것을 의미합니다.
작은 단위의 클래스를 만들고, 이들을 조합해서 클래스를 만듭니다.
class Circle {
Point c = new Point(); // 포함관계
int r;
}
class Point {
int x;
int y;
}
상속관계
~은 ~이다.(is-a)
포함관계
~은 ~을 가지고 있다(has-a) ->대부분 포함관계인경우가 많다.
Java는 단일 상속만을 허용합니다.
비중이 높은 클래스 하나만 상속관계로, 나머지는 포함관계로 설계합니다.
만약 두 부모에 동명의 메서드가 있는경우(충돌문제)
Object클래스는 상속계층에서 최상층에 있는 클래스입니다.
부모가 없는 클래스는 자동적으로 Object클래스를 상속받게 됩니다.
모든 클래스는 Object클래스에 정의된 11개의 메서드를 상속받습니다.
toString()(중요), equals(Object obj), hashCode(), ....(9장에서 자세히...)
toString() - '클래스명@객체의 메모리주소값' 형태로 출력됩니다.
그냥 참조변수를 출력해도 toString()을 호출해서 출력합니다.
오버라이딩은 상속받은 조상의 메서드를 자신에 맞게 변경하는 것을 의미합니다.
예제)
class Point {
int x;
int y;
String getLocation() {
return "x: "+x+", y: "+y;
}
}
class Point3D extends Point {
int z;
//선언부는 변경불가
//내용(구현부{})만 변경가능
String getLocation() {
return "x: "+x+", y: "+y+", z: "+z;
}
}
오버로딩(overloading) - 이름은 같으나 기존의 없는 새로운 메서드를 정의하는것
오버라이딩(overriding) - 상속받은 메서드의 내용을 변경하는 것
조상 클래스를 가리키는 참조변수. 인스턴스 메서드(생성자)내에만 존재합니다.
조상의 멤버를 자신의 멤버와 구별할 때 사용됩니다.
예제)
class Ex7_2 {
public static void main(String[] args) {
Child c = new Child();
c.method();
}
}
//super.x
class Parent { int x = 10; }
class Child extends Parent {
int x = 20;
void method() {
System.out.println("x="+x); // 20
System.out.println("this.x="+this.x); // 20
System.out.println("super.x="+super.x); // 10
}
}
조상의 생성자를 호출할 때 사용됩니다.
조상의 멤버는 조상의 생성자를 호출해서 초기화됩니다.
예제)
class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Point3D extends Point {
Point3D(int x, int y, int z) {
super(x, y); // 조상의 생성자를 호출
this.z = z;
}
}
생성자의 첫줄에 반드시 생성자를 호출해야 합니다.
그렇지 않으면 컴파일러가 생성자의 첫 줄에 super();를 자동으로 삽입하게 됩니다.
만약 상속받은 클래스가 없다면 Object()의 super()를 실행하게 됩니다.
만약 상속받은 클래스의 생성자에 기본생성자가 없고 매개변수가 있다면 반드시 매개변수를 넣은 super(매개변수1, 매개변수2, ....)를 사용해야합니다.
예제)
class Point {
int x;
int y;
//Point() {}
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Point3D extends Point {
int z;
Point3D(int x, int y, int x) {
super(x, y);//작성안할시 에러발생
this.z = z;
}
}
패키지란 서로 관련된 클래스의 묶음을 의미합니다.
실제로 컴퓨터에서 클래스는 클래스파일(*.class), 패키지는 폴더로 구성되어 있습니다.(하위 패키지는 하위 폴더로 구성)
클래스의 실제 이름(full name)은 패키지를 포함하고 있는 형태입니다.(java.lang.String)
rt.jar는 클래스들을 압축한 파일을 의미합니다.(JDK설치경로 \jre\lib에 위치)
패키지는 소스파일의 첫 번째 문장으로 단 한번만 선언해야 합니다.
같은 소스 파일의 클래스들은 모두 같은 패키지에 속하게 됩니다.
패키지 선언이 없으면 이름없는(unnamed)패키지에 속하게 됩니다.
package com.codechobo.book;
public class PackageTest {
public static void main(String[] args) {
System.out.println();
}
}
import문을 이용하면 클래스를 사용할 때 패키지이름을 생략할 수 있습니다.
//원래는 아래와같이 작성해야한다.
class ImportTest {
java.util.Date today = new java.util.Date();
//....
}
//import문을 이용하면 아래와같이 패키지를 생략할 수 있다.
import java.util.Date;
class ImportTest {
Date today = new Date();
}
java.lang패키지의 클래스는 import하지 않고도 사용할 수 있습니다.
String, Object, System, Thread ....
import문을 선언하는 방법은 다음과 같습니다.
//패키지의 특정클래스 가져오기
import 패키지명.클래스명;
//패키지의 모든 클래스 가져오기
import 패키지명.*;
import문은 패키지문과 클래스선언의 사이에 선언합니다.
예제)
package com.codechobo.book;
import java.text.SimpleDateFormat;
import java.util.*;
public class PackageTest {
public static void main(String[] args) {
Date today = new Date();
SimpleDateFormat date = new SimpleDateFormat("yyyy/MM/dd");
}
}
import문은 컴파일 시에 처리되므로 프로그램의 성능에 영향없습니다.
그러므로 모든클래스를 가져오는 import 패키지명.*;을 써도 무방합니다.
import java.util.*;
import java.*;
클래스 이름을 생략할 수 있게 해줍니다.
꼭 필요할때만 사용하는 것이 좋습니다.
import static java.lang.Math.random; //Math.random()만
import static java.lang.System.out; //System.out을 out만으로 참조가능
//System.out.println(Math.random());
out.println(random());
클래스와 클래스의 멤버(멤버변수, 메서드)에 부가적인 의미 부여하는 역할을 합니다.
public, protected, (default), private
static, final, abstract, native, transient, synchronized, volatile,strictfp
public class ModifierTest {
public static final int WIDTH = 200;
public static void main(String[] args) {
System.out.println("WIDTH = "+WIDTH);
}
}
멤버변수
메서드
예제)
class StaticTest {
static int width = 200; //클래스 변수(static 변수)
static int height = 120; //클래스 변수(static 변수)
static { //클래스 초기화 블럭
//static변수의 복잡한 초기화 수행
}
static int max(int a, int b) { //클래스 메서드(static메서드)
return a > b ? a : b;
}
}
클래스
메서드
멤버변수, 지역변수
예제)
final class FinalTest { //조상이 될수 없는 클래스
final int MAX_SIZE = 10; // 값을 변경할 수 없는 멤버변수(상수)
final void getMaxSize() { // 오버라이딩할 수 없는 메서드(변경불가)
final int LV = MAX_SIZE; //값을 변경할 수 없는 지역변수(상수)
return MAX_SIZE;
}
}
클래스
메서드
abstract class AbstractTest { // 추상 클래스(추상 메서드를 포함한 클래스)
abstract void move(); // 추상 메서드(구현부가 없는 메서드)
}
AbstractTest a = new AbstractTest(); // 에러!! 추상클래스의 인스턴스는 생성할 수 없다.
추상클래스를 상속받아서 완전한 클래스를 만든후에 객체생성이 가능하다(차후 강의 예정)
4개중 1개만 사용이 가능합니다.
제어자 | 같은 클래스(파일) | 같은 패키지(폴더) | 자손클래스(다른폴더) | 전체 |
---|---|---|---|---|
public | o | o | o | o |
protected | o | o | o | |
(default) | o | o | ||
private | o |
클래스
멤버변수
예제)
class Time {
//접근 제어자를 private으로 하여
//외부에서 직접 접근하지 못하도록 한다.
private int hour;
private int minute;
private int second;
public int getHour() { return hour; }
//함수를 통해 데이터를 정제할 수 있다.
public void setHour(int hour) {
if (hour < 0 || hour > 23) {
return;
}
this.hour = hour;
}
public int getHour() {
return hour;
}
}
public class TimeTest {
public static void main(String[] args) {
//위와같이 코드를 작성하면 다음과같은 코드를 막을 수 있다.
Time t = new Time();
t.hour = 52; // 에러발생!
}
}
여러 가지 형태를 가질 수 있는 능력을 의미하고
java에서의 정확한 의미는 조상 타입 참조 변수로 자손 타입 객체를 다루는 것을 의미합니다.
조상타입의 맴버변수만 제한적으로 사용할 때 주로 이용합니다.
예제)
class Tv {
boolean power;
int channel;
void power() { power = !power; }
void channelUp() { ++channel; }
void channelDown() { --channel; }
}
class SmartTv extends Tv {
String text;
void caption() { //.....}
}
public class Polymorphism {
public static void main(String [] args) {
Tv tv = new SmartTv(); //조상타입 참조변수 = new 자손타입();
}
}
//일치(조상, 자손 멤버 전부사용가능)
SmartTv s = new SmartTv(); // 참조변수와 인스턴스의 타입이 일치
//불일치(변수 전부사용불가 조상의 멤버만 사용가능)
Tv t = new SmartTv(); // 조상타입 참조변수로 자손 타입 인스턴스 참조
반대로 자손타입의 참조변수로 조상타입의 객체를 가리킬수 없습니다.
SmartTv s = new Tv(); //에러! 허용안됨
//이유: 조상타입에 없는 멤버를 자손측에서 호출하게 되면서 에러가 발생하게 됩니다.