본문 바로가기

Java

새싹체험_java_1023

1023

내부클래스(= 중첩클래스 = 클래스 내부에 선언한 클래스) :: 클래스가 여러 클래스와 관계를 맺는 경우에는 독립적으로 선언하는 것이 좋지만 특정 클래스와 관계를 맺는 경우에는 클래스 내부에 선언하는 것이 좋음  

내부클래스에서 외부클래스의 멤버를 쉽게 접근할 수 있음/ 코드의 복잡성을 줄일 수 있음 

내부클래스는 선언 위치에 따라서 두가지로 분류되는데 클래스의 멤버로 선언되는 클래스를 멤버 클래스라고 하고 메소드 내부에 선언되는 클래스를 로컬클래스라고 함 

멤버클래스는 클래스나 객체가 사용 중이라면 재사용이 가능하다 / 로컬클래스는 메소드를 실행할때만 사용되고 종료되면 사라짐 

멤버클래스 (인스턴스 멤버 클래스 / 정적 멤버 클래스)

인스턴스 멤버 클래스는 인스턴스 필드와 인스턴스 메소드만 선언 가능하고 정적필드와 메소드는 선언할 수 없음 

정적 멤버 클래스는 모든 종류의 필드와 메소드를 선언할 수 있음 

메소드 내에서도 선언하는 클래스를 로컬클래스라고 하고 로컬클래스는 접근제한자 및 static을 붙일 수 없음 

익명객체(= 익명 내부 클래스) :: 익명 객체는 이름없는 객체를 말하고 익명객체를 만들려면 어떤 클래스를 상속하거나 인터페이스를 구현해야만 함 / 클래스 변수는 이름없는 객체를 참조하고 인터페이스변수는 이름없는 구현 객체를 참조하게 됨 / 이름이 없기 때문에 생성자도 가질 수 없음 

> 익명클래스는 하나의 실행문이라 ; 세미콜론을 붙여주어야 함 

Inner 클래스에서 Outer 클래스멤버 접근하는 예제

package inner;

class Outer1{
	private int x = 100;
	private static int y = 200;
	
	public void outerMethod1() {
		System.out.println("public 바깥클래스 메소드");
	}

	public void outerMethod2() {
		System.out.println("public 바깥클래스 메소드");
	}
	
	// 인스턴스 멤버클래스
	class Inner1 {
		private int x = 300;
		private int y = 300;
//		private static int z = 400;
		// 인스턴스 멤버클래스에서 정적(static)는 만들 수 없다
		
		public void disp() {
			System.out.println("Outer x :: " + x);
			System.out.println("Inner y :: " + y);
			System.out.println("Outer y :: " + Outer1.y);
			outerMethod1();
			outerMethod2();
		}
	}
	
}

public class Ex01 {
	public static void main(String[] args) {
		Outer1 outer1 = new Outer1();
		Outer1.Inner1 inner = outer1.new Inner1();
		inner.disp();
	}
}

Outer클래스에서 Inner클래스 멤버 접근예제

class Outer{
	private int x= 100;
	public void disp() {
		System.out.println(x); 
//		System.out.println(y);
		Inner2 inner2 = new Inner2();
		System.out.println(inner2.y); 
		inner2.innerMethod1();
		inner2.innerMethod2();
	}
	class Inner2{
		private int y = 200;
		public void innerMethod1() {
			System.out.println("public 안쪽클래스 메소드");
		}
		private void innerMethod2() {
			System.out.println("private 안쪽클래스 메소드");
		}
	}
}

public class Ex02 {
	public static void main(String[] args) {
		
	}
}

Outer 클래스의 static 멤버 클래스 

class Outer3{
	private int x = 100;
	private static int y = 200;
	
	// 정적 멤버 클래스
	static class Inner3{
		private int z = 300;
		private static int zz = 400;
		
		public void disp() {
			System.out.println(y);
			System.out.println(new Outer3().x);
			
		}
	}
}

public class Ex03 {
	public static void main(String[] args) {
		Outer3.Inner3 inner3 = new Outer3.Inner3();
		inner3.disp();
	}
}

 로컬클래스 > 어떤 메소드 안에서 기능을 할때 특정 클래스가 필요할때 만듬 (잘 사용은 안함)

class LocalEx{
	public void method() {
		class InnerLocal{
			int x = 100;
			
			public void disp() {
				System.out.println("methodInner x ::" + x);
			}
		}
		InnerLocal innerLocal = new InnerLocal();
		innerLocal.disp();
	}
}

public class Ex04 {
	public static void main(String[] args) {
		LocalEx ex = new LocalEx();
		ex.method();
	}
}
class Outer5 {
	public void aaa() {
		System.out.println("a");
	}
	public void bbb() {
		System.out.println("b");
		
	}
	public void ccc() {
		System.out.println("c");
		
	}
}


public class Ex05 {
	public static void main(String[] args) {
		Outer5 outer5 = new Outer5() {
			public void bbb() {
				System.out.println("bbbb");
				
			}
		}; // 익명클래스(=익명내부클래스)도 하나의 실행문이므로 세미콜론 필수 
		// 클래스의 메소드를 가져와서 수정하기 위함 
		
		outer5.aaa();
		outer5.bbb();
		outer5.ccc();
	}
}

=================================================1교시 끝

java상속 :: 부모클래스의 멤버를 자식 클래스에게 물려줄 수 있음/ 프로그램에서는 부모클래스를 상위클래스라고 부르고 자식클래스를 하위 클래스 라고 부름 / 현실에서 상속은 부모가 자식을 선택해서 물려주지만 프로그램에서는 자식이 부모를 선택해서 부모의 멤버를 물려받음 

상속을 쓰는 이유 :: 반복적으로 들어가는 공통 부분을 부모클래스에 작성하면 상속을 받는 자식클래스들은 부모의 멤버를 상속받아 그래도 사용할 수 있게 됨 / 이미 마련되어 있던 부모클래스의 기능들을 재사용하기 때문에 효율적으로 개발 시간을 줄여줌 / 수정을 해도 공통 부분만 수정해주면 되기 때문에 유지보수가 쉬워짐 

자바에서의 상속 특징

여러개의 부모클래스를 상속할 수 없기때문에 extends뒤에는 단 하나의 부모 클래스만 와야함

부모 클래스에서 private 접근 제한을 갖는 필드와 메소드는 상속대상에서 제외됨 

object 클래스

자바의 모든 클래스는 오브젝트 클래스의 모든 필드와 메소드를 자동으로 상속받게 됨 > 오브젝트 클래스의 모든 멤버를 자유롭게 사용할 수 있음 

자바의 모든 객체에서 toString()과 같은 메소드를 바로 사용할 수 있는 이유가 오브젝트 클래스의 메소드 이기 때문

toString() 메소드 :: 해당 객체에 대한 정보를 문자열로 반환함 ex ) Test@123a439b (객체@16진수 해시코드)

super키워드(부모클래스의 기본 생성자를 호출시킴) :: 부모 클래스로 부터 상속받은 멤버를 자식 클래스에서 참조하는데 사용되는 참조변수이다 

> this키워드와 비슷함

부모클래스의 생성자 호출( super( ) )은 자식 생성자의 맨 첫줄에서 호출이 됨 

부모클래스의 특정 메소드는 자식클래스가 사용하기에 적합하지 않을 수 있음

이 경우 상속된 일부 메소드는 자식 클래스가 다시 수정해야하기 때문에 메소드 재정의 기능을 제공함(오버라이딩)

상속 실습 

package inheritance;

class Parent {
	int parentMoney = 1000;
	public void parentMethod() {
		System.out.println("부모클래스 입니다");
	}
}

class Child extends Parent{

	int childMoney = 500;
	public void childMethod() {
		System.out.println("자식클래스 입니다");
	}
	
	
}


public class Ex01 {
	public static void main(String[] args) {
		Child child = new Child();
		System.out.println(child.parentMoney);
		child.parentMethod();
	}
}

부모생성자 호출과 자식 생성자 호출

class Sedan{
	String color;

	public Sedan(String color) {
		System.out.println("sedan 생성자입니다");
		this.color = color;
	}
}

class Sonata extends Sedan{
	
	public Sonata(String color) {
//		super(); // 부모 생성자 호출 && 첫줄에만 올 수 있음 (해당 키워드가 없으면 컴파일러가 만들어줌)
		super(color);
		System.out.println("sonata 생성자입니다");

	}
}


public class Ex02 {
	public static void main(String[] args) {
		Sonata sonata = new Sonata("빨강");
		System.out.println(sonata.color); 
		
	}
}

상속 관계에서의 오버라이딩

- 부모클래스의 private 접근제한을 갖는 필드와 메소드는 자식이 물려받을 수 없다
- 부모와 자식클래스가 서로 다른 패키지에 있다면 부모의 default 접근제한을 갖는 멤버도 자식이 물려받을 수 없다
- 그외 경우는 모두 상속의 대상이 된다
  

class Suv{
	private String color;
	int speed = 100;
	
	public void run() {
		System.out.println("SUV 차량이 달립니다");
	}
}

class Santafe extends Suv{
	int speed = 120;
	
	@Override 
	public void run() {
		System.out.println("싼타페 차량이 달립니다");
//		super.run();
	}
	
	public void disp() {
		System.out.println("부모"  + super.speed);
		super.run();
		System.out.println("자식"  + speed);
		run();
		
	}
	
	// 부모클래스에 상속받은 멤버필드의 이름과 자식클래스에서 만든 멤버필드의 이름이 같을 경우
	// 부모 클래스의 멤버를 사용하기 위해서는 super라는 키워드를 사용해야 한다
	// 자식클래스는 this가 생략되어 있어서 그냥 사용하면 자식클래스의 멤버가 사용된다
	
}

public class Ex03 {
	public static void main(String[] args) {
		Santafe santafe = new Santafe();
//		santafe.run();
		santafe.disp();
	}
}

=================================================2교시 끝

어노테이션 :: 소스코드에 메타 코드를 주는 것
메타코드 :: 메타 정보를 주는 것 
메타 정보 :: 주요 정보가 아닌 부가 정보  
런타임시(실행시) 특정 기능을 실행하도록 정보 제공

@Override 어노테이션 :: 컴파일러에게 코드 문법 에러를 체크하도록 정보를 제공한다

> 메소드 선언시 사용되며 메서드 오버라이드 된 것 임을 컴파일러에게 알려주어 컴파일러가 체크

> 체크했을 때 오버라이드가 되지 않았다면 컴파일러는 에러를 발생시킨다(부모와 동일한 메서드 시그니처를 가져왔는지 확인)

부모클래스 메소드 오버라이딩 실습

class Car{
	int speed;
	
	public void upSpeed(int speed) {
		this.speed += speed;
		System.out.println("현재속도 car 클래스 "  + this.speed);
	}
}

class Genesis extends Car{

	@Override
	public void upSpeed(int speed) {
		super.speed += speed;
		if(super.speed > 200) {
			super.speed = 200;
		}
		System.out.println("현재속도 car 클래스 "  + this.speed);
	}
}

public class Ex04 {
	public static void main(String[] args) {
		Car car = new Car();
		car.upSpeed(300);
		
		Genesis genesis = new Genesis();
		genesis.upSpeed(300);
		
	}
}

// console 
현재속도 car 클래스 300
현재속도 car 클래스 200

java 다형성 :: 하나 이상의 형태를 뜻한다(= 여러개의 형태를 갖는다)  자바에서의 다형성이란 동일한 이름을 사용하지만 다양한 객체를 이용해서 다양한 실행결과가 나오도록 하는 성질이다. 하나의 이름으로 실행결과가 여러개가 나온다는 말

부모타입으로 자식객체를 사용하는 것 / 다형성을 구현하려면 메소드 재정의(오버라이딩)와 타입변환이 필요하다 

자식의 객체를 부모타입의 변수에 담을 수 있음 > >>> 다형성 *** 부모는 자식을 품을 수 있다 

자식은 부모타입으로 자동 타입 변환이 가능함 / 부모타입변수 = 자식객체 [자동타입변환 (upcasting)]

** 제약사항 :: 부모타입으로 자동 타입변환 된 이후에는 부모클래스에 선언된 필드와 메소드만 접근 가능하다.

변수는 자식 객체를 참조하지만 변수로 접근 가능한 멤버는 부모클래스 멤버로만 한정됨/ 하지만 메소드가 자식 클래스에서 재정의 되었다면 자식클래스의 메소드가 대신 호출됨 

강제타입변환[down casting] >> 자식 타입이 부모타입으로 자동 타입 변환 후 다시 자식타입으로 변환할 때 강제 타입변환을 시킬 수 있음 >> 자식에만 선언된 멤버만을 사용해야 할 때 

***어떤 객체가 어떤 클래스의 인스턴스인지 확인하기 위해 instanceof 연산자를 사용함 

Boolean result = 좌항(객체) instanceof 우항(타입) >>> 좌항의 객체가 우항의 타입으로 생성된 객체라면 true  아니면 false

**** 자동타입변환은 주로 메소드 호출할때 많이 발생함 

매개변수의 타입을 부모타입으로 선언하면 매개값을 자식타입으로 받을 수 있음 /// ? 무슨말인지 다시 정리하기

class Parent{
	int parentMoney = 1000;
}

class Child extends Parent{
	int childMoney = 500;
}

public class Ex01 {
	public static void main(String[] args) {
		Parent poly = new Child(); // 자동타입변환 upcasting
		// 다형성은 부모타입의 변수에 자식객체를 담는 것(부모 멤버에만 접근가능)
		// 부모 위주이다 >> 객체는 자식객체이지만 타입은 부모타입임 
		
		System.out.println(poly.parentMoney);
//		System.out.println(poly.childMoney); // 자식멤버 접근 안됨
		System.out.println();
		
		Child poly2 = (Child)poly; // 다운캐스팅(강제 타입변환)
		System.out.println(poly2.childMoney); // 부모필드와 자식필드 모두 쓸 수 있게 됨 
		System.out.println(poly2.parentMoney); 
		
		Parent poly3 = poly2; // 자동타입변환 upcasting
		System.out.println(poly3.parentMoney);
	}
    
 // console
 1000

500
1000
1000

=================================================3교시 끝

// 다형성 부모클래스 타입의 변수에 자식객체를 담는것
// 부모클래스가 가지고 있는 모든 멤버들에 접근할 수 있다
// 단 자식 클래스에서 메소드 오버라이딩을 했다면 오버라이딩된 자식의 메소드가 호출됨
// 자식 클래스만 있는 멤버는 오버라이딩 된 자식 클래스의 메소드에 의해서만 접근할 수 있다

class Run{
	int speed = 100;
	public void run() {
		System.out.println("부모 클래스 " + speed);
	}
}
class Person extends Run{
	String name = "홍길동";
	public void walk() {
		System.out.println("person 클래스 " + name);
	}
	
	@Override
	public void run() {
		System.out.println(name + "이 " + speed + "의 속도록 달린다");
		walk();
	}
	
	
}
class KiaCar extends Run{
	String model = "k5";
	public void parking() {
		System.out.println("kiacar 클래스 " + model);
	}
	@Override
	public void run() {
		System.out.println("kiacar 클래스 " + model + "speed 는" + speed);
		parking();
	}
}

public class Ex02 {
	public static void main(String[] args) {
		Run run = new Person();
		System.out.println(run.speed);
		run.run(); // 자식 멤버필드와 멤버 메서드에 접근이 안됨
		System.out.println();
		run = new KiaCar();
		run.run();
	}
}


// console
100
홍길동이 100의 속도록 달린다
person 클래스 홍길동

kiacar 클래스 k5speed 는100
kiacar 클래스 k5

필드의 다형성

class Car{
	Tire tire = new Tire();
}

class Tire{
	public String tireName;
	public Tire() {
		tireName = "정품타이어";
	}
	public String getTireName() {
		return tireName;
	}
}

class hakTire extends Tire{
	public hakTire() {
		tireName = "한국타이어";
	}
}

class khkTire extends Tire{
	public khkTire() {
		tireName = "금호타이어";
	}
}

public class Ex03 {
	public static void main(String[] args) {
		Car car = new Car();
		System.out.println(car.tire.getTireName()); 
		car.tire = new hakTire();
		// 필드의 다형성 
		System.out.println(car.tire.getTireName()); 
		car.tire = new khkTire();
		System.out.println(car.tire.getTireName()); 
		// 이런식으로 객체를 부품처럼 조립하는 형태로 프로그래밍 하기 위함
		// 필드의 타입을 부모타입으로 선언해두면 다양한 자식 객체들이 저장될 수 있고
		// 이 때문에 필드 사용 결과가 달라질 수 있다
		
	}
}

// console
정품타이어
한국타이어
금호타이어

매개변수의 다형성

package poly;

class Vehicle{
	public void run() {
		System.out.println("차량이 달립니다");
	}
}

class Driver{
	public void drive(Vehicle vehicle) {  // 매개변수가 부모의 타입으로 되어 있으면 자식 객체를 받을 수 있음
		
		if(vehicle instanceof Bus) { // 객체 타입인하여 메서드 사용
			Bus bus = (Bus)vehicle;
			bus.checkFare(); // 강제 타입변환 안하면 부모멤버만 쓸수있으니까 사용 못함
		}
		System.out.println("드라이브를 시작합니다");
		vehicle.run();
	}
}

class Bus extends Vehicle{

	@Override
	public void run() {
		System.out.println("버스가 달립니다");
	}
	public void checkFare() {
		System.out.println("요금확인");
	}
}

class Taxie extends Vehicle{
	@Override
	public void run() {
		System.out.println("택시가 달립니다");
	}
	
	
}

public class Ex04 {
	public static void main(String[] args) {
		Driver driver = new Driver();
		Bus bus = new Bus();
		Taxie taxie = new Taxie();
		
		driver.drive(taxie);
		System.out.println();
		driver.drive(bus);
		System.out.println();
		driver.drive(taxie); // 캐스팅 안됨
		// 매개변수가 부모의 타입으로 되어 있으면 자식 객체를 받을 수 있음
	}
}

// cosole 

드라이브를 시작합니다
택시가 달립니다

요금확인
드라이브를 시작합니다
버스가 달립니다

드라이브를 시작합니다
택시가 달립니다

=================================================4교시 끝

**오늘 추상화 까지 나가고 인터페이스는 다음시간에 나갈 예정 

객체를 직접 생성할 수 있는 클래스를 실체클래스라고 한다면 이 클래슫들의 공통 특성을 추출해서 선언한 클래스를 추상클래스라고 함 

추상 클래스가 부모이고 실체 클래스가 자식 클래스라고 보면 됨 / 실체클래스는 추상클래스의 모든 특성을 물려받고 추가적인 특성을 가질 수 있음

실체클래스를 설계하는 사람이 여러 사람일 경우, 실체 클래스마다 필드와 메소드가 제각기 다른 이름을 가질 수 있다

추상클래스는 실체클래스의 필드와 메소드 이름을 통일할 용도로 사용한다

실체클래스가 가져야 할 필드와 메소드를 미리 추상클래스에 정의하므로 실체클래스 설계 규격을 만들고자할때 사용함

** 즉 , 추상클래스는 직접 사용하는 클래스가 아님/ 객체를 생성하는 용도가 아님

abstract 키워드를(추상클래스) 붙이면 new연산자를 이용해서 객체를 못만들고 상속을 통해서 자식 클래스로 만듬

**자식클래스는 반드시 추상메소드를 재정의해서 실행내용을 작성해야 함 >>> 실행블록을 가질수가 없고 선언부만 있음

 

abstract class Animal { 
	// abstract 키워드를 붙이면 추상클래스가 됨
	// 추상클래스가 되면 객체를 직접 생성할수가 없음
	public void eat() {
		System.out.println("냠");
	}
	
	abstract void sound();
	// 추상메소드 :: 실제 구현은 자식클래스에서 함 (선언부만 있고 실행블록 가지지 못함)
	// 만약, 클래스 내부에 추상 메소드가 하나라도 있으면 그 클래스는 추상 클래스가 됨
	// 즉 일반 클래스에서는 추상 메소드를 만들 수 없다는 뜻
}

class Dog extends Animal{
	// 추상메소드 오버라이딩 안하면 오류남
	// 자식클래스에서 부모의 추상메소드는 강제 오버라이딩해야함
	@Override 
	void sound() {
		System.out.println("멍멍");
	}
	
}

class Cat extends Animal{
	// 추상메소드 오버라이딩 안하면 오류남
	// 자식클래스에서 부모의 추상메소드는 강제 오버라이딩해야함
	@Override 
	void sound() {
		System.out.println("야옹");
	}
	
}

public class Ex01 {
	public static void main(String[] args) {
//		Animal animal = new Animal(); // 추상클래스는 객체를 직접 생성하지 못함
		Dog dog = new Dog();
		Cat cat = new Cat();
		dog.sound();
		cat.sound();
	}
}

// console
멍멍
야옹

추상클래스 연습

package abstraction;

abstract class Worker{
	String name;
	public Worker(String name) {
		this.name = name;
	}
	
	public abstract void work();
	public abstract void eat();
}

// worker클래스 상속받는 TaxiDriver 클래스 만들고 추상메소드 오버라이딩 해서 재정의
// worker클래스 상속받는 Cleaner 클래스 만들고 추상메소드 오버라이딩 해서 재정의


class TaxiDriver extends Worker{
	
	public TaxiDriver(String name) {
		super(name);
	}

	@Override
	public void work() {
		System.out.println("일해라" + name);
	}

	@Override
	public void eat() {
		System.out.println("먹어라 " + name);
		
	}
}

class Cleaner extends Worker{

	public Cleaner(String name) {
		super(name);
	}

	@Override
	public void work() {
		System.out.println("청소해라 " + name);
	}

	@Override
	public void eat() {
		System.out.println("구내식당가라 " + name);
	}
}


public class Ex02 {
	public static void main(String[] args) {
		TaxiDriver driver = new TaxiDriver("홍길동");
		driver.work();
		driver.eat();
		
		System.out.println();
		Cleaner cleaner = new Cleaner("성춘향");
		cleaner.work();
		cleaner.eat();
	}
}

// console
일해라홍길동
먹어라 홍길동

청소해라 성춘향
구내식당가라 성춘향

싱글톤 디자인 패턴 :: 객체를 하나만 생성하는 것을 보장

(외부에서 new 연산자를 통해 객체를 생성하지 못하도록 하는 것)

package singleton;

public class Singleton {
	private Singleton() {
		
	}
	
	private static Singleton instance = new Singleton();
	// 자기 자신을 갖는 정적 필드를 만듬
	
	// 위의 정적 필드를 반환해주는 정적 메소드를 만들어준다
	public static Singleton getInstance() {
		return instance;
	}
	// new 연산자를 한번 사용했기때문에 싱글톤으로 리턴받는 객체는 같은 객체임
	// 이렇게 싱글톤은 객체를 하나만 생성하도록 보장하는 패턴임
}


=================================================================================

package singleton;

public class SingletonMain {
	public static void main(String[] args) {
		// Singleton s1 = new Singleton(); 싱글톤 사용하면 이렇게 객체 여러개 못만듬
		// Singleton s2 = new Singleton();
		Singleton s1 = Singleton.getInstance(); 
		Singleton s2 = Singleton.getInstance(); 
		
		
		if(s1 == s2 ) {
			System.out.println("같은 객체");
		}else {
			System.out.println("다른 객체");
		}
		
	}
}

다음시간에 인터페이스랑 기본 API 진도나가고

마지막 날에 collection framework 랑 IO 클래스까지 해서 수업 마무리 예정

'Java' 카테고리의 다른 글

클래스 상속과 인터페이스 사용 목적 정리  (1) 2022.11.23
다형성_추상클래스 / 인터페이스 정리  (0) 2022.11.23
새싹체험_java_1022  (0) 2022.10.22
새싹체험_java_1016  (0) 2022.10.17
새싹체험_java_1015  (0) 2022.10.15