//문제가 없다.
int a = 10;
int b = 20;
//컴파일러가 묵시적 형변환을 해준다. c = (double) a
double c = a;
//이 부분이 에러가 난다.
float d = 5.1f;
int e = d;
-> java: incompatible types: possible lossy conversion from double to int 라는 에러가 Intellij에서 실행시키면 발생한다.
에러가 발생하는 이유
int e = (int) d
따라서 위와 같이 수동 형변환을 해야한다. float 형태로 int 타입으로 형변환을 했기 때문에 데이터 손실이 발생한다. but 실행은 된다.
-> 결론부터 말하면 상속만으로는 중복제거가 쉽지 않다. 따라서 구성을 사용한다.
// 1단계
class Main {
public static void main(String[] args) {
전사타입A a전사타입A = new 전사타입A();
a전사타입A.공격();
전사타입D a전사타입D = new 전사타입D();
a전사타입D.공격();
}
}
class 전사타입A extends 전사 {
void 공격() {
System.out.println("칼로 공격");
}
}
class 전사타입D extends 전사타입C {
void 공격() {
System.out.println("활로 공격");
}
}
class Main {
public static void main(String[] args) {
전사타입A a전사타입A = new 전사타입A();
a전사타입A.공격();
전사타입B a전사타입B = new 전사타입B();
a전사타입B.공격();
전사타입C a전사타입C = new 전사타입C();
a전사타입C.공격();
전사타입D a전사타입D = new 전사타입D();
a전사타입D.공격();
}
}
class 전사{
}
class 전사타입A extends 전사 {
void 공격() {
new 칼().작동();
}
}
}
class 전사타입D extends 전사타입C {
void 공격() {
new 활().작동();
}
}
class 칼 {
void 작동() { System.out.println("칼로 공격"); }
}
class 활 {
void 작동() { System.out.println("활로 공격"); }
}
class Main {
public static void main(String[] args) {
전사타입A a전사타입A = new 전사타입A();
a전사타입A.공격();
//신무기 나오면 이렇게 교체하면 된다.
a전사타입D.a무기 = new 로켓런처();
a전사타입D.공격(); // 로켓이 발사됩니다.
}
}
abstract class 전사 {
무기 a무기;
void 공격() {
a무기.작동();
}
}
class 전사타입A extends 전사 {
전사타입A() { a무기 = new 칼(); }
}
class 전사타입D extends 전사 {
전사타입D() { a무기 = new 활(); }
}
abstract class 무기 { abstract void 작동(); }
class 칼 {
void 작동() { System.out.println("칼로 공격"); }
}
class 활 {
void 작동() { System.out.println("활로 공격"); }
}
class 로켓런처 extends 무기 {
void 작동() { System.out.println("로켓이 발사됩니다."); }
}
-> 위와 같이 상속과 구성을 함께 사용하면 중복코드를 좀 더 수월하게 제거할 수 있다.
class Main {
public static void main(String[] args) {
//생성자 호출 순서 : Object -> 생물 -> 동물 -> 오리 -> 천둥오리
천둥오리 천둥오리 = new 천둥오리();
}
}
//모든 클래스는 extends Object가 생략되었다.
//즉, 모든 클래스는 Object 클래스의 자식이다.
class 생물{
생물(){
System.out.println("생물");
}
void 호흡(){}
}
class 동물 extends 생물{
동물(){
System.out.println("동물");
}
void 먹기(){}
}
class 오리 extends 동물{
오리(){
System.out.println("오리");
}
void 날기(){}
}
class 천둥오리 extends 오리{
천둥오리(){
System.out.println("천둥오리");
}
void 긴거리이동(){}
}
class Main {
public static void main(String[] args) {
int[] datas = new int[2];
try {
work(datas);
}
catch ( ArrayIndexOutOfBoundsException e ) { // main 함수 입장에서 이 코드는 가독성이 떨어진다.
System.out.println("이런.. 오류가 발생했군요.");
}
}
static void work(int[] datas) {
datas[0] = 10;
datas[1] = 20;
datas[2] = 30; // 여기서 자동으로 throw new ArrayIndexOutOfBoundsException(); 이 발생한다.
}
}
class Main {
public static void main(String[] args) {
int[] datas = new int[2];
try {
work(datas);
}
//work()에 발생한 에러를 여기서 처리
catch ( IllegalArgumentException e ) {
System.out.println("하하");
}
}
static void work(int[] datas) {
//try-catch로 예외를 잡는거보다 이러한 방법이 더 낫다.
if ( datas.length < 3 ) {
throw new IllegalArgumentException();
}
datas[0] = 10;
datas[1] = 20;
datas[2] = 30;
}
}
class Main {
public static void main(String[] args) {
int[] datas = new int[2];
try {
work(datas);
}
catch ( 입력된_배열의_사이즈가_3보다_작은_Exception e ) { // 코드 가독성이 v2 보다 좋음, 단 예외클래스를 만들어야 해서 귀찮음, 그래서 실무에서는 예외클래스를 꼭 필요할 때만 직접 만듬
System.out.println("이런.. 오류가 발생했군요.");
}
}
static void work(int[] datas) {
if ( datas.length < 3 ) {
throw new 입력된_배열의_사이즈가_3보다_작은_Exception(); // 함수가 여기서 멈춤
}
datas[0] = 10;
datas[1] = 20;
datas[2] = 30;
}
}
class 입력된_배열의_사이즈가_3보다_작은_Exception extends RuntimeException { }