Home Java 기본문법 (1)
Post
Cancel

Java 기본문법 (1)

Python을 주로 사용해서 헷갈렸던 Java 문법을 정리해보려 한다.

자바 정리

자바 파일 작성시 주의 사항

  1. 패키지명은 반드시 소문자로 작성한다.
  2. 클래스 파일명은 반드시 대문자로 작성한다.
  3. 클래스명이 파일명이 되어야 한다.

문자열

공백 제거 - trim()

trim()은 문자열 앞 뒤의 공백을 제거하지만 중간에 있는 공백은 제거하지 못한다.

1
2
3
4
5
6
7
8
9
10
11
12
String str1 = " TEST TEST ";
String str2 = " TEST TEST";
String str3 = "TEST TEST";

System.out.println("[" + str1.trim() + "]");
System.out.println("[" + str2.trim() + "]");
System.out.println("[" + str3.trim() + "]");

// 결과
[TEST TEST]
[TEST TEST]
[TEST TEST]

공백 제거 - replace()

replace(target, replacement)를 이용하면 모든 공백을 제거할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
String str1 = " TEST TEST ";
String str2 = " TEST TEST";
String str3 = "TEST TEST";

System.out.println("[" + str1.replace(" ", "") + "]");
System.out.println("[" + str2.replace(" ", "") + "]");
System.out.println("[" + str3.replace(" ", "") + "]");

// 결과
[TESTTEST]
[TESTTEST]
[TESTTEST]

문자열 비교 - equals()

1
2
3
4
5
6
7
8
9
10
11
String s1 = "hello";
String s2 = "hello";

if (s1.equals(s2)){
	System.out.println("same");
}else{
	SYstem.out.println("different");
}

// 결과
same

배열

파이썬의 리스트(배열)와 비슷하지만, 자바에서는 배열을 선언한 후 새로운 값을 추가하기가 까다롭다.
배열을 사용하기보다는 ArrayList를 자주 사용한다고 한다.

배열 초기화

1
2
3
4
5
6
7
// 방법 1.
int[] arr; // 또는
int arr[];
arr = new int[] {1, 2, 3, 4, 5};

// 방법 2.
int[] arr = {1, 2, 3, 4, 5};

배열 출력

1
2
3
4
5
6
7
import java.util.Arrays;

arr = new int[] {1, 2, 3, 4, 5};
System.out.println("Arrays.toString()(으)로 출력 하기 : " + Arrays.toString(arr));

// 결과
Arrays.toString()() 출력 하기 : [1, 2, 3, 4, 5]
1
2
3
4
5
6
7
8
9
// String에서 한글자씩 출력하는 방법
String str1 = "Java String?";

for (int i=0; i < str1.length(); i++){
	System.out.print("i = " + str1.charAt(i) + " ");
}

// 결과
0 = J 1 = a 2 = v 3 = a 4 =   5 = S 6 = t 7 = r 8 = i 9 = n 10 = g 

Java에서는 왜 .cahrAt() 을 이용해야 하는가?
문자열은 한글자마다 메모리에 저장되는것이 아닌, 스트링풀에 저장되므로 .cahrAt()을 이용해야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 2차원 배열 출력
int [][] data = {
	{1, 2, 3, 4, 5},
  	{6, 7, 8, 9, 10},
  	{11, 12, 13, 14, 15}
};

// 결과
data[0][0] = 1
data[0][1] = 2
data[0][2] = 3
data[0][3] = 4
data[0][4] = 5
	
data[2][3] = 14
data[2][4] = 15

for each를 왜 사용하지 않았는가?
for each로 출력 가능한 자료형은 int, double, char, ArrayList 이다.
for each 문을 사용할 때는 인덱스 정보를 직접 얻기 어렵고, 각 요소의 값만 얻을 수 있다.
배열의 요소 값만 필요한 경우에는 for each를 사용하면 편리하다.
하지만 인덱스 정보가 필요한 경우에는 for를 사용하는 것이 더 적합하다.

static

메소드 static

main 메소드 앞에는 반드시 static을 붙여야한다.
static 메소드는 static 메소드만 호출할 수 있다.

1
2
3
4
5
6
7
8
9
class Data{
	static void show(){
		...
	}

	public static void main(String[] args){
		show(); // static 메소드는 static 메소드만 호출할 수 있다.
	}
}

클래스 static

클래스에서 사용되는 static은 클래스 변수(static variable)로 인스턴스가 공유하는 클래스당 한개만 생성되는 변수이다.
클래스 변수는 클래스.클래스 변수명으로 접근할 수 있다.
클래스 메소드 또한 클래스.클래스 메소드명으로 접근할 수 있다.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Student {
	static int numberOfStudent; // 클래스 변수(값을 공유)
	String name; // 인스턴수 변수
	
	Student(){
		numberOfStudent++;
	}
	
	Student(String name){
		numberOfStudent++;
		this.name = name;
	}
	
	void print(){
		System.out.println("name : " + name);
		System.out.println("numberOfStudent : " + numberOfStudent);
	}
	
	static void print2(){
		System.out.println("name : " + name); // 에러 static 변수만 올 수 있다.
		System.out.println("numberOfStudent : " + numberOfStudent);
	}

	static void printNumberOfStudent(){
        System.out.println("Student.printNumberOfStudent() : " + numberOfStudent);
    }
}
public class Practice {
	public static void main(String[] args){
		System.out.println("Student.numberOfStudent : " + Student.numberOfStudent);
		Student s1 = new Student("Alice");
		s1.print();
		Student s2 = new Student("Jack");
		s2.print();
		Student s3 = new Student();
		System.out.println("Student.numberOfStudent : " + Student.numberOfStudent);
	}	
}

// 결과
Student.numberOfStudent : 0
name : Alice
numberOfStudent : 1
name : Jack
numberOfStudent : 2
name : null
numberOfStudent : 3
Student.printNumberOfStudent() : 3

static 블록과 non-static 블록

non-static블록은 인스턴스를 생성할 때마다 블록이 먼저 수행되고 생성자를 다음으로 수행한다.
static 블록은 첫 번째 인스턴스를 생성하기 전에 딱 한번만 수행된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Student {
	String name;
	 {
        System.out.println("인스턴스 생성 전 실행");
    }

    static {
        System.out.println("인스턴스 생성 전 단 한번만 실행");
    }
}

public class Practice {
	public static void main(String[] args){
			Student s1 = new Student();
	}
}

// 결과
인스턴스 생성   한번만 실행
인스턴스 생성 
실행

클래스

파일에 클래스 한개 있는 경우 클래스명과 파일명이 일치해야한다. 파일에 클래스가 여러개 있는 경우

  • 모든 클래스가 public 키워드를 갖지 않는 경우에는 어떤 클래스명도 파일명이 될 수 있다.
  • public키워드를 갖는 클래스가 있다면 그 클래스명을 파일명으로 해야한다.
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
// public 한개인 경우 : 파일명은 Test로 해야한다.
public class Test {
	...
}

class Test2 {
	...
}

class Test3 {
	...
}

// public 여러개인 경우 : Test, Test2, Test3 모두 파일명이 될 수 있다.
class Test {
	...
}

class Test2 {
	...
}

class Test3 {
	...
}

new

new키워드를 사용하여 객체를 생성할 수 있다.
Class에 생성자가 없다면 new할 때 디폴트 생성자가 자동으로 호출된다.
디폴트 생성자는 이름이 클래스명과 똑같고, 매개변수가 없다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Student {
	static int numberOfStudent; // 클래스 변수(값을 공유)
	String name; // 인스턴수 변수
	
	Student(){ // 디폴트 생성자
		numberOfStudent++;
	}
	
	Student(String name){
		numberOfStudent++;
		this.name = name;
	}
	
	void print(){
		System.out.println("name : " + name);
		System.out.println("numberOfStudent : " + numberOfStudent);
	}
}

this

반드시 생성자 첫 줄에 한번만 사용해야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Student {
	static int numberOfStudent;
	String name; 
	int age;
	double score;
		
	Student(String name){
		numberOfStudent++;
		this.name = name;
	}
	
	Student(String name, int age){
		this(name); // 첫 줄에 한번 작성.
		this.name = name;
		numberOfStudent++;
	}
	
	Student(String name, int age, double score){
		this(name); // 첫 줄에 한번 작성.
		this(name, age); // Error.
		this.name = name;
		numberOfStudent++;
	}
}

public, private, default, protected

private 같은 클래스에서만 접근이 가능하다.

  • 접근자 : get<인스턴스 변수명>을 이용하여 인스턴스 변수의 값을 가져온다.
  • 변경자 : set<인스턴스 변수명>을 이용하여 인스턴스 변수의 값을 변경한다.

protected 패키지가 같거나 달라도 상속 관계에 있으면 접근이 가능하다.
default 상속과 관계없이 같은 패키지 안에서만 접근 가능하다.
public 어디서나 접근 가능하다.

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
class Student {
	public String name;
	private int score;
	int num;	
	
	// 접근자 (다른 접근제어도 사용 가능)
	String getScore(){
		return score
	}
	
	// 변경자 (다른 접근제어도 사용 가능)
	void setScore(int score){
		this.score = score;
	}
}

public class Practice {
	public static void main(String[] args){
			Student s1 = new Student();
			s1.name = "김민수";
			s1.score = 10; // 에러
			s1.num = 1;
			
			// 변경자 호출
			s1.setScore(100);
			// 접근자 호출
			System.out.println(s1.getScore());
	}
}

상속

extends 키워드로 다른클래스를 상속받을 수 있다.
자식 객체를 생성하면 부모 생성자를 호출하고 다음으로 자식의 생성자를 호출한다.
만약 부모 클래스에 디폴트 생성자가 아닌 생성자가 하나라도 있으면 디폴트 생성자를 자동으로 제공하지 않는다.

1
2
3
4
5
6
7
8
9
class Parent {
	Parent(int data){
		
	}
}

class Child extends Parent {
	Child(){} // 에러 발생
}

super

자식 클래스에서 부모 멤버에 접근하려면 사용하는 키워드이다.
super를 사용할 때에도 this와 마찬가지로 생성자 맨 첫줄에 적어야한다.
superthis를 동시에 사용할 수 없다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Parent {
	private String name;
	private int age;
	Parent(){}
	Parent(String name, int age){
		
	}
}

class Child extends Parent {
	private String gender;
	
	Child(){} 
	Child(String gender){
		
	}
	Child(String name, int age, String gender){
		super(name, age); // 에러발생
		this(gender)
	}
}

final

final 클래스는 자식 클래스를 가질 수 없는 클래스이다.
인수턴스 변수 앞에 final은 상수라는 뜻이다.
final메소드는 오버라이딩 할 수 없는 메소드이다.
지역변수로 지정된 final변수는 한번 값이 지정되면 변경이 불가능하다.

1
2
3
4
5
6
7
8
9
10
final class Data { // final 클래스
	final private int x; // final 인스턴스 변수 x
	final void print(){ // final 메소드
		
	}
	void test() {
		final int data; // final 지역변수 data
	}
}

다형성

다형성은 부모 클래스에 있는 멤버를 접근할 수 있으며, 자식 클래스에 오버라이딩 된 메서드가 존재한다면, 자식클래스의 메서드를 우선 접근하게 된다.

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
class Parent {
	void print(){
		System.out.println("parent print");
	}
	void print2(){
		System.out.println("parent pirnt2");
	}
}

class Child extends Parent {
	void print() {
		System.out.println("child print");
	}
	
	void check(){
		System.out.println("child check");
	}
}

public class Practice{
	public static void main(String[] args){
		Parent x = new Child();
		x.print();
		x.print2();
		x.check(); // 에러
	}
}

// 결과 ( x.check() 없을시 )
parent print
parent print2

다형성을 사용하는 이유

  1. 코드 재사용성 향상
    • 다형성을 사용하면 하위 클래스들을 공통적으로 처리할 수 있으므로, 코드의 재사용성이 향상된다.
    • 동일한 메서드나 기능을 여러 클래스에서 재사용할 수 있다.
  2. 유연성과 확장성
    • 다형성은 새로운 클래스를 추가하거나 기존 클래스를 수정하지 않고도 기존 코드를 확장하고 변경할 수 있게 한다.
    • 이로써 소프트웨어의 유지 보수 및 확장이 더 쉬워진다.
  3. 객체 간의 상호교환이 가능
    • 상위 클래스 타입으로 선언된 변수에 하위 클래스의 객체를 할당할 수 있다.
      이는 코드의 일반화(generalization)를 가능하게 하며, 코드의 유연성을 높인다.