일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 자바
- S&P500
- 인플레이션
- object
- 다형성
- 제태크
- 객체지향
- FCF
- 미국주식
- 주린이
- 현금흐름표
- 주식
- 금리인하
- 오버라이딩
- 기업분석
- 프로그래머스
- 그리디 알고리즘
- 금리인상
- XLF
- 알고리즘
- 접근제어자
- Java
- 무디스
- 백준
- javascript
- 잉여현금흐름
- etf
- 배당성장
- mco
- StringBuffer
- Today
- Total
오늘의하루
[JAVA] 객체지향 2편 제어자 다형성 본문
1. 제어자
- 클래스, 변수, 메서드의 선언부에 사용되어 부가적인 의미를 부여한다.
- 제어자는 크게 접근 제어자와 그 외 제어자로 나뉜다.
- 접근 제어자 : public, protected, default, private
- 그 외 제어자 : static, final, abstract, native, transient, synchronized, volatile, strictfp
- 하나의 대상에 여러 개의 제어자를 조합해서 사용할 수 있지만 접근 제어자는 단 하나만 사용이 가능하다.
1-1. 그 외 제어자에 대해 알아보기
static - 공통적인
static이 사용될 수 있는 곳은 멤버 변수, 메서드, 초기화 블록이다.
- 멤버 변수
- 모든 인스턴스에 공통적으로 사용되는 클래스 변수가 된다.
- 클래스 변수는 인스턴스를 생성하지 않고도 사용이 가능하다.
- 클래스가 메모리에 로드될 때 생성된다.
- 메서드
- 인스턴스를 생성하지 않고도 호출이 가능한 static 메서드가 된다.
- static 메서드 내에서는 인스턴스 변수를 사용할 수 없다.
class T{
// 클래스 변수
static int width = 200;
static int height = 100;
// 클래스 변수 초기화 블럭(복잡)
static {}
// static 메서드
static int max(int a, int b){ // 인스턴스 변수 사용 x
return a > b ? a : b;
}
}
final - 변경될 수 없는
final이 사용될 수 있는 곳은 클래스, 메서드, 멤버 변수, 지역변수이다.
- 클래스
- 다른 클래스의 부모가 될 수 없다. (확장이 불가능하다.)
- 메서드
- 오버 라이딩을 통해 재 정의될 수 없다.
- 멤버 변수, 지역 변수
- 값을 변경할 수 없는 상수가 된다.
// 상속 불가 메서드
final class Test{
// 상수
final int iv = 10;
// 오버라이딩 불가 메서드
final void get(){
final lv = iv;
}
}
class T extends Test{ // 💥Error > final class는 상속할 수 없다.
void get(){}; // 💥 Error > final 메서드는 오버라이딩 할 수 없다.
}
final 멤버 변수 초기화
final이 붙은 변수는 상수이므로 보통 선언과 초기화를 동시에 하지만 인스턴스 변수의 경우 생성자를 통해 단 한 번만 초기화할 수 있다.
class card{
final int num;
final String kind;
static int width = 300;
// 생성자를 통해 final 멤버 변수 초기화 (단 한번)
card(int num, String kind){
this.num = num;
this.kind = kind;
}
card(){
this("HEART",1);
}
}
public static void main(String[] args){
card a = new card("HEART", 10);
// 💥 Error : 상수는 선언과 동시에 초기화 하던지 생성자를 통해 단한번 초기화 해야한다.
a.num = 4;
}
abstract - 미완성의
abstract가 사용될 수 있는 곳은 클래스, 메서드이다.
- 클래스
- 클래스 내에 추상 메서드가 선언되어 있음을 의미한다.
- 메서드
- 선언 부만 작성하고 구현부가 없는 추상 메서드임을 알린다.
abstract class T{ // 추상 클래스
abstract void method(); // 추상 메서드
}
1-2. 접근 제어자에 대해 알아보기
접근 제어자는 외부로부터 접근을 제한하여 데이터를 보호하며 내부적으로만 사용되는 부분을 감추기 위해 사용된다.
- public : 접근 제한이 없다.
- 클래스, 멤버 변수, 메서드에서 사용이 가능하다.
- protected : 같은 패키지 및 다른 패키지의 자식 클래스에서만 접근이 가능하다.
- 클래스에 사용이 불가능하다.
- 멤버 변수, 메서드에서 사용이 가능하다.
- default : 같은 패키지에서만 접근이 가능하다.
- 클래스, 멤버 변수, 메서드에서 사용이 가능하다.
- default의 경우 생략이 가능하다.
- private : 같은 클래스 내에서만 접근이 가능하다.
- 클래스에 사용이 불가능하다.
- 멤버 변수, 메서드에서 사용이 가능하다.
(default)class Time{
private int hour;
Time(int hour, int minute, int second){
//super();
this.hour = hour;
}
public int getHour(){return hour;}
public void setHour(int hour){
if (hour < 0 || hour > 23){
return;
}
this.hour = hour;
}
}
public static void main(String[] args){
Time test = new Time(10);
// 💥 Error : private 변수는 외부 클래스에서 접근이 불가능하다.
System.out.println(test.hour);
test.hour = 3;
// private 변수를 사용하고 싶다면 메서드를 통해 접근해야한다.
test.setHour(22); // private 변수 hour의 값을 변경한다.
System.out.println(test.getHour()); // private 변수 hour을 보여준다.
}
제어자 총 종리
- 클래스
- public, default, final, abstract
- 메서드
- 모든 접근 제어자, final, abstract, static
- 멤버 변수
- 모든 접근 제어자, final, static
- 지역 변수
- final
Q. 메서드에 static과 abstract를 같이 사용할 수 없는 이유는?
A. static 메서드는 구현부가 있는 메서드만 사용할 수 있기 때문이다.
Q. 클래스에 abstract와 final을 같이 사용할 수 없는 이유는?
A. abstract는 상속을 통해 완성돼야 하기 때문에 상속을 하지 못하는 final을 같이 사용할 수 없다.
Q. abstract 메서드의 접근제어자로 private을 사용할 수 없는 이유는?
A. abstract 메서드는 상속을 통해 완성돼야 하는데 private일 경우 자식 클래스에서 접근할 수 없기 때문이다.
Q. 메서드에 private과 final을 같이 사용할 수 없는 이유는?
A. private 메서드는 외부에서 접근을 못하기 때문에 오버 라이딩을 할 수 없고 final 메서드는 오버 라이딩을 하지 못하게 만들기 때문에 의미가 중복된다.
2. 다형성
부모 타입의 참조 변수로 자식 타입의 객체를 다룰 수 있는 것을 다형성이라고 부른다.
다형성의 장점
- 하나의 참조 변수로 여러 타입의 객체를 참조할 수 있다.
- 여러 가지 형태를 가질 수 있다.
다형성을 사용할 때 기억해두어야 할 점은 부모 타입의 참조 변수는 자식 타입의 인스턴스를 참조할 수 있지만 반대의 경우는 성립되지 않는다.
(default)class Tv{
int channel;
Tv(){
this(1);
}
Tv(int x){
//super();
this.channel = x;
}
void channelUp(){
++channel;
}
}
class SmartTv extends Tv{
String text;
SmartTv(){
this(1,"Hello Java");
}
SmartTv(int x, String text){
super(x);
this.text = text;
}
void caption(){
System.out.println(text);
}
}
public static void main(String[] args){
SmartTv S = new SmartTv(); // 총 멤버 : 4 | 사용 가능 멤버 : 4
Tv T = new SmartTv(); // 총 멤버 : 4 | 사용 가능 멤버 : 2
// 💥 Error : Tv 타입의 참조변수 T는 caption() 메서드를 가지고 있지 않다.
T.caption();
// 💥 Error : Tv 타입의 참조변수 T는 String text 인스턴스 변수를 가지고 있지 않다.
T.text = "hi~";
}
2-1. 참조 변수의 형 변환
서로 상속 관계에 있는 타입 간의 형 변환만 가능하다.
class car{
String color;
void drive(){
System.out.println("drive~~");
}
void stop(){
System.out.println("stop");
}
}
class fireEngine extends car{
void water(){
System.out.println("water~");
}
}
public static void main(String[] args){
fireEngine f = new fireEngine();
// 참조변수 f에 fireEngine 인스턴스의 주소 저장
car c = null;
// 참조변수 c에 null을 저장
c = (car)f;
// car타입의 참조변수 c에 fireEngine 인스턴스 주소를 저장
// 두개의 참조변수 타입이 같아야 하므로 참조변수 f의 타입을 car타입으로 형변환 시켜준다.
// car타입에는 변수 color, 메소드 drive, stop 있다.
// 생성된 인스턴스에는 메서드 water가 있지만 사용할 수 없다.
c.water(); // 💥 Error
fireEngine f2 = null;
// 참조변수 f2에 null을 저장
f2 = (fireEngine)c;
// fireEngine타입의 참조변수 f2에 fireEngine 인스턴스 주소를 저장
// 참조변수 c의 타입은 car이기 때문에 fireEngine으로 형변환 시켜준다.
// fireEngine 타입에는 모든 멤버가 있기 때문에 모두 사용 가능하다.
f2.water(); // ⭐ 정상작동
}
2-2. instanceof 연산자
- 참조 변수가 참조하는 인스턴스의 실제 타입을 체크하는 데 사용한다.
- 이항 연산자이며 피연산자는 참조형 변수와 타입 연산 결과는 true, false로 반환한다.
- instanceof 연산 결과가 true이면 해당 타입으로 형 변환이 가능하다.
A instanceof B 연산자를 읽는 방법은 A의 부모 타입에 B가 있다면 true 아니라면 false를 반환합니다.
class car {
void drive(){
System.out.println("drive");
}
}
class fire extends car{
void water(){
System.out.println("watre~");
}
}
public static void main(String args[]) {
fire a = new fire();
car c = new car();
if(a instanceof fire){
System.out.println("This is a fire instance");
}
if(a instanceof car){
System.out.println("This is a car instance");
}
if(a instanceof Object){
System.out.println("This is a Object instance");
}
if(c instanceof fire){
System.out.println("car의 부모타입에는 fire가 없으므로 실행 x");
}
}
// 결과
// This is a fire instance
// This is a car instance
// This is a Object instance
2-3. 참조 변수와 인스턴스 변수의 연결
- 멤버 변수가 중복 정의된 경우 참조 변수의 타입에 따라 연결되는 멤버 변수가 달라진다.
- 참조 변수 타입에 영향을 받는다.
- 메서드가 중복 정의된 경우 참조 변수의 타입에 관계없이 항상 실제 인스턴스의 타입에 정의된 메서드가 호출된다.
- 참조 변수 타입에 영향을 받지 않는다.
public static void main(String args[]) {
Parent p = new Child();
Child c = new Child();
System.out.println("p.x = " + p.x); // p.x = 10
p.method(); // Child method
System.out.println("c.x = " + c.x); // c.x = 20
c.method(); // Child method
Parent2 p2 = new Child2();
Child2 c2 = new Child2();
System.out.println("p2.x = " + p2.x); // p2.x = 30
p2.method(); // Parent2 method
System.out.println("c2.x = " + c2.x); // c2.x = 30
c2.method(); // Parent2 method
}
class Parent{
int x = 10;
void method(){
System.out.println("Parent method");
}
}
class Child extends Parent{
int x = 20;
void method(){ // 오버라이딩
System.out.println("Child method");
}
}
class Parent2{
int x = 30;
void method(){
System.out.println("Parent2 method");
}
}
class Child2 extends Parent2{ }
2-4. 매개변수의 다형성
참조형 매개변수는 메서드 호출 시 자신과 같은 타입 또는 자식 타입의 인스턴스를 넘겨줄 수 있다.
public class MyClass {
public static void main(String args[]) {
Product tv = new Tv(10);
Product audio = new Audio(5);
Buyer buyer = new Buyer();
buyer.buy(tv);
System.out.println(buyer.money);
}
}
class Product {
int price;
Product(int x){
price = x;
}
}
class Tv extends Product{
Tv(int x){
super(x);
}
}
class Audio extends Product{
Audio(int x){
super(x);
}
}
class Buyer{
int money;
Buyer(){this(1000);}
Buyer(int x){
money = x;
}
// 매개변수의 다형성 사용 O
// 물건이 추가되더라도 이 코드는 수정하지 않아도 된다.
void buy(Product p){
money = money - p.price;
}
// 매개변수의 다형성 사용 x
// 물건이 추가되면 이 코드를 수정해줘야 한다.
void buy2(Tv t){
money = money - t.price;
}
void buy2(Audio a){
money = money - a.price;
}
}
2-5. 여러 종류의 객체를 하나의 배열로 다루기
원래 배열은 같은 타입만 가능하지만 다형성을 이용하면 부모 타입의 배열에 각기 다른 자식 타입들의 인스턴스를 담을 수 있습니다.
import java.util.*;
public class MyClass {
public static void main(String args[]) {
// 다형성을 이용해서 자식 타입의 객체를 생성후 부모 타입의 참조변수에 주소를 저장시킨다.
Product tv = new Tv(10);
Product audio = new Audio(5);
Buyer buyer = new Buyer();
buyer.buy(tv); // tv 구매
buyer.buy(tv); // tv 구매
buyer.buy(audio); // audio 구매
System.out.println(buyer.money); // buyer 남은 돈 확인
System.out.println(Arrays.toString(buyer.cart)); // 구매 물품 배열로 확인
System.out.println(buyer.cart[0].price); // 배열의 0번째에 들어있는 물건 가격확인
System.out.println(buyer.sum); // 배열에 있는 모든 가격 합산
}
}
class Product {
int price;
Product(int x){
price = x;
}
}
class Tv extends Product{
Tv(int x){
super(x);
}
}
class Audio extends Product{
Audio(int x){
super(x);
}
}
class Buyer{
int money;
Product[] cart = new Product[10]; // 부모타입에 배열 생성
int i = 0;
int sum = 0;
Buyer(){this(1000);}
Buyer(int x){
money = x;
}
void buy(Product p){
money = money - p.price;
sum = sum + p.price;
cart[i++] = p; // 배열에 하나씩 차곡차곡 자식들의 객체를 담는다.
}
}
'JAVA' 카테고리의 다른 글
[JAVA] 예외처리 (0) | 2022.08.03 |
---|---|
[JAVA] 객체지향 추상클래스 인터페이스 내부클래스 (0) | 2022.08.03 |
[JAVA] 객체지향 2편 (0) | 2022.08.01 |
[JAVA 공부 6일차] static, final, abstract, 접근 제어자 알아보기 (0) | 2022.07.27 |
[JAVA 공부 6일차] 객체지향 Part 4 (0) | 2022.07.27 |