What thestaticboils down to is that an instance of the class can stand on its own. Or, the other way around: a non-static inner class (= instance inner class) cannot exist without an instance of the outer class. Since a top-level class does not have an outer class, it can't be anything butstatic.
Becausealltop-level classes are static, having thestatickeyword in a top-level class definition is pointless.
Some code to play around with:
public class Foo {
public class Bar {
// Non-static innner class
}
public static class Baz {
// Static inner class
}
}
public class Example {
public static void main(String[] args) {
new Foo(); // this is ok
new Foo.Baz(); // this is ok
new Foo.Bar(); // does not compile!
Foo f = new Foo();
Foo.Bar bar = f.new Bar(); //this works, but don't do this
}
}
I put the "but don't do this" in there because it'sreallyugly code design. Instance inner classes should not be visible outside the outer class. They should only be used from within the outer class.
// 기본 list의 element 값 가져오기
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + "\t");
}
// interator 객체로 element 얻어오기 => Iterator Pattern
Iterator elements = list.iterator();
while (elements.hasNext()) {
System.out.print(elements.next() + "\t");
}
// LinkedList에 있는 메소드 사용하여 element가져오기
int i = 0;
while (!linkedList.isEmpty()) {
System.out.println(i + "->" + linkedList.poll()); // 메모리에서 삭제하면서 element를 가져옴.
i++;
}
// 입력 성능이 필요한 곳에서는 Linkedlist를 사용하는 것이 성능면에서 좋다.
List<String> list1 = new ArrayList<String>();
List<String> list2 = new LinkedList<String>();
long startTime;
long endTime;
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
list1.add(0, String.valueOf(i));
}
endTime = System.nanoTime();
System.out.println("ArrayList 걸린 시간: " + (endTime - startTime) + "ns");
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
list2.add(0, String.valueOf(i));
}
endTime = System.nanoTime();
System.out.println("LinkedList 걸린 시간: " + (endTime - startTime) + "ns");
public class Member {
public String name;
public int age;
public Member(String name, int age) {
this.name = name;
this.age = age;
}
/*
equals: 최상위 클래스인 Object가 가지고 있는 메소드
Overriding하여 조건에 맞는 equals 구현 가능
(ex. HashSet에서 같은 값이면 추가되지 않는 조건 지정 가능)
*/
public boolean equals(Object obj) {
if (obj instanceof Member) {
Member member = (Member) obj;
return member.name.equals(name) && (member.age == age);
} else {
return false;
}
}
// 메모리가 생성된 주소값
public int hashCode() {
return this.name.hashCode() + age;
}
}
3) Map Interface
- Key와 Value를 매핑하는 객체
- Key는 절대 중복될 수 없음.
- 정렬 기준이 없음.
- 구현 클래스: HashMap, TreeMap ...
Hash Map
저장되는 value와 key가 null 허용
동기화가 포함되지 않았으므로 나중에 배우는 multi-thread 환경에서의 구현이 아니라면 Hashtable에 비해서 처리 속도가 빠름.
메서드에 static과 abstract를 함께 사용할 수 없다. - static메서드는 몸통(구현부)이 있는 메서드에만 사용할 수 있기 때문
클래스에 abstract와 final을 동시에 사용할 수 없다. - 클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미이고, abstract는 상속을 통해서 완성되어야 한다는 의미이므로 서로 모순되기 때문
abstract메서드의 접근제어자가 private일 수 없다. - abstract메서드는 자손클래스에서 구현해주어야 하는데 접근 제어자가 private이면, 자손클래스에서 접근할 수 없기 때문
메서드에 private과 final을 같이 사용할 필요 없음 - 접근 제어자가 private인 메서드는 오버라이딩될 수 없기 때문 - 이 둘 중 하나만 사용해도 의미가 충분.
6. Getter와 Setter 메소드
객체지향 프로그래밍에서는 외부에서 직접적으로 객체의 데이터 접근을 막는다.
-> 객체의 무결성(결점이 없는 성질)이 깨질 수 있기 때문. - 매개값을 검증해서 유효한 값만 데이터 저장함.
: 메소드를 통해서 데이터 변경 => Getter / Setter
7. Inner class
: 특정 클래스 내에서만 주로 사용되는 클래스를 내부 클래스로 선언
: 장점: 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근가능, 코드의 복잡성 줄일 수 있음(캡슐화)
특징
클래스 내부에 또 다른 클래스를 가짐으로 클래스 관리의 효율을 높인 것
형식과 생성파일 - 형식: class Outer { class Inner {...} } - 생성파일) Outer.class, Outer$Inner.class
객체 생성 - Outer.Inner oi = new Outer().new Inner();
class InnerEx1 {
class InstanceInner {
int iv = 100;
// static int cv = 100; // *error! static 변수 선언할 수 없음.*
final static int CONST = 100; // *final static은 상수이므로 허용*
}
static class StaticInner {
int iv = 200;
static int cv = 200; // *static class만 static 멤버 정의 가능*
}
void myMethod() {
class LocalInner {
int iv = 300;
// static int cv = 300; // error! static 변수 선언할 수 없음.
final static int CONST = 300; // final static은 상수이므로 허용
}
}
}
Anonymous inner class (익명 중첩 클래스)
- 기존 클래스의 특정 메서드를 오버라이딩하여 원하는 형태로 재정의하여 사용하는 방식 - 외부 멤버 중 final만 포함할 수 있음.
형식과 생성파일 - 형식: class Outer {method() { new Inner() { ... }}} - 생성파일: Outer.class, Outer$숫자.class
객체 생성: new Inner() 자체가 객체 생성임.
import java.awt.*;
import java.awt.event.*;
class InnerEx8 {
public static void main(String[] args) {
Button b = new Button("Start");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("ActionEvent occured!");
}
}); // 익명 클래스의 끝
} // main메서드의 끝
} // InnerEx8클래스의 끝
int Type - 변수에 어떤 진수(10,8,16진수)를 입력하더라도동일한 값이 2진수로 변환되어 저장
long Type - 수치가 큰 데이터를 다루는 프로그램에서 필수적 - 변수 초기화: 정수값 뒤에 l 또는 L 붙임.
실수 타입
float과 double의 메모리 사용 크기는 각각 int와 long의 크기와 같지만, 정수 타입과는다른 저장 방식 때문에 훨씬 더 큰 범위의 값을 저장할 수 있음.
자바의 실수 리터럴의 기본 타입: double
타입 변환 (Type Casting)
자동 타입 변환 (promotion) : 큰 크기 타입 <- 작은 크기 타입 (메모리 크기) - byte(1) < short(2) < int(4) < long(8) < float(4) < double(8) float가 뒤인 이유?! 표현할 수 있는 값의 범위가 float이 더 크기 때문 - char type의 경우 int type으로 자동 변환. but! 음수 저장이 안되므로 byte타입은 자동 변환 안됨.
4) 메모리를 자동으로 관리 : 개발자가 직접 메모리에 접근할 수 없도록 설계. 객체 생성 시 자동적으로 메모리 영역을 찾아서 할당하고, 사용이 완료되면 Garbage collector를 실행시켜 자동적으로 사용하지 않는 객체를 제거
5) 멀티스레드를 쉽게 구현
6) 동적 로딩을 지원
2. JDK (Java Development Kit)
1) JDK 란?
- 자바 프로그램 개발 도구 - 개발을 위한 클래스, 컴파일러, 실행 및 배포도구를 포함 등 개발을 위한 전반적인 환경 제공
2) 플랫폼
- 프로그래밍이나 컴퓨터 실행을 위한 기본적인 기능을 제공하는 것. - Java의 JVM은 이런 다양한 플랫폼 위에서 동일한 Java 소스코드를 이용할 수 있는 환경 제공 - 플랫폼 종류: J2SE(Java 2 Standard Edition), J2EE(Java 2 Enterprise Edition), J2ME(Java 2 Micro Edition)
3) JDK 디렉터리 구조
JDK 디렉터리 구조
4) JVM, API, JRE, JDK 관계
- JDK(Java Development Kit) = JRE + 개발에 필요한 도구 - JRE(Java Runtime Environment) = JVM + 표준 클래스 라이브러리
JVM, API, JRE, JDK 관계
3. JVM (Java Virtual Machine)
자바 프로그램은 완전한 기계어가 아닌, 중간 단계의 바이트 코드이기 때문에 이것을 해석하고 실행할 수 있는 가상의 운영체제(JVM)가 필요
- 장점: Write once, run anywhere.
- 단점: 한번의 컴파일링으로 실행 가능한 기계어가 만들어지지 않고 JVM에 의해 기계어로 번역되고 실행되기 때문에, C와 C++의 컴파일 단계에서 만들어지는 완전한 기계어보다는 속도가 느림.
4. Java 프로그램 실행 단계
javac Hello.java // 1) 컴파일러(javac.exe)로 자바 소스 파일 컴파일, *.class 파일 생성
java Hello // 2) JVM을 구동시키는 명령어(java.exe)
1) Java 소스 파일을 컴파일러로(javac.exe)로 컴파일하면 확장자가 .class인 바이트 코드 파일이 생성됨. 2) java.exe 명령어가 실행되면서 JVM은 바이트 코드 파일(Hello.class)을 메모리로 로드하고, 해당 운영체제에 맞게 기계어로 번역. 그리고 main() 메소드를 찾아 실행
main() method
- Program entry point (실행 진입점) - java.exe로 JVM을 구동시키면 제일 먼저 main() 메소드를 찾아서 실행시킴.
자바 실행 단계자바 실행 단계(자세히)
프로그램 동작 순서
5. 메모리 사용 영역
java.exe로 JVM이 시작되면 JVM은 운영체제에서 할당받은 메모리영역(Runtime Data Area)을 다음과 같이 세부 영역으로 구분하여 사용
=> 메소드 영역, 힙 영역, JVM 스택 영역
메소드 영역
코드에서 사용되는 클래스(~.class)들을 클래스 로더로 읽어 클래스별로 런타임 상수풀(runtime constant pool), 필드(field) 데이터, 메소드(method) 데이터, 메소드 코드, 생성자(constant) 코드 등을 분류하여 저장.
JVM이 시작할 때 생성되고 모든 스레드가 공유하는 영역
힙 영역
객체와 배열이 생성되는 영역
JVM 스택 영역의 변수나 다른 객체의 필드에서 참조
참조하는 변수나 field가 없으면 Garbage Collector를 실행시켜 쓰레기 객체를 힙 영역에서 자동으로 제거
JVM 스택 영역 (-> Frame -> 로컬 변수 스택)
각 스레드마다 하나씩 존재. 스레드가 시작될 때 할당
기본적으로 main thread가 존재(JVM 스택도 하나)
Frame: JVM stack의 element - method를 호출할 때 마다 Frame을 추가(push)하고 method 종료되면 해당 Frame 을 제거(pop)하는 동작 수행 - 예외 발생시 printStackTrack() method
로컬 변수 스택: Frame 내부에 존재 - 기본 타입 변수와 참조 타입 변수가 추가(push)되거나 제거(pop)됨. - 변수가 이 영역에 생성되는 시점은 초기화될 때, 즉 최초로 변수에 값이 저장될 때.