public interface Comparator {
int compare(Object o1, Object o2); //o1, o2 두 객체 비교
boolean equals(Object obj); //equals를 오버라이딩하라는 뜻
}
public interface Comparable {
int compareTo (Object o); // 주어진 객체 o 를 자신과 비교
}
public final class Integer extends Number implements Comparable {
...
public in t compareTo(Integer anotherInteger) {
int v1 = this.value;
int v2 = anotherInteger.value;
//같으면 0, 오른쪽값이 크면 -1, 작으면 1을 반환
return (v1 < v2 ? -1: (v1==v2? 0 :1));
}
...
}
예제 Ex11_7
import java.util.*;
class Ex11_7 {
public static void main(String[] args) {
String[] strArr = {"cat", "Dog", "lion", "tiger"};
Arrays.sort(strArr); // String의 Comparable 구현에 의한 정렬
System.out.println("strArr=" + Arrays.toString(strArr));
Arrays.sort(strArr, String.CASE_INSENSITIVE_ORDER); // 대소문자 상관 없이 정렬
System.out.println("strArr=" + Arrays.toString(strArr));
Arrays.sort(strArr, new Descending()); //역순으로 정렬
System.out.println("strArr=" + Arrays.toString(strArr));
}
}
class Descending implements Comparator {
public int compare(Object o1, Object o2){
if( o1 instanceof Comparable && o2 instanceof Comparable) {
Comparable c1 = (Comparable)o1;
Comparable c2 = (Comparable)o2;
return c1.compareTo(c2) * -1 ; //-1을 곱해서 기본 정렬방식의 역으로 변경
// 또는 c2.compareTo(c1)와 같이 순서를 바꿔도 됨
}
return -1;
}
}
Integer와 Comparable
삼항연산자가 기본사칙연산보다 상대적으로 빠르다 (2~3% 정도)
버블정렬 bubble sort 코드
서로 인접한 두 원소의 대소를 비교하고, 조건에 맞지 않다면 자리를 교환하며 정렬하는 알고리즘
List list = new ArrayLsit(); //다른 컬렉션으로 변경할 때는 이 부분만 고치면 된다.
Iterator it = list.interator();
while(it.hasNext()) { //boolean has Next()
System.out.println(it.next());
}
iterator는 1회용이라 다쓰고나면 다시 얻어와야 한다
Map과 Iterator
Map에는 iterator()가 없음
Keyset(), entrySet(), values()를 호출해야함
Map map = new HashMap();
.
.
.
Iterator it = map.entrySet().iterator();
interface 인터페이스이름 {
public static final 타입 상수이름 = 값; //상수
public abstract 메서드이름(매개변수목록); //추상메서드
}
//인터페이스의 모든 메소드는 public이고 final이고 abstract 여서 생략 가능
인터페이스의 상속
인터페이스의 조상은 인터페이스만 가능(Object가 최고 조상이 아님)
다중 상속이 가능 (추상메서드는 충돌해도 문제 없음)
interface Fightable extends Movable, Attackable {}
interface Movable {
/** 지정된 위치(x,y)로 이동하는 기능의 메서드 */
void move(int x, int y);
}
interface Attackable {
/** 지정된 대상(u)을 공격하는 기능의 메서드 */
void attack(Unit u);
}
인터페이스의 구현
인터페이스에 정의된 추상 메서드를 완성하는 것
class 클래스이름 implements인터페이스이름 { // 인터페이스에 정의된 추상메서드를 모두 구현해야 한다 }
구현한다는 의미의 키워드 'implements'를 사용함
class Fighter implements Fightable {
public void move(int x, int y) { /*내용 생략 */}
public void attack(Unit u) { /*내용 생략 */} // 몸통 완성
}
//Fighter 클래스는 Fightable 인터페이스를 구현했다.
추상클래스 완성과 동일; 키워드만 다름
일부만 구현하는 경우, 클래스 앞에 abstract를 붙어야 함
인터페이스란?
추상 메서드의 집합
인터페이스의 구현이란?
인터페이스의 추상메서드 몸통{} 만들기(미완성 설계도 완성하기)
추상 클래스와 인터페이스의 공통점은?
추상 메서드를 가지고 있다 (미완성 설계도)
추상 클래스와 인터페이스의 차이점은?
인터페이스는 iv를 가질 수 없다
인터페이스를 이용한 다형성
인터페이스도 구현클래스의 부모
인터페이스 타입 매개변수는 인터페이스 구현한 클래스의 객체만 가능
인터페이스를 메서드를 리턴타입으로 지정할 수 있다
abstract class Unit2 {
int x, y;
abstract void move(int x, int y);
void stop() {
System.out.println("멈춥니다.");
}
}
interface Fightable { //인터페이스의 모든 메서드는 public abstract. 예외 없이
void move (int x, int y); // public abstract가 생략됨
void attack(Fightable f); // public abstract가 생략됨
}
class Fighter extends Unit2 implements Fightable{
//오버라이딩 규칙: 조상(public) 보다 접근제어자가 좁으면 안된다.
public void move (int x, int y) {
System.out.println("["+x+","+y+"]로 이동");
}
public void attack(Fightable f){
System.out.println(f+"를 공격");
}
}
public class FighterTest {
public static void main(String[] args) {
// Fighter f = new Fighter();
Unit2 u = new Fighter(); //Unit2에는 attack()이 없어서 호출불가
Fightable f = new Fighter();
u.move(100, 200);
// u.attack(new Fighter()); //Unit2에는 attack()이 없어서 호출불가
u.stop();
f.move(100, 200);
f.attack(new Fighter());
// f.stop(); //Fightable에는 stop()이 없어서 호출불가
}
}
인터페이스의 장점
두 대상(객체) 간의 '연결, 대화, 소통'을 돕는 '중간 역할'을 한다
GUI - Graphic User Interface
선언(설계, 껍데기)와 구현(알맹이)을 분리시킬수 있게 함
변경에 유리하고 유연한 코드가 됨
인터페이스 덕분에 B가 변경되어도 A는 안바꿀 수 있게 됨 -> 느슨한 결합
의존도가 낮아짐
개발 시간 단축 가능
변경에 유리한 유연한 설계 가능
표준화가 가능
서로 관계없는 클래스들을 관계를 맺어줄 수 있음
다중상속 가능
class A{
public void method(I i) { //인터페이스 I를 구현한 넘들만 들어와라
i.method();
}
}
// B클래스의 선언과 구현을 분
interface I {
public void method();
}
class B implements I{
public void method(){
System.out.println("B클래스의 메서드");
}
}
class C implements I{
public void method(){
System.out.println("C클래스의 메서드");
}
}
public class InterfaceTest {
public static void main(String[] args) {
A a = new A();
a.method(new C()); // A가 B를 사용(의존)
}
}
abstract class Player { //추상 클래스
abstract void play(int pos); //추상 메서드
abstract void stop(); //추상 메서드 (선언부만 있고 구현부{}가 없는 메서드)
}
//추상 클래스는 상속을 통해 완성해야 객체 생성가능
class AudioPlayer extends Player {
@Override
void play(int pos) {
System.out.println(pos+"위치부터 play 합니다");
}
@Override
void stop() {
System.out.println("재생을 멈춥니다.");
}
}
public class PlayerTest {
public static void main(String[] args) {
// Player p = new Player(); // 추상 클래스의 객체를 생성
// AudioPlayer ap = new AudioPlayer();
Player ap = new AudioPlayer(); //다형성
ap.play(100);
ap.stop();
}
}
추상클래스의 작성
- 여러 클래스에 공통적으로 사용될 수 있는 추상클래스를 바로 작성하거나 기존 클래스의 공통 부분을 뽑아서 추상클래스를 만든다
public class Ex7_10 {
public static void main(String[] args) {
// Unit[] group = new Unit[]{new Marine(), new Tank(), new Dropship()};
Unit[] group = new Unit[3];
group[0] = new Marine();
group[1] = new Tank();
group[2] = new Dropship();
for(int i = 0; i < group.length; ++i)
group[i].move(100, 200);
}
}
abstract class Unit {
int x, y;
abstract void move(int x, int y);
void stop() {/*현재 위치에 정지*/}
}
class Marine extends Unit { //보병
void move(int x, int y) {
System.out.println("Marine[x="+x+",y="+y+"]");
}
void stimPack() {/*스팀팩을 사용한다. */}
}
class Tank extends Unit { //탱크
@Override
void move(int x, int y) {
System.out.println("Tank[x="+x+",y="+y+"]");
}
void changeMod() { /*공격모드를 변환한다.*/}
}
class Dropship extends Unit { //탱크
@Override
void move(int x, int y) {
System.out.println("Dropship[x="+x+",y="+y+"]");
}
void change() { /*공격모드를 변환한다.*/}
}
class Time{
private int hour; //0~23 사이의 값을 가져야 함.
private int minute;
private int second;
public void setHour(int hour){
if(isValidhour(hour)) return;
this.hour = hour;
}
//매개 변수로 넘겨진 hour가 유효한지 확인해서 알려주는 메서드
private boolean isValidhour(int hour){
return hour <0 || hour >23;
}
public int getHour() { return hour; };
}
public class TimeTest {
public static void main(String[] args) {
Time t = new Time();
// t.hour = -100;
t.setHour(21); //hour의 값을 21로 변경
System.out.println(t.getHour());
t.setHour(100);
System.out.println(t.getHour());
}
}
접근제어자의 범위는 최소화 시키는 것이 좋다
다형성(polymorphism)
여러가지 형태를 가질 수 있는 능력
조상 타입 참조 변수로 자손 타입 객체를 다루는 것
타입 불일치해도 괜찮다
객체와 참조변수의 타입이 일치할 때와 일치하지 않을 때의 차이
자손 타입의 참조변수로 조상 타입의 객체를 가리킬 수 없음
참조변수의 타입은 인스턴스의 타입과 일치하는 것이 보통이지만 일치 하지 않을 수도 있음
참조변수가 조상타입일 때와 자손 타입일 때의 차이
참조변수로 사용할 수 있는 멤버의 갯수가 달라짐
자손타입의 참조변수로 조상 타입의 객체를 가리킬 수 없음
참조변수의 형변환
사용할 수 있는 멤버의 갯수를 조절하는 것
조상 자손 관계의 참조변수는 서로 형변환 가능
public class Ex7_7 {
public static void main(String[] args) {
Car car = null;
FireEngine fe = new FireEngine();
// FireEngine fe2 = null; //car = (Car)fe; 에서 형변환이 생략됨
FireEngine fe2 = (FireEngine)car; // 조상 -> 자손으로 형변환
Car car2 = (Car)fe2; // 자손 -> 조상으로 형변환
// car2.drive(); //NullPointerException 발생.
// fe.water();
// fe2 = (FireEngine) fe; //자손타입 <- 조상타입, 형변환 생략 불가
// fe2.water();
}
}
class Car{
String color;
int door;
void drive() {
System.out.println("drive, Brrrr~~");
}
void stop() {
System.out.println("stop!!");
}
}
class FireEngine extends Car {
FireEngine() {
}
void water() {
System.out.println("water!!!");
}
}
class MyPoint{
int x;
int y;
}
//class Circle extends MyPoint { //상속
// int r;
//}
class Circle {
MyPoint p = new MyPoint();
int r;
}
public class InheritanceTest {
public static void main(String[] args) {
Circle c = new Circle();
c.p.x =1;
c.p.y =2;
c.r = 3;
System.out.println("c.p.x="+c.p.x);
System.out.println("c.p.y="+c.p.y);
System.out.println("c.r="+c.r);
}
}
단일 상속(Single Inheritance)
Java는 단일 상속만을 허용한다.
조상은 하나만!
비중이 높은 클래스 하나만 상속관계로, 나머지는 포함관계로 한다.
Object클래스 - 모든 클래스의 조상
부모가 없는 클래스는 자동적으로 Object 클래스를 상속받게 된다.
모든 클래스는 Object에 정의된 11개의 메서드를 상속받는다 (toString(), equals(), hashCode(),...)
public class InheritanceTest {
public static void main(String[] args) {
Circle c = new Circle();
System.out.println(c.toString()); //Circle@340f438e
Circle c2 = new Circle();
System.out.println(c2.toString()); //Circle@30c7da1e
}
}
toString()을 안써도 똑같이 출력된다.
println()의 기능
오버라이딩(overriding)
상속받은 조상의 메서드를 자신에 맞게 변경하는 것
선언부는 변경 불가, 내용만 변경가능
class Point {
int x;
int y;
String getLocation(){
return "x: "+ x + ", y:" +y;
}
}
class MyPoint3 extends Point {
int z;
//조상의 getLocation()을 오버라이딩
String getLocation(){
return "x: "+ x + ", y:" +y+" ,z:"+z;
}
}
public class OverrideTest {
public static void main(String[] args) {
MyPoint3 p = new MyPoint3();
p.x = 3;
p.y =5;
p.z =7;
System.out.println(p.getLocation());
}
}
public class 가 있는 경우, 소스파일의 이름은 반드시 public class의 이름과 일치해야한다.
public class가 하나도 없는 경우, 소스파일의 이름은 상관 없음
객체의 생성과 사용
1. 객체의 생성
클래스명 변수명; //클래스의 객체를 참조하기 위한 참조변수를 선언 --> 리모콘 역할
변수명 = new 클래스명(); //클래스의 객체를 생성 후, 객체의 주소를 참조변수에 저장
Tv t; //Tv 클래스 타입의 참조변수 t를 선언
t = new tv(); //Tv 인스턴스를 생성한 후, 생성된 Tv인스턴스의 주소를 t에 저장
class Ex6_1 {
public static void main(String args[]) {
Tv t; // Tv인스턴스를 참조하기 위한 변수 t를 선언
t = new Tv(); // Tv인스턴스를 생성한다.
t.channel = 7; // Tv인스턴스의 멤버 변수 channel의 값을 7로 한다.
t.channelDown(); // Tv인스턴스 메서드 channelDown()을 호출한다.
System.out.println("현재 채널은 " + t.channel + " 입니다..");
}
}
class Tv {
// Tv의 속성(멤버변수)
String color; // 생상
boolean power; // 전원상태(on/off)
int channel; // 채널
// Tv의 기능(메서드)
void power() { power = !power; } // TV를 켜거나 끄는 기능을 하는 메서드
void channelUp() { ++channel; } // TV의 채널을 높이는 기능을 하는 메서드
void channelDown() { --channel; } // TV의 채널을 낮추는 기능을 하는 메서드
}
class Ex6_2 {
public static void main(String args[]) {
Tv t1 = new Tv(); // Tv t1; t1 = new Tv();를 한 문장으로 가능
Tv t2 = new Tv();
System.out.println("t1의 channel값은 " + t1.channel + "입니다.");
System.out.println("t2의 channel값은 " + t2.channel + "입니다.");
t1.channel = 7; // channel 값을 7으로 한다.
System.out.println("t1의 channel값은 7로 변경하였습니다.");
System.out.println("t1의 channel값은 " + t1.channel + "입니다.");
System.out.println("t2의 channel값은 " + t2.channel + "입니다.");
}
}
int result = add(3,5); // int add(intx, int y)를 호출하고 결과를 result에 저장
class Ex6_4 {
public static void main(String args[]) {
MyMath mm = new MyMath();
long result1 = mm.add(5L, 3L);
long result2 = mm.subtract(5L, 3L);
long result3 = mm.multiply(5L, 3L);
double result4 = mm.divide(5L, 3L);
System.out.println("add(5L, 3L) = " + result1);
System.out.println("subtract(5L, 3L) = " + result2);
System.out.println("multiply(5L, 3L) = " + result3);
System.out.println("divide(5L, 3L) = " + result4);
}
}
class MyMath {
long add(long a, long b) {
long result = a + b;
return result;
// return a + b; //위의 두 줄을 이와 같이 한 줄로 간단히 할 수 있다.
}
long subtract(long a, long b) { return a - b; }
long multiply(long a, long b) { return a * b; }
double divide(double a, double b) {
return a / b;
}
}
public class Ex5_1_tmp {
public static void main(String[] args) {
// int[] score; 1. 배열 score를 선언(참조변수)
// score = new int[5]; 2. 배열의 생성(int저장공간 x 5)
int [] score = new int[5]; // 배열의 선언과 생성을 동시에
score[3] =100;
}
배열의 길이
"배열은 한번 생성하면 그 길이를 바꿀 수 없다."
배열의 초기화
배열의 각 요소에 처음으로 값을 저장하는 것
int[] score = { 1, 2, 3,4,5};
배열의 출력
char[] ChArr
캐릭터 배여일 때만 출력 가능
// 배열의 요소를 순서대로 하나씩 출력
for( int i=0; i<Arr.length; i++){
System.out.println(Arr[i]);}
//배열의 모든 요소를 출력
System.out.println(Arrays.toString(Arr));
배열의 활용
총점과 평균 구하기
public class Ex5_2 {
public static void main(String[] args) {
int sum=0;
float average =-0f;
int[] score = {100,88,100,100,90};
for (int i=0; i <score.length; i++){
sum += score[i];
}
average = sum /score.length; //계산결과를 Float으로 얻기
System.out.println("총점 : " + sum);
System.out.println("평균 : " + average);
}
}
최대값과 최소값
public class Ex5_3 {
public static void main(String[] args) {
int[] score = {79, 88, 91, 33, 100, 55,95};
int max = score[0];
int min = score[0];
for(int i=1; i <score.length; i++) {
if(score[i]> max){
max = score[i];
} else if(score[i]<min){
min = score[i];
}
}
System.out.println("최대값 :"+max);
System.out.println("최소값 :"+min);
}
}
섞기(Shuffle)
import java.util.Arrays;
public class Ex5_4 {
public static void main(String[] args) {
int[] numArr = {0,1,2,3,4,5,6,7,8,9};
System.out.println(Arrays.toString(numArr));
for (int i =0; i<100; i++){
int n = (int)(Math.random()*10);
int tmp = numArr[0];
numArr[0] = numArr[n];
numArr[n] =tmp;
}
System.out.println(Arrays.toString(numArr));
}
}
로또 번호
import java.util.Arrays;
public class Ex5_5 {
public static void main(String[] args) {
int[] ball = new int[45]; //45개 정수값을 저장하기
//배열의 각 요소에 1~45값을 저장
for(int i=0; i<ball.length; i++){
ball[i]=i+1; // ball[0]에 1이 저장된다.인덱스는 0부터 시작하니까
}
System.out.println(Arrays.toString(ball));
int tmp =0; // 두 값을 바꾸는데 사용할 임시변수
int j =0; // 임의의 값을 얻어서 저장할 변수
// 배열의 i번째 요소와 임의의 요소에 저장된 값을 서로 바꿔서 값을 저장
// 0번째부터 5번째 요소까지 모두 6개만 바꾼다.
for (int i=0; i<6; i++){
j=(int)(Math.random()*45); //0~44범위 임의의 수
tmp =ball[i];
ball[i] = ball[j];
ball[j] = tmp;
System.out.println(Arrays.toString(ball));
}
//배열 ball의 앞에서부터 6개의 요소를 출력한다.
for(int i=0; i<6; i++){
System.out.printf("ball[%d]=%d%n", i, ball[i]);
}
}
}
2. case문의 값은 정수, 상수(문자포함), 문자열만 가능하며, 중복되지 않아야 한다.
임의의 정수 만들기
Math.random() - 0.0과 1.0사이의 임의의 double값을 반환
0.0 <= Math.random() < 1.0
1과 3사이의 정수 구하기
1. 각 변에 3을 곱한다.
2. 각 변을 Int형으로 변환한다.
3. 각 변에 1을 더한다.
System.out.println((int)(Math.random()*11)-5);//-5와 5의 사이
for문
조건을 만족하는 동안 블럭{}을 반복 - 반복 횟수를 알 때 적합
변수의 범위(scope)는 좁을수록 좋다; 선언위치부터 선언된 블럭의 끝까지
//조건식을 생력하면, true로 간주되엇 무한반복문이 된다.
for(;;){
System.out.println("i="+1);
}
중첩 for 문
직사각형 별찍기
public class Ex4_15 {
public static void main(String[] args) {
for(int i=1; i<=5; i++) {
for (int j = 1; j <= 10; j++) {
System.out.print("*");
}
System.out.println();
}
}
}
별 늘리기
public class Ex4_15 {
public static void main(String[] args) {
for(int i=1; i<=5; i++) {
for (int j = 1; j <= i; j++) {
System.out.print("*");
}
System.out.println();
}
}
}
while문
조건을 만족시키는 동안 블럭{}을 반복 - 반복 횟수 모를 때
while 조건식 {
//조건식의 연산결과가 참(true)인 동안, 반복될 문장들을 적는다.
}
for문과 100% 상호 대체 가능
for 문
public class Ex4_14 {
public static void main(String[] args) {
int num =12345, sum =0;
//10으로 나머지 연산을 하면 마지막 자리를 얻는다.
// System.out.println(12345%10);
//num = 12345, 1234, 123,12, 1
for(num=12345; num>0; num=num/10){
System.out.println(num);
}
System.out.println("각 자리수의 합:" +sum);
}
}
while문으로 바꾸기
public class Ex4_14 {
public static void main(String[] args) {
int num =12345, sum =0;
//10으로 나머지 연산을 하면 마지막 자리를 얻는다.
// System.out.println(12345%10);
//num = 12345, 1234, 123,12, 1
while(num>0){
sum += num%10;
System.out.println("sum"+sum+",num%10="+num%10);
num =num/10;
}
System.out.println("각 자리수의 합:" +sum);
}
}
do-while문
블럭{}을 최소한 한 번 이상 반복 - 사용자 입력받을 때 유용
break문
자신이 포함된 하나의 반복문을 벗어난다.
while문
public class Ex_16 {
public static void main(String[] args) {
int sum =0;
int i =0;
while(true){//무한 반복문 for(;true;) {}
if(sum>100)
break; //자신이 속한 하나의 반복문을 벗어난다.
++i;
sum += i;
} // end of while
System.out.println("i=" +i);
System.out.println("sum=" + sum);
}
}
for문
public class Ex_16 {
public static void main(String[] args) {
int sum =0;
int i =0;
for(;;){//무한 반복문 for(;true;) {}
if(sum>100)
break; //자신이 속한 하나의 반복문을 벗어난다.
++i;
sum += i;
} // end of while
System.out.println("i=" +i);
System.out.println("sum=" + sum);
}
}
continue문
자신이 포함된 반복문의 끝으로 이동 - 다음 반복으로 넘아감
전체 반복 중에서 특정 조건시 반복을 건너뛸 때 유용
break문과 달리 반복문을 벗어나지 않는다.
public class Ex4_17 {
public static void main(String[] args) {
for(int i=0; i<= 10; i++){
if(i%2==0)
continue;
System.out.println(i);
}
}
}
예시
import java.util.Scanner;
public class Ex4_18 {
public static void main(String[] args) {
int menu =0;
int num =0;
Scanner scanner = new Scanner(System.in);
while (true){ // 무한 반복문
System.out.println("(1) square");
System.out.println("(2) square root");
System.out.println("(3) log");
System.out.println("원하는 메뉴(1~3)을 선택하세요. (종료:0>");
String tmp = scanner.nextLine(); //화면에서 입력받은 내용을 tmp에 저장
menu = Integer.parseInt(tmp); //입력받은 문자열(tmp)을 숫자로 변환
if(menu==0) {
System.out.println("프로그램을 종료합니다");
break;
} else if (!(1<=menu && menu<=3)) {
System.out.println("메뉴를 잘못 선택하셨습니다. (종료는 0)");
continue;
}
System.out.println("선택하신 메뉴는" + menu + "번입니다.");
} //main의 끝
}
}
public class Ex2_1 {
public static void main(String[] args) {
int x=4, y=2;
int tmp;
tmp =x;
x=y;
y=tmp;
System.out.println(x);
System.out.println(y);
}
}