생성자의 접근 제어자 - 일반적으로 생성자의 접근 제어자는 클래스의 접근 제어자와 일치한다. - 생성자에 접근 제어자를 사용함으로써 인스턴스 생성을 제한할 수 있다.
싱글톤 패턴, 싱글톤 인스턴스 - 인스턴스를 하나만 생성한다.
💬 생성자에 private가 적혀있다. ex) private MyTest() {} 💬 객체에 static ex) static MyTest mt = null; 💬 객체를 하나 출력하게 한다. ex) mt = new MyTest();
📃 싱글톤 예제 (1)
- MyTest 클래스
public class MyTest {
// getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static이어야한다.
static MyTest mt = null; // 주소 값을 저장할 참조 변수, 공유 메모리 공간에 만듬
private MyTest() {
System.out.println("MyTest 생성");
}
static MyTest getInstance() {
if(mt == null) { // 처음 null일 때 객체 생성하고 출력
mt = new MyTest();
}
return mt;
}
}
- TestMain 클래스
public class TestFile {
public static void main(String[] args) {
MyTest m1 = MyTest.getInstance(); // 출력
MyTest m2 = MyTest.getInstance(); // 출력 X
MyTest m3 = MyTest.getInstance(); // 출력 X
}
}
📃 싱글톤 예제 (2)
- MusicPlayer 클래스
// 다른 클래스에서 getInsatance를 여러 번 호출해도
// 인스턴스를 한 번만 생성하도록 코드를 수정하세요
public class MusicPlayer {
private static MusicPlayer mp = null;
private MusicPlayer() {
System.out.println("뮤직플레이어 생성");
}
public static MusicPlayer getInstance() {
if(mp == null) {
mp = new MusicPlayer();
}
return mp;
}
}
- TestMain 클래스
public class TestFile2 {
public static void main(String[] args) {
MusicPlayer m1 = MusicPlayer.getInstance(); // 출력
MusicPlayer m2 = MusicPlayer.getInstance(); // 출력 X
MusicPlayer m3 = MusicPlayer.getInstance(); // 출력 X
}
}
💡다형성
다형성(polymorphism) : 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있는 것 (조타참 자타객) - 하나의 참조변수로 여러 타입의 객체를 참조할 수 있는 것
⚡예제 Tv t = new Tv(); CaptionTv c = new CaptionTv(); 다형성을 사용하게 되면 위처럼 따로따로 인스턴스를 정의하지 않아도 된다.
Tv ctv = new CaptionTv();
class Man extends People{
@Override
public void printInfo() {
super.printInfo();
System.out.println("그리고 나는 남자입니다.");
}
public void enlist() {
System.out.println("내일 군대를 갑니다.");
System.out.println("충성!");
}
}
class Woman extends People{
@Override
public void printInfo() {
super.printInfo();
System.out.println("그리고 나는 여자입니다.");
}
public void makeUp() {
System.out.println("예뻐질 거랍니다.");
System.out.println("톡톡 촵촵!");
}
}
public class Test {
public static void main(String[] args) {
People people=new Man();
people.printInfo();
((Man)people).enlist();
System.out.println();
people=new Woman();
people.printInfo();
((Woman)people).makeUp();
}
}
- 객체를 매개변수로 받으면 그것을 상속하는 모든 클래스를 받아낼 수 있다. --> Object 객체로 모든 객체를 받을 수 있는 것은 다형성의 속성 때문이다.
public static void func(People people) {
people.printInfo();
}
public static void main(String[] args) {
Man man = new Man();
Woman woman = new Woman();
func(man);
System.out.println();
func(woman);
}
- 추가적으로 필요에 의해서는 instanceof 연산자를 사용해서 캐스팅 할 수 있다.
public static void func(People people) {
people.printInfo();
/*------- 추가 ------*/
if(people instanceof Man)
((Man)people).enlist();
if(people instanceof Woman)
((Woman)people).makeUp();
/*-------------*/
}
public static void main(String[] args) {
Man man = new Man();
Woman woman = new Woman();
func(man);
System.out.println();
func(woman);
}
📃 다형성 예제 (1)
- Tv, CaptionTv 클래스
// 다형성 예제
class CaptionTv extends Tv {
String text;
void caption() {
System.out.println("캡션 기능");
}
}
public class Tv {
int channel;
boolean power;
void power() {power = !power;}
void channelUp() {channel++;}
void channelDown() {channel--;}
}
- TestMain 클래스
Tv t = new Tv(); CaptionTv c = new CaptionTv();
== Tv t = new CaptionTv(); // 동일
public class TestMain {
public static void main(String[] args) {
CaptionTv ctv = new CaptionTv();
ctv.caption();
ctv.channelDown();
// 조상 타입의 참조 변수로, 자손 타입의 객체에 접근(조타참 자타객)
Tv t = new CaptionTv();
t.channelUp();
((CaptionTv)t).caption(); // 조상 클래스가 자식 클래스의 메소드를 사용하려면 자식 클래스로 형변환 해야한다.
// t.caption(); // 에러
}
}
📃 ⭐다형성 예제 (2)
[ 조건 ] //클래스명 Product //멤버변수 : int-price-제품가격 //생성자 : 매개변수가 하나인 생성자, 제품가격을 전달받아 초기화
//클래스명 : Tv //생성자 : 기본생성자, 조상클래스의 생성자를 활용해 가격을 100원으로 초기화
package Test1;
public class Product {
int price; // 제품 가격
// 매개변수가 하나인 생성자, 제품 가격을 전달받아 초기화
Product(int price) {
this.price = price;
}
}
class Tv extends Product {
// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 100원으로 초기화
Tv() {
super(100);
}
public String toString() {
return "Tv";
}
}
class Computer extends Product {
// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 200원으로 초기화
Computer() {
super(200);
}
public String toString() {
return "Computer";
}
}
class Audio extends Product {
// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 50원으로 초기화
Audio() {
super(50);
}
public String toString() {
return "Audio";
}
}
class Buyer {
int money = 1000;
void buy(Product p) {
if (money < 0) { return; }
money = money - p.price;
System.out.println("현재 잔액은 " + money);
}
}
- TestMain 클래스
package Test1;
public class TestMain {
public static void main(String[] args) {
// Tv p1 = new Tv();
// Computer p2 = new Computer();
// Audio p3 = new Audio();
Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();
Buyer buyer = new Buyer();
buyer.buy(p1); // 현재 잔액은 900
buyer.buy(p2); // 현재 잔액은 700
buyer.buy(p3); // 현재 잔액은 650
}
}
💡 참조변수의 형변환
참조변수의 형변환 - 서로 상속관계에 있는 타입간의 형변환만 가능하다. - 같은 자식 클래스끼리는 형변환이 불가능하다. - 자손 타입에서 조상 타입으로 형변환하는 경우는 형변환을 생략할 수 있다.
참조형 변수? - 형태(Type)
💡 instanceof 연산자
- Product, Tv, Computer, Audio, Buyer 클래스
// 위의 다형성 예제(2) 참고
instanceof 연산자 - 참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용 - 이항연산자이며 연산결과는 true/false - 연산결과가 true이면 해당 타입으로 형변환이 가능하다.
- Buyer 클래스의 buy 메소드에서 instanceof 연산자 사용하기 // buy메소드 안에서 instanceof를 이용하여 전달받은 인자의 상품 유형 출력 // ex. Product p가 Tv, Computer, Audio 중 무엇인지 확인
📃 ⭐다형성 예제 (3)
package Test1;
public class Product {
int price; // 제품 가격
// 매개변수가 하나인 생성자, 제품 가격을 전달받아 초기화
Product(int price) {
this.price = price;
}
}
class Tv extends Product {
// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 100원으로 초기화
Tv() {
super(100);
}
public String toString() {
return "Tv";
}
}
class Computer extends Product {
// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 200원으로 초기화
Computer() {
super(200);
}
public String toString() {
return "Computer";
}
}
class Audio extends Product {
// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 50원으로 초기화
Audio() {
super(50);
}
public String toString() {
return "Audio";
}
}
class Buyer {
int money = 1000;
void buy(Product p) {
if (money < 0) { return; }
// buy메소드 안에서 instanceof를 이용하여 전달받은 인자의 상품 유형 출력
// ex. Product p가 Tv, Computer, Audio 중 무엇인지 확인
if(p instanceof Tv) {
System.out.print("Tv 구매 후, ");
}
else if(p instanceof Computer) {
System.out.print("Computer 구매 후, ");
}
else if(p instanceof Audio) {
System.out.print("Audio 구매 후, ");
}
money = money - p.price;
System.out.println("현재 잔액은 " + money);
}
}
- TestMain 클래스
package Test1;
public class TestMain {
public static void main(String[] args) {
Tv p1 = new Tv();
Computer p2 = new Computer();
Audio p3 = new Audio();
Buyer buyer = new Buyer();
buyer.buy(p1); // 현재 잔액은 900
buyer.buy(p2); // 현재 잔액은 700
buyer.buy(p3); // 현재 잔액은 650
}
}
📃 ⭐다형성 예제 (4)
⚡ 자손간의 형변환은 불가능하다. FireEngine f; Ambulance a;
a = (Ambulance)f; f = (FireEngine)a;
⚡ 객체만 생성해두고 다형성으로 채울 수 있다. FireEngine fe = new FireEngine(); fe.water();
Car car = null; // 생성 FireEngine fe2 = null; car = fe; // == car = (Car)fe; [조상 <- 자손] -- 다형성 fe2 = (FireEngine)car; // [자손 <- 조상] (형변환 필요) -- 다형성 // car.water(); // 에러 fe2.water();
⚡형변환시 자손 클래스의 메소드를 사용할 수 있다. Car c = null; FireEngine f; Ambulance a = new Ambulance(); c = a; // 다형성
// car.siren(); //에러
((Ambulance)c).siren(); // 형변환
package TypeTransfer;
public class Car {
public static void main(String[] args) {
Car c1 = new FireEngine();
Car c2 = new Ambulance();
if(c1 instanceof FireEngine) {
System.out.println("This is a FireEngine instance");
}
else if(c1 instanceof Car) {
System.out.println("This is a Car instance");
}
else if(c1 instanceof Object) {
System.out.println("This is an Object instance");
}
((FireEngine)c1).water();
((Ambulance)c2).siren();
c1.drive();
c1.stop();
c2.drive();
c2.stop();
}
String color;
int door;
void drive() { // 운전 기능
System.out.println("drive, Brrrr~");
}
void stop() { // 멈추는 기능
System.out.println("stop!!!");
}
}
class FireEngine extends Car { // 소방차
void water() { // 물 뿌리는 기능
System.out.println("water!!!");
}
}
class Ambulance extends Car { // 구급차
void siren() { // 사이렌을 울리는 기능
System.out.println("siren~~~");
}
}
댓글