void beforePoly(){
Person[] persons = new Person[10];
persons[0] = new Person();
SpiderMan [] spiderMans = new SpdierMan[10];
spiderMans[0] = new SpiderMan();
}
void afterPoly(){
Person [] persons = new Person[10];
Person[0] = new Person();
Person[1] = new SpiderMan();
}
다형성으로 다른 타입의 데이터(Person, SpiderMan을 하나의 배열로 관리)
→ 메서드가 호출되기 위해서는 메서드 이름과 파라미터가 맞아야 한다
ex) public void println(Phone p), public void println(SmartPhone sp)
public void println(Object x){
String S = String.valueOf(x);
synchronized(this){
print(s);
newLine();
}
}
Object가 모든 클래스의 조상이므로 어떤 타입의 객체라도 저장해서 출력 가능
다형성의 활용 예3 - 다형성과 참조형 객체의 형 변환
→ 메모리에 있는 것과 사용할 수 있는 것의 차이
메모리에 있더라도 참조하는 변수의 타입에 따라 접근할 수 있는 내용이 제한됨
1번
byte b = 10;
int i = b;
Phone phone = new Phone();
Object obj = phone;
자손 타입의 객체를 조상 타입으로 참조: 형변환 생략 가능 (조상의 모든 내용이 자식에 있음)
2번
int i = 10;
byte b = (byte)i;
Phone phone = new SmartPhone();
SmartPhone sPhone = (SmartPhone)phone;
조상 타입을 자손 타입으로 참조: 형변환 생략 불가
Person person = new Person();
SpiderMan sman = (SpiderMan) person;
sman.fireweb();
메모리의 객체는 fireWeb이 없다
→ instanceof 연산자: 실제 메모리에 있는 객체가 특정 클래스 타입인지 bool로 리턴
다른 형태의 하위객체 들이 한 부모를 상속 받았을 경우에 어떤 클래스인지 알아낼 수 있다.
Person person = new Person();
if(person instanceof SpiderMan){
SpiderMan sman = (SpiderMan) person;
}
-> person 이라는 객체가 SpiderMan과 같은 객체 (메모리상에서)일때만 if문을 실행
class AA{}
class BB extends AA {}
class CC extends AA {}
public class InstanceofEx1 {
public static void main(String[] args) {
AA a=new AA();
BB b=new BB();
System.out.println(b instanceof AA); // true
System.out.println(a instanceof CC); // false
// System.out.println(b instanceof CC); // error
}
}
class SuperClass{
String x = "super";
public void method(){
system.out.println("super class method");
}
}
class SubClass extends SuperClass{
String x = "sub";
@Override
public void method(){
system.out.println("sub class method");
}
}
public class MemberBindingTest{
public static void main(String[]args){
SubClass subClass = new SubClass();
system.out.println(subClass.x); // sub
subClass.method(); // sub class method
SuperClass superClass = subClass;
system.out.println(superClass.x); //super
superClass.method(); //sub class method
}
}
정적 바인딩(static binding)
동적 바인딩(dynamic binding)
static 메서드는 클래스가 Compile 되는 시점에 결정되지만, Override의 경우에는 Runtime 시점에 사용될 메서드가 결정되기 때문
부모에 static 메서드를 선언하고 자식에서 똑같은 static함수로 선언하면 해당함수는 상속받는게 아니라 자식 객체로 해당 메서드를 실행하면 부모의 static 메서드가 hiding 되는 것 부모 객체의 해당 메서드를 실행하면 부모 클래스에서 선언한 static 메서드가 호출된다
객체가 출력되는 과정
SuperClass superClass = new subClass();
System.out.print(superClass)
public void print(Object obj){
write(String.valueOf(obj));
}
public statoc String valueOf(Object obj){
return (obj == null) ? "null" : obj.toString();
}
public String toString(){
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public class AbstractEx1 {
public static void main(String[] args) {
// AA ob=new AA(); //AA로 객체 생성 불가능
// ob.view1(); //1번 호출
AA ob2=new BB();
ob2.view1(); //3번 호출
ob2.view2(); //2번 호출
}
}
//추상메서드가 있는 추상클래스----------------------------------
abstract class AA{
abstract public void view1(); //--1
public void view2() {} //--2
}
class BB extends AA{
@Override
public void view1() {} //--3,강제성이 있는 재정의
}
public class AbstractEx1 {
public static void main(String[] args) {
// AA ob=new AA(); //AA로 객체 생성 불가능
// ob.view1(); //1번 호출
AA ob2=new BB();
ob2.view1(); //3번 호출
ob2.view2(); //2번 호출
}
}
//일반클래스-----------------------------------------------
class AA{
public void view1() {} //--1
public void view2() {} //--2
}
class BB extends AA{
@Override
public void view1() {} //--3, 강제성이 없는 재정의
}
public class AbstractEx1 {
public static void main(String[] args) {
AA ob=new AA(); //AA로 객체 생성 가능
ob.view1(); //1번 호출
AA ob2=new BB();
ob2.view1(); //3번 호출
ob2.view2(); //2번 호출
}
}
예를 들어 pair programming 중에 각자 다양한 메서드 이름을 쓰는 경우가 존재, 이럴 때 메서드 이름을 통일하되, 각자의 클래스에서 부모클래스를 강제로 오버라이딩 해서 사용하도록 하기 위해서 사용
public void view() { } -- 구현O
abstract public void view(); -- 구현X
→ abstract class 클래스 이름{
abstract 리턴타입 추상메소드이름( );
}
public interface MyInterface{
public static final MEMBER1 = 10;
int MEMBER2 = 10;
public abstract void method1(int param);
void method2(int param)
}
추상클래스 vs 인터페이스
//인터페이스 ---------------------------------------------
interface Flyable{
abstract public void fly();
}
interface Cryable{
abstract public void cry();
}
class Eagle implements Flyable,Cryable{
@Override
public void fly() {
System.out.println("독수리는 날아 다닙니다");
}
@Override
public void cry() {
System.out.println("까악 까악");
}
}
public class InterfaceEx2 {
public static void main(String[] args) {
new Eagle().fly();
new Eagle().cry();
}
}
//추상클래스 ---------------------------------------------
abstract class Flyable{
abstract public void fly();
}
abstract class Cryable{
abstract public void cry();
}
//클래스 상속은 하나 밖에 받을 수가 없다
class Eagle extends Flyable{
@Override
public void fly() {
System.out.println("독수리는 날아 다닙니다");
new CryableEx().cry();
}
//중첩클래스(inner class):클래스 안에서 또 다른 클래스를 사용
class CryableEx extends Cryable{
@Override
public void cry() {
System.out.println("까악 까악");
}
}
}
public class InterfaceEx2 {
public static void main(String[] args) {
new Eagle().fly();
}
}
인터페이스 활용 2
class User {
private String name;
public User() {}
public User(String name) {
this.name = name;
}
@Override
public String toString() {
return "이름 : "+ this.name;
}
}
//----------------------------------------------------
interface Score {
public int sol = 20;
public int getScore();
}
//-----------------------------------------------------
interface Print {
public String toPaint();
}
//-----------------------------------------------------
public class InterfaceEx3 extends User implements Score,Print{ // User,Score,Print 상속받기
int s; // 맞은수
public InterfaceEx3(String name, int s) {
super(name);
this.s = s;
}
public static void main(String[] args) {
InterfaceEx3 ob = new InterfaceEx3("홍길동", 3);
System.out.println(ob.toPaint());
}
@Override
public String toPaint() {
return super.toString() +"\n점수 : "+getScore()+"점";
}
@Override
public int getScore() {
return this.s*sol;
}
}
[출력화면]
이름 : 홍길동
점수 : 60점
인터페이스 상속
인터페이스 구현과 객체 참조
인터페이스의 필요성
if MySQL에서 Oracle로 데이터베이스를 바꾼다고 할 때 다 뜯어고칠 필요가 없다. JDBC 인터페이스를 각각의 DB가 구현하고 있으니 인터페이스 단에서
고쳐줘야 하는 코드는 없다. 그냥 MySQL에서 Oracle로만 바꾸면 그만 → 다형성 이용
자바는 Single Inheritance 만 지원한다 → 상속 받을 수 있는 클래스는 1개 밖에 없음 HandPhone은 Phone을 상속받고 Chargeable 인터페이스를 구현
DigitalCamera는 Camera를 상속받고 Chargeable 인터페이스를 구현 ⇒ chargeable 객체로 묶어서 한 번에 처리가 가능하다.
접근 제한자는 public으로 한정됨(생략가능)
interface DefaultMethodInterface{
void abstracrMethod();
default void defaultMethod(){
System.out.println("기본 메서드 입니다");
}
}
새로운 메서드를 인터페이스에 넣을 때 인터페이스를 구현하는 하위 클래스들이 일일히 다 override하지 않아도 되게한다.
원래 interface 메서드는 구현부가 없기 때문에 다중상속이 가능했다, but default 메서드를 만들면 이 메서드는 구현되기 때문에 충돌이 발생할 수 있다.
interface StaticMethodInterface{
static void staticMethod(){
System.out.println("static 메서드");
}
}
public class StaticMethodTest{
public static void main(String[] args){
StaticMethodInterface.staticMethod();
}
}
요구사항
/*
[출력 결과]
이름 : 홍길동 <--- Family의 toString()에서 작성
아빠는 나가서 일을 한다 <-- Job인터페이스를 상속받아서 Father의 work()에서 작성
이름 : 김순희
엄마는 집안일을 한다
이름 : 홍돌이
아들은 공부를 한다
*/
class Family{
private String name;
public Family() {}
public Family(String name) {
this.name = name;
}
@Override
public String toString(){
return "이름 : "+name +"\n";
}
}
interface Job{
public String work();
}
class Father extends Family implements Job{
public Father() {}
public Father(String name) {
super(name);
}
@Override
public String work() {
return "아빠는 나가서 일을한다";
}
@Override
public String toString() {
return super.toString()+this.work()+"\n";
}
}
class Mother extends Family implements Job{
public Mother() {}
public Mother(String name) {
super(name);
}
@Override
public String work() {
return "엄마는 집안일을 한다";
}
@Override
public String toString() {
return super.toString()+this.work()+"\n";
}
}
class Son extends Family implements Job{
public Son() {}
public Son(String name) {
super(name);
}
@Override
public String work() {
return "아들은 공부를 한다";
}
@Override
public String toString() {
return super.toString()+this.work()+"\n";
}
}
public class MainEx {
public static void main(String[] args) {
//-------------------------------------------------
Father ob1=new Father("홍길동");
Mother ob2=new Mother("김순희");
Son ob3=new Son("홍돌이");
System.out.println(ob1); // or ob1.toString()
System.out.println(ob2);
System.out.println(ob3);
}
}
이름 : 홍길동
아빠는 나가서 일을 한다
이름 : 김순희
엄마는 집안일을 한다
이름 : 홍돌이
아들은 공부를 한다
똑같이 객체 출력을 했는데 실행되는 정보가 다르다
String s1="Hello";
String s2="Hello";
String s3=s2;
String s4=new String("Hello");
String s5=new String("Hello");
System.out.println(s1==s2); //true
System.out.println(s2==s3); //true
System.out.println(s1.equals(s2)); //true
System.out.println(s2.equals(s3)); //true
System.out.println(s4==s5); //false
System.out.println(s4.equals(s5)); //true
문자를 비교할 땐 str1.equals(str2)로 하자 str1 == str2로 쓰는 거 보단