클래스 뒤에 implements Serializable
을 붙이면 직렬화된다. 모바일 개발할 때 화면간 통신할 때 쓰인다.
data class화 한다는것운 hashcode()
와 equals()
함수를 만들어준다는 것이다. 이클립스에서 자동완성 지원한다.
클래스간의 상속(단일 상속), 인터페이스 간의 상속(다중 상속):
extends
클래스와 인터페이스 간의 상속(다중 상속):implements
extends Object
가 생략되어 있다.public class Parent /*extends Object*/
@Override
는 반드시 상속받은 부모 함수와 재정의할 내 함수의 이름이 같아야 한다.
상속을 맺으면, 메모리상에 모든 부모 클래스가 다 생성되기 때문에, 메모리상으로 그렇게 효율적이진 않다.
자바는 원래 메서드 안에 메서드를 정의할 수 없다. (람다식 제외)
// Parent.java
package test.com;
public /*final*/ class Parent extends Object { // final 붙이면, 상속 안됨 ex) String
final int num = 11;
String name = "kim";
public /*final*/ int sleep() { // sleep에 final 붙일 경우, 재정의 불가
System.out.println("Parent sleep()...");
return 8;
}
}
// Mother.java
package test.com;
public abstract class Mother { // 추상 클래스
int num;
String name;
public Mother() {
// TODO Auto-generated constructor stub
}
public int drive() {
System.out.println("Mother drive()...");
return 8;
}
public abstract void run(); // 클래수 내부에 블럭 없이 정이된 메소드 -> 추상메소드
public abstract String run2(int x); // 매개변수 넣어서도 가능
}
// MySister.java
package test.com;
public class MySister extends Mother {
// 추상 클래스를 상속받은 클래스는 반드시 추상 매서드를 오버라이드 해야한다.
@Override
public void run() {
}
@Override
public String run2(int x) {
return "";
}
public void stop(int x, int y, int z) {
System.out.println("stop()...");
}
public void stop2(int ...z) { // 개수 상관없이 int면 된다.
System.out.println("stop2()..." + z);
}
}
// MyBrother.java
package test.com;
public class MyBrother extends Parent {
int score = 100;
String hobby = "golf";
public int play(String x) {
System.out.println("play()..." + x);
return 10;
}
}
// My.java
package test.com;
public class My extends Parent{
int money = 1000;
String name = "kim";
public My() {
}
public int work() {
System.out.println("My work()...");
return 8;
}
@Override
public int sleep() { // Ctrl + space로 자동완성 가능
System.out.println("My sleep()...");
return 10;
}
}
//Child.java
package test.com;
public class Child extends My{
int money = 10;
String name = "kim";
public int study() {
System.out.println("Child study()...");
System.out.println("super.num: " + num); // super.num이지만, super 생략해도 된다.
System.out.println("super.money: " + super.money); // 1000
System.out.println("this.money: " + this.money); // 10
// 부모와 내 변수 구분 가능
return 10;
}
public Child() {
System.out.println("child...");
}
// 알바
@Override
public int work() {
System.out.println("Child work()...");
return 4;
}
@Override
public int sleep() {
System.out.println("Child sleep()...");
return 6;
}
}
여기까지 클래스
// Test01main.java
package test.com;
public class Test01main {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("상속...");
Parent p = new Parent();
System.out.println(p.num);
System.out.println(p.name);
System.out.println(p.sleep());
System.out.println("=====================");
My m = new My();
System.out.println(m.money);
System.out.println(m.name);
System.out.println(m.work());
System.out.println("=====================");
Child c = new Child();
System.out.println(c.money);
System.out.println(c.name);
System.out.println(c.study());
System.out.println(c.work());
System.out.println("=====================");
My my = new My();
System.out.println(my.money);
System.out.println(my.name);
System.out.println(my.work());
System.out.println(my.num);
System.out.println(my.sleep());
System.out.println("=====================");
Child ch = new Child(); // 상속을 맺으면, 메모리상에
System.out.println(ch.money);
System.out.println(ch.name);
System.out.println(ch.study());
System.out.println(ch.work());
System.out.println(ch.sleep());
System.out.println("===========다형성==========");
Parent p2 = new My(); // 가능
System.out.println(p2.num);
System.out.println(p2.name);
System.out.println(p2.sleep()); // Parent(좌측)의 자원들만 사용할 수 있다.
Parent p3 = new Child(); // 가능
System.out.println(p3.num);
System.out.println(p3.name);
System.out.println(p3.sleep()); // Parent(좌측)의 자원들만 사용할 수 있다.
System.out.println(p2 instanceof Parent); // true
System.out.println(p3 instanceof Parent); // true
// 내부 클래스로 상속을 구현할 수 있다.
System.out.println("===========내부 클래스로 상속 구현==========");
Parent p4 = new Parent() {
// 클래스 영역, 이름 없는 익명 내부 클래스
// 속성
String myName = "Lee";
int kor = 99;
// 메소드 정의, 밖으로 빠져나가면 호출 불가
public String myFriend(int x) {
return "Yang";
}
@Override
public int sleep() {
System.out.println("Inner sleep()...");
return 7;
}
};
// System.out.println(p4.myFriend()); // error
System.out.println(p4.sleep()); // 재정의 한 것은 콜 가능
}
}
// Test02main.java
package test.com;
public class Test02main {
public static void main(String[] args) {
System.out.println("디형성...");
// Parent p = new Parent();
Parent p = test();
}
public static Parent test() {
return new My();
}
}
// Test03main.java
package test.com;
public class Test03main {
public static void main(String[] args) {
// Mother m = new Mother(); // error
Mother m = new MySister(); // ok
// 반드시 상속받는 쪽으로 생성해야 한다.
MySister ms = new MySister();
ms.stop(11, 22, 33);
ms.stop2(11);
ms.stop2(11, 22);
ms.stop2(11, 22, 33);
ms.stop2(11, 22, 33, 44);
}
}
this("홍길동", 100, false);
this("길동홍", 200);
super()
생성자 위에는 어떤 코드도 쓸 수 없다.
protected
는 상속관계라면, 패키지 밖에서도 접근할 수 있다는 뜻이다.
추상 클래스 사용 이유: 사용자의 혼동을 방지하기 위해, 사용 패턴을 강제하기 위해
// SingletonClass.java
package test.com;
public class SingletonClass {
private static SingletonClass st = new SingletonClass(); // 외부 접근 불가능. 싱글톤 막는다.
// 접근 시 외부 getter 함수 필요
private SingletonClass() { // 외부 접근 불가능(new 불가능)
// TODO Auto-generated constructor stub
}
public static SingletonClass getInstance() { // 보통 이름을 이렇게 짓는다.
return st;
}
}
// SingletonMain.java
package test.com;
public class SingletonMain {
public static void main(String[] args) {
System.out.println("Singleton class");
SingletonClass st1 = SingletonClass.getInstance();
System.out.println(st1); // 주소
SingletonClass st2 = SingletonClass.getInstance();
System.out.println(st2); // 주소
}
}
// Friend.java
package test.com;
public interface Friend {
// 인터페이스는 생성자가 존재하지 않는다.
// 반드시 누군가가 상속받아서 오버라이딩하거나, inner class로 명시해야 한다.
// 인터페이스의 필드는 항상 public static final이다. 생략 가능
String USER_NAME = "YANG";
// 1. abstract
public void sleep(); // abstract 키워드 생략 가능
// 2. default
public default void stop() { // interface는 default 키워드 명시 필수
System.out.println("Friend default stop()...");
}
// 3. static
public static void start() {
System.out.println("Friend static start()...");
}
}
// Student.java
package test.com;
public interface Student {
String SCHOOL_NAME = "SDS";
public int study(String name);
}
// Person.java
package test.com;
public class Person implements Friend, Student { // 다중 상속 가능
@Override
public void sleep() {
System.out.println("Person sleep()...");
}
@Override
public int study(String name) {
System.out.println("Person study()..." + name);
return 10;
}
}
// Test01main.java
package test.com;
public class Test01main {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("interface...");
Friend f = new Friend() {
@Override
public void sleep() {
System.out.println("anonymous inner sleep()...");
}
};
f.sleep();
Friend f2 = new Person();
f2.sleep();
f2.stop();
Friend.start();
Student st = new Person();
int studyTime = st.study("Kim");
System.out.println("studyTime: " + studyTime);
}
}
단일 상속과 다중 상속의 조건들을 잘 보고 추상 클래스(단일 상속)랑 인터페이스(다중 상속)를 구별해서 사용하면 된다.
default
에도 주의하자.
대세는 인터페이스다. 인터페이스에서도default
,static
등의 키워드를 모두 쓸 수 있기 때문에, 굳이 추상 클래스의 제약조건을 신경 쓸 필요가 없다.
가변배열 처리를 위해 사용. 자료구조 라고도 불린다.
1. 순서 있고, 중복 허용: List
계열 -> ArrayList
, Vector
등
2. 순서 없고, 중복 불가: Set
계열 -> HashSet
3. 키와 값으로 여러 데이터 갖는 객체이며 키는 중복 불가능, 값은 가능: Map
계열 -> HashMap
, HashTable
등
Set
계열은 랜덤이 아니지만, 순서대로 쌓이는 것도 아니다.set()
은 불가능하고, remove()
도 값 기반으로 해야한다.package test.com;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Test01main {
public static void main(String[] args) {
// 가변배열: Collection
int[] sus = new int[3];
Integer[] sus2 = new Integer[3];
// 1. List 계열
List<Integer> sus3 = new ArrayList<Integer>();
sus3.add(1000); // 0
sus3.add(1000); // 1
sus3.add(2000); // 2
sus3.set(2, 4000);
System.out.println(sus3); // [1000, 1000, 4000]
for (int v : sus3)
System.out.println(v);
sus3.remove(0);
for (int i = 0; i < sus3.size(); i++)
System.out.println(sus3.get(i));
// sus3.clear(); // 다 지움
System.out.println("=========================================");
// List<BoardVO> vos = new ArrayList();
// vos.add(new BoardVO(1, "kim", "aaa", "Lee"));
// 2. Set 계열
Set<Integer> s = new HashSet<>();
s.add(1000);
s.add(1000);
s.add(1000);
s.add(1000);
s.add(1000);
s.add(2000);
System.out.println("s.size(): " + s.size()); // 2
s.remove(2000);
// s.clear();
System.out.println("=========================================");
Set<BoardVO> svos = new HashSet<>();
svos.add(new BoardVO());
svos.add(new BoardVO());
svos.add(new BoardVO(1, "kim", "aaa", "Lee"));
svos.add(new BoardVO(1, "kim", "aaa", "Lee"));
System.out.println("svos size(): " + svos.size()); // 2
// Data class(hashCode, equals)가 아니라면, equals가 없기 때문에 제대로 실행되지 않는다. 4 나옴.
// Serializable과는 아예 다른 개념이다. 객체를 매개변수로 전달할 때 쓰이는 기법이다. new를 통해 만든 객체를 전송할 때, 받는 쪽이 Serializable type인 경우가 있다. 그 때 쓰는거다.
// Byte code로 직렬화가 되며, 그냥 상속만 해주면 된다.
}
}