기본형 매개변수

기본형 매개변수 - 변수의 값을 읽기만 할 수 있다. (readonly)

참조형 매개변수 - 변수의 값을 읽고 변경할 수 있다. (read & write)

 

class Data { int x; }

class Example {
	public static void main(String[] args) {
    	Data d = new Data();
        d.x = 10;
        System.out.println("main() : x = " + d.x);
        
        change(d.x);
        System.out.println("main() : x = " + d.x);
    }
    static void change(int x) { // 기본형 매개변수
    	x = 1000;
        System.out.println("change() : x = " + x);
    }
}

먼저 값을 예상해본다.

 

Data타입의 d라는 참조 변수에 Data객체를 생성해서 그 주소를 d가 가리킨다.

 

d.x를 통해서 메서드를 호출하고 10이 change에 들어간다.

 

출력을 통해 change 메서드에 있는 출력문을 출력하고

 

돌아왔을때 d.x를 또 호출하지만 값은 10이다. why? void타입으로 return을 하고 있지 않기 때문!!


참조형 매개변수

class Data { int x; }

class Example {
	public static void main(String[] args) {
    	Data2 d = new Data2();
        d.x = 10;
        System.out.println("main() : x = " + d.x);
        
        change(d);
        System.out.println("main() : x = " + d.x);
    }
    static void change(Data2 d) { // 참조형 매개변수
    	d.x = 1000;
        System.out.println("change() : x = " + x);
    }
}

참조형 매개 변수도 실행 순서를 먼저 적어 본다.

 

메서드를 호출하고 d의 값을 change메서드에 파라미터로 보낸다 

 

그런다음 d.x를 통해서 d의 x값에 1000을 대입한다

 

그러면 객체 d 주소에 있는 x의 값을 1000으로 바꿧으므로 메인 메서드의 d.x에 1000이 저장된다.

 

change(d)에서 메인메서드는 대기 상태가 되고,
d가 이동하는 것이 아니라 복사가 되고, 이 참조변수도 d.x 10의 값을 가리키게 되는 것.
그리고 10이였던 값을 1000으로 바꾼다.
참조형 반환타입
class Data { int x; }

class Example {
	public static void main(String[] args) {
    	Data3 d = new Data3();
        d.x = 10;
        Data3 d2 = copy(d)
        
        System.out.println("1 : " + d.x);
        System.out.println("2 : " + d2.x);
    }
    static Data3 copy (Data3 d) {
    	Data3 tmp = new Data3();
        
        tmp.x = d.x;
        
        return tmp;
    }
}

먼저 예상해보자!

 

일단 d.x는 아무런 변화가 없음 10이 찍힐 것

 

d2는 d를 참조하는 매개변수를 복사해서 파라미터로 넘겨주고

 

그곳에는 tmp라는 참조변수를 가진 Data3타입의 객체가 생성되고

 

tmp가 가리키는 x의 값에 d가 가리키는 10의 값을 넣어준다.

 

그리고 tmp를 돌려줌으로 Data3 타입의 d2.x또한 10을 갖게 된다!

 

return tmp; 부분에서
0x200 주소에 저장되어있는 객체의 주소를 반환해주는 것
0x200 주소를 d2가 갖게되고, 그 다음 tmp.x의 0x200의 10을 가리킨다.

static 메서드와 인스턴스 메서드

메서드 앞에 static이 붙는 것이 클래스 메서드(static 메서드)

그럼 인스턴스 메서드는 ? static 없는 것

 

인스턴스 메서드

- 인스턴스 생성 후, 참조변수.메서드이름()으로 호출

- 인스턴스 멤버(iv, im)와 관련된 작업을 하는 메서드

- 메서드 내에서 인스턴스 변수(iv) 사용 가능

 

static 메서드(클래스 메서드)

- 객체생성없이 클래스이름.메서드이름()으로 호출 예를 들면 Math.random

- 인스턴스 멤버(iv, im)와 관련없는 작업을 하는 메서드

- 메서드 내에서 인스턴스 변수(iv) 사용 불가

 

static을 언제?

속성(멤버 변수)중에서 공통 속성에 static을 붙인다.

 

 

메서드란?

- 문장들을 묶어놓은 것

- 값(입력)을 받아서 처리하고, 결과를 반환(출력)

 

코드의 중복을 줄이기 위해서 메서드를 사용한다.

 

만약에 반복문이 있으면 그거를 두번 작성하는 것이 아닌 메서드를 이용해서 한번 작성하고 메서드를 호출하는 방법으로 사용한다.

 

int add (int x, int y) {
	int result = x + y;
	return result;
}

메서드 이름은 add가 된다.

매개변수가 int x , int y (입력 부분)이 된다.

 

return으로 결과를 반환한다.

 

메서드의 장점

- 코드의 중복 줄임

- 코드의 관리 쉽다

- 코드 재사용

- 코드 간결해서 이해 쉽다

메서드의 작성

- 반복적으로 수행되는 여러 문장을 메서드로 작성

- 하나의 메서드는 한 가지 기능만 수행하도록 작성

 

메서드 = 선언부 + 구현부
int add (int x, int y) // 선언부{
	int result = x + y; // 구현부
	return result;      // 구현부
}                       // 구현부

지역 변수(lv) : 메서드 내에 선언된 변수

위의 코드에서는 x,y 그리고 result가 모두 지역 변수가 된다. 메서드가 종료되면 사라짐!

 


메서드 호출

메서드 이름 (값1, 값2, ... ); // 메서드를 호출하는 방법

 

void는 그냥 써주면 됨.

 

메서드의 값을 받아와서 함수를 실행하고 작업을 마치면 다시 호출한 곳으로 돌아간다.

 

메서드는 클래스 영역에만 정의 가능하다!


return문, 반환값

실행 중인 메서드를 종료하고 호출한 곳으로 되돌아간다.

void testMethod(int num){
	if(!(2 <= num && num <= 10))
    	return;
    
    for(int i=1; i<=9; i++){
    	System.out.printf("%d * %d = %d%n", num, i, num * i);
    }
   	return;
}

반환 타입이 void가 아니면, 반드시 return문이 필요하다.


호출 스택(call stack)

스택(stack):밑이 막힌 상자. 차곡차곡 쌓임.

 

메서드 수행에 필요한 메모리가 제공되는 공간

메서드가 호출되면 호출스택에 메모리 할당, 종료되면 해제

 

프로그램 실행과정이 중요함.

 

엄청 간단한 코드로 해석해보자.

class Test{
	public static void main(String[] args){
    	System.out.println("Hello");
    }
}

처음에는 스택이 비어있음.

그리고 이제 main메서드가 올라가고, 그 다음에 main이 println을 호출함(이때 main은 대기상태로 변함),

println을 작업을 완료하고 메모리를 반환하고 종료함. 그러면 다시 main으로 가고 main도 실행상태에서 이제 더 이상 실행할 문장이 없으므로 메모리 반환하고 프로그램이 종료된다.

선언위치에 따른 변수의 종류

{
	int iv;
    static int cv;
    
    void method(){
    	int lv = 0;
    }
}

위의 코드를 보면

int iv 는 인스턴스 변수

static int cv 는 클래스 변수(static 변수, 공유 변수)

int lv 는 메서드 영역의 지역 변수이다.

 

위의 iv,cv는 클래스 변수에 속한다.

 

클래스 영역에는 y=x+3; 또는 System.out.println() 같은 일반 문장들은 들어올 수 가없다.

오직 선언문만 들어갈 수 있음.

 

클래스 변수는 클래스가 메모리에 올라갈 때 생성된다.

인스턴스 변수는 인스턴스가 생성되었을 때⭐ 생성된다.

지역 변수는 변수 선언문이 수행되었을 때 사용된다.

 

객체는 iv 변수 묶음이다!

 


클래스 변수와 인스턴스 변수

카드에서 

숫자하고 무늬는 개별마다 다르기 때문에 다르게 유지되어야 함. 이것은 인스턴스 변수이다.(개별 속성)

 

폭 하고 넓이는 다 똑같이 유지되어야 함. 다이아몬드 카드의 크기만 크면 안되기 때문.. 클래스 변수 (공통 속성)

class Card{
	String kind;
	int number;
    
	static int width = 100; // 폭 공통 속성
	static int height = 250; // 높이 공통 속성

}

iv는 c.kind = "DIAMOND";

c.number = 5;

으로 사용이 가능한데

cv는 가능하면 c.width로 가능하지만,

Card.width = 200;

Card.height = 300;

iv로 오해할 수 있기 때문에 Card로 쓰는 것이 좋다.

 

 

객체지향 언어의 특징은

 

코드의 재사용성이 높고 유지보수가 용이, 중복 코드 제거

 

객체지향 언어는 프로그래밍 언어 + 객체지향개념(규칙)이 추가된 것이다.

 

객체 지향언어의 핵심적인 4가지 특징

OOP(Object-Oriented Programming)

 

1. 캡슐화

2. 상속

3. 추상화

4. 다형성⭐

 

클래스와 객체

클래스란? 객체를 정의해 놓은 것

 

어디에 쓰일까? 클래스 객체를 생성하는데 사용

 

객체의 정의? 실제로 존재하는 것, 사물 또는 개념

객체의 용도 객체가 가지고 있는 기능과 속성에 따라 다르다.

 

객체와 인스턴스

객체 : 모든 인스턴스를 대표하는 일반적인 용어

인스턴스 : 특정 클래스로부터 생성된 객체(예: Tv인스턴스)

 

설계도를 가지고 제품을 만드는 것을 인스턴스화 라고 한다.

 

클래스 ----- 인스턴스화 ----> 인스턴스(객체)

 


하나의 파일에 클래스를 두개 넣을 수 있음.

 

Hello.java

public class Hello{

}
class hello2{}

public이 있는 경우 , 소스파일의 이름은 반드시 pulic class의 이름과 일치해야 한다.


객체의 생성과 사용

1. 객체의 생성

클래스명 변수명;            클래스의 객체를 참조하기 위한 참조변수를 선언           

변수명 = new 클래스명(); 클래스의 객체를 생성 후, 객체의 주소를 참조변수에 저장

 

Tv t;           Tv클래스 타입의 참조변수 t를 선언

t = new Tv();Tv인스턴스를 생성한 후, 생성된 Tv인스턴스의 주소를 t에 저장

 

2. 객체의 사용

t.channel = 7; Tv인스턴스의 참조변수 t의 멤버 변수 channel의 값을 7로 한다. Tv클래스형의 t는 참조변수 이다.

t.channelDown(); // Tv인스턴스의 메서드 channelDown()을 호출한다.


객체 배열

객체 배열 == 참조변수 배열

 

Tv tv1, tv2, tv3; 를 배열로 바꾸면

Tv[] tvArr = new Tv[3];

tvArr[0] = new Tv();
tvArr[1] = new Tv();
tvArr[2] = new Tv();

Tv[] tvArr = { new Tv(), new Tv(), new Tv()};

클래스의 정의

클래스 == 데이터 + 함수

 

클래스의 정의

- 설계도

- 데이터 + 함수

- 사용자 정의 타입

 

1. 변수 하나의 데이터를 저장할 수 있는 공간

2. 배열 같은 종류의 여러 데이터를 하나로 저장할 수 있는 공간

3. 구조체 서로 관련된 여러 데이터(종류 관계X)를 하나로 저장할 수 있는 공간

4. 클래스 데이터와 함수의 결합(구조체 + 함수)

 

사용자 정의 타입? - 원하는 타입을 직접 만들 수 있다.

 

int hour;

int minute;

int second;

- T 타입 객체의 래퍼 클래스 - Optional <T>

래퍼 클래스란? Integer , Long.... int(X)

 

public final class Optional <T> {

       private final T value; // T타입의 참조 변수

           ...

}

T타입의 value는 모든 종류의 객체를 저장할 수 있다.(null을 저장할 수 있다.)

null을 직접 사용하면 위험 부담이 크다 nullpointException이 발생할 수 있기 때문!!

 

간접적으로 null을 다루기 위해서 Optional 사용함.

 

한마디로, null이 올 수 있는 값을 감싸는 wrapper 클래스! 🤗

if(result != null){
	result.toString()
}

이런 식으로 null이 없을 때 사용해야 되기 때문에 if문을 사용하는 것을 방지해주기 위해 Optional을 사용함.


Optional <T> 객체 생성하기

- Optional<T> 객체를 생성하는 다양한 방법

String str = "abc";

Optional <String> optVal = Optional.of(str);

Optional <String> optVal = Optional.of("abc");

Optional <String> optVal = Optional.of(null);

Optional<String> optVal = Optional.ofNullable(null); 

 

한 단계 더 거친 거라고 생각하면 됨.

 

- null대신 빈 Optional <T> 객체를 사용하자

Optional <String> optVal = null; // 널로 초기화. 바람직하지 않음.

Optional <String> optVal = Optional. <String> empty(); // 빈 객체로 초기화


Optional <T> 객체의 값 가져오기

- Optional객체의 값 가져오기 - get(), orElse(), orElseGet(), orElseThrow()

 

Optional <String> optVal = Optional.of("abc");

String str1 = optVal.get(); // optVal에 저장된 값을 반환. null이면 예외 발생

String str2 = optVal.orElse(""); // optVal에 저장된 값이 null일 때는, "'를 반환

String str3 = optVal.orElseGet(String::new); // 람다식 사용 가능 () -> new String()

String str4 = optVal.orElseThrow(NullPointerException::new);  // null이면 예외 발생

 

- isPresent() - Optional객체의 값이 null이면 false, 아니면 true를 반환

if(Optional.ofNullable(str). isPresent()){

      System.out.println(str);

}

 

// ifPresent(Consumer) - null이 아닐 때만 작업 수행, null이면 아무 일도 안 함

Optional.ofNullable(str). ifPresent(System.out::println);


Surround With 들어가면 try / catch문 자동으로 만들어 준다.

package OptionalPt;

import java.util.Optional;

public class OptionalTests {

	public static void main(String[] args) {
		Optional<String> opt2 = null; // OK. 하지만 null은 바람직하지 않다.
		Optional<String> opt = Optional.empty();
		System.out.println("opt="+opt);
		//System.out.println("opt="+opt.get()); // null이여서 예외 발생함. get 잘 안씀
		
		String str = "";
		
		try {
			str = opt.get();
		} catch (Exception e) {
			str =""; // 예외 발생하면 ""로 초기화
		}
		
//		str = opt.orElse("EMPTY"); // Optional에 저장된 값이 null이면 ""반환
//		str = opt.orElseGet(() -> new String()); // Optional에 저장된 값이 null이면 ""반환
		str = opt.orElseGet(String::new); // Optional에 지정된 값이 null이면 ""반환
		System.out.println("str="+str);
	}

}

OptionalInt, OptionalLong, OptionalDouble

- 기본형 값을 감싸는 래퍼 클래스

성능 때문에 씀.. 그냥 Optional 써도 상관없다.

 

- OptionalInt의 값 가져오기 - int getAsInt()

Optional <T> T get()

OptionalInt  int getAsInt()

OptionalLong long getAsLong()

OptionalDouble double getAsDouble()

 

- 빈 Optional객체와의 비교

OptionalInt opt = OptionalInt.of(0); // OptionalInt에 0을 저장

OptionalInt opt2 = OptionalInt.empty(); // OptionalInt에 0을 저장

 

System.out.println(opt.isPresent()); // true

System.out.println(opt2.isPresent()); // false

System.out.prinltln(opt.equals(opt2)); // false

 

opt는 value가 0이어서 값은 있음.

empty도 value는 0인데 값이 없어서 false이다.

 

package OptionalPt;

import java.util.Optional;
import java.util.OptionalInt;

public class OptionalTests2 {
	public static void main(String[] args) {
		Optional<String> optStr = Optional.of("abcde");
		Optional<Integer> optInt = optStr.map(String::length);
		
		System.out.println(optStr);
		System.out.println(optInt);
		
		int result1 = Optional.of("123")
						.filter(x->x.length() > 0)
						.map(Integer::parseInt).get();
		
		int result2 = Optional.of("")
						.filter(x->x.length() > 0)
						.map(Integer::parseInt).orElse(-1);
		
		System.out.println(result1);
		System.out.println(result2);
		
		Optional.of("456").map(Integer::parseInt)
						  .ifPresent(x->System.out.printf("result3=%d%n",x));
		
		OptionalInt optInt1 = OptionalInt.of(0);   // 0을 저장
		OptionalInt optInt2 = OptionalInt.empty(); // 빈 객체를 생성
		
		System.out.println(optInt1.isPresent()); // true
		System.out.println(optInt2.isPresent()); // false
	}
}

 

스트림의 중간연산

map() , peek() , faltmap()

 

스트림의 요소 변환하기 - map()

Stream<R> map(Function<? super T,? extends R> mapper) // Stream<T>->Stream<R>

Stream<File> fileStream = Stream.of(new File("Ex1.java"), new File("Ex1) new File("Ex1.bak), 
	new File("Ex2.java), new File("Ex1.txt"));

Stream<String> filenameStream = fileStream.map(File::getName);
filenameStream.forEach(System.out::println); // 스트림의 모든 파일의 이름을 출력

map을 이용해서 바꾸는 것.

파일 이름을 String으로 바꾸는 것

Stream<File> ------- map(File::getName) ------> Stream<String>

 

예제 ) 

package Stream;

import java.io.File;
import java.util.*;
import java.util.stream.Stream;

public class StreamPt2 {

	public static void main(String[] args) {
		File[] fileArr = { new File("Ex1.java"),new File("Ex1.bak"),
				new File("Ex2.java"),new File("Ex1"),new File("Ex1.txt")};

		Stream<File> fileStream = Stream.of(fileArr);
		
		// map()으로 Stream<File>을 Stream<String>으로 변환
		Stream<String> filenameStream = fileStream.map(File::getName);
		filenameStream.forEach(System.out::println); // 모든 파일의 이름을 출력
		
		fileStream = Stream.of(fileArr); // 스트림을 다시 생성
		
		fileStream.map(File::getName)
			.filter(s -> s.indexOf('.') != -1) // 확장자가 없는 것 제외
			.map(s -> s.substring(s.indexOf('.')+1)) // 확장자만 추출
			.distinct()					   // 중복 제거
			.forEach(System.out::println); // JAVABAKTXT
		
		System.out.println();
	}

}

map을 이용해서 String을 자유 자재로 변경시킬 수 있다.


스트림의 요소를 소비하지 않고 엿보기 - peek()

Stream<T> peek(Consumer<? super T> action) // 중간 연산(스트림을 소비x)

void          forEach(Consumer<? super T action) // 최종 연산(스트림을 소비o)

 

fileStream.map(File::getName)
    .filter(s -> s.indexOf('.')!=-1)
    .peek(s->System.out,printf("filename=%s%n", s))
    .map(s -> s.substring(s.indexOf('.')+1)) 
    .peek(s ->System.out.printf("extension=%s%n", s))
    .forEach(System.out::println);

일단 File을 Stream으로 바꿔준다.

filter로 확장자 .이 없는 것을 걸러줌.

peek로 파일명을 출력함.

map으로 확장자만 추출한다.

peek로 확장자를 출력함.

마지막 최종 연산으로 스트림을 소비한다.

중간 중간 출력하는 부분은 최종 연산에서 스트림을 소비하면서 다시 만들어 줘야 하는데 peek은 엿봐서 소비시키지 않는다.

 

		fileStream.map(File::getName)
			.filter(s -> s.indexOf('.') != -1) // 확장자가 없는 것 제외
			.peek(s->System.out.printf("filename=%s%n",s))
			.map(s -> s.substring(s.indexOf('.')+1)) // 확장자만 추출
			.peek(s->System.out.printf("extension=%s%n",s))
			.distinct()					   // 중복 제거
			.forEach(System.out::println); // JAVABAKTXT

중간 중간에 peek를 추가해준다.


스트림의 스트림을 스트림으로 변환 - flatMap()

Stream<String []> strArrStrm = Stream.of(new String[]{"abc", "def", "ghi"},

                                                      new String[]{"ABC", "GHI", "JKLMN"});

package Stream;

import java.util.Arrays;
import java.util.stream.Stream;

public class StreamFlatmap {
	public static void main(String[] args) {
		Stream<String[]> strArrStrm = Stream.of(
			new String[] {"abc","def","jkl"},
			new String[] {"ABC","GHI","JKL"}
		);
		
		Stream<String> strStrm = strArrStrm.flatMap(Arrays::stream);
		
		strStrm.map(String::toLowerCase)
			.distinct()
			.sorted()
			.forEach(System.out::println);
		System.out.println();
		
		String[] lineArr = {
			"Believe or not It is true",
			"Do or do not There is no try",
		};
		
		Stream<String> lineStream = Arrays.stream(lineArr);
		lineStream.flatMap(line -> Stream.of(line.split(" +")))
			.map(String::toLowerCase)
			.distinct()
			.sorted()
			.forEach(System.out::print);
	}
}

split(" +")는 하나 이상의 공백을 의미함 보통 " "는 공백 하나임.

 

+ Recent posts