A Tour of Java III Sungjoo Ha March 18th, 2016 Sungjoo Ha 1 / 30
Review First principle 문제가생기면침착하게영어로구글에서찾아본다. 타입은가능한값의집합과연산의집합을정의한다. 기본형이아니라면이름표가메모리에달라붙는다. 클래스로사용자정의타입을만든다. 프로그래밍은복잡도관리가중요하다. OOP 는객체가서로메시지를주고받는방식으로프로그램을구성해서복잡도관리를꾀한다. Sungjoo Ha 2 / 30
Objects 자바에서사용자정의타입을정의하고사용하는방법이클래스이다. 코드가어떤 개념 을대표하도록하는것이클래스이다. 자바의기초적인타입, 연산자와명령을제외한대부분의기능이클래스를더잘만들거나잘사용할수있기위해존재한다. 사고하기쉽게 읽기쉽게 사용하기쉽게 우아하게 효율적으로동작하게 유지보수가쉽게 올바로동작하게 Sungjoo Ha 3 / 30
Classes 클래스로만들어진타입은기본형과비슷한방식으로동작해야한다. 물론자체적인의미와연산을갖게된다. BigInteger 는마치 int 를사용하는것과같은방식으로사용할수있어야한다. Sungjoo Ha 4 / 30
Complex class Complex { private int re, im; public Complex(int re, int im) { this.re = re; this.im = im; public Complex(int r) { this(r, 0); public Complex() { this(0, 0); public int real() { return re; public int imag() { return im; public Complex add(complex that) { return new Complex(this.re + that.real(), this.im + that.imag()); public Complex sub(complex that) { return new Complex(this.re - that.real(), this.im - that.imag()); Sungjoo Ha 5 / 30
Complex private 과 public 키워드를사용해서구현과인터페이스를분리하였다. 여러종류의생성자를정의하였다. this 를사용해서생성자를호출할수있다. 또다른 this 의사용예로자기자신을가리킬수있다. this.re = re 객체가개념적으로같은지여부는 equals 메소드를만들어서비교한다. add 와 sub 가각각새객체를생성하여리턴한다. new 연산자와함께생성자를부르고이를통해클래스의인스턴스를생성한다. 즉, Complex 타입의객체를생성한다. Complex 타입의일종 (instance) 을만드는것이기에이를인스턴스라고부른다. Sungjoo Ha 6 / 30
Complex class Complex { public int hashcode() { final int prime = 31; int result = 1; result = prime * result + re; result = prime * result + im; return result; public boolean equals(object obj) { if (obj == null) return false; if (getclass()!= obj.getclass()) return false; Complex other = (Complex) obj; return re == other.re && im == other.im; Sungjoo Ha 7 / 30
Complex Equality 두객체가개념적으로같은지비교하기위해 equals 메소드를사용한다. equals 메소드는항상 Object 를인자로받아야한다. 자기자신과의비교는참을리턴해야한다. equals 메소드를만들면 hashcode 메소드를항상함께만들어줘야한다. Eclipse 에서자동생성할수있다. Source 메뉴의 Generate hashcode and equals Sungjoo Ha 8 / 30
User-Defined Types public class ComplexTest { public static void main(string[] args) { Complex a = new Complex(12); Complex b = new Complex(1, 2); Complex c = new Complex(1, 2); Complex d = a.add(b); System.out.println(d.real() + " + " + d.imag() + "i"); System.out.println(b == c); System.out.println(b.equals(c)); Complex 타입을사용하는방식이기본형인 int 와크게다르지않음을주시하라. Sungjoo Ha 9 / 30
Equality class Something { int member; String h; public int hashcode() { final int prime = 31; int result = 1; result = prime * result + ((h == null)? 0 : h.hashcode()); result = prime * result + member; return result; Sungjoo Ha public boolean equals(object obj) { if (this == obj) return true; if (obj == null) return false; if (getclass()!= obj.getclass()) return false; Something other = (Something) obj; if (h == null) { if (other.h!= null) return false; else if (!h.equals(other.h)) { return false; if (member!= other.member) return false; return true; 10 / 30
Equality 또다른 equals 예제이다. 각멤버에적합한방식으로 equals 와 hashcode 를만들어야한다. 멤버로정수와문자열이있다. 논리적으로두객체가같음은같은논리적인내용을담고있음을뜻한다. hashcode 는논리적으로같은객체라면같은값을뱉어야한다. 보통 hashcode 는소수를곱하고멤버를적절히숫자로표현한값을더하는것을반복하여계산된다. 자신이없다면 Eclipse 를사용해서자동생성하기를권한다. Sungjoo Ha 11 / 30
Container class Vector { // construct a Vector public Vector(int s) { elem = new double[s]; sz = s; // elem access public double elementat(int i) { return elem[i]; public void set(int i, double e) { elem[i] = e; public int size() { return sz; private int sz; // number of elements private double[] elem; // array of elements Container 는원소여러개를한데모은것을가리킨다. Vector 는그러므로 container 이다. 과제 2 번에서구현할 linked list 도 container 이다. Sungjoo Ha 12 / 30
Container Scope/Lifetime public class VectorConsole { public static void main(string[] args) { int n = 10; Vector v1 = new Vector(n); { int m = 20; Vector v2 = new Vector(2*n); // m and v2 are out of scope 사용자가 Vector 를쓸때에마치기본형을사용하는것과비슷한느낌으로사용할수있어야한다. Vector 는기본형과같은스코프및생명주기를가진다. Sungjoo Ha 13 / 30
Container Usage public void add(double e) { // Append an element at the end of the sequence. // Increase the size accordingly. Vector v1 = new Vector(10); for (int i = 0; i < 20; ++i) { v1.add(i); Container 는원소를들고있기위해존재한다. 그러므로원소를 container 에넣는편리한방법이있어야한다. add() 메소드는원소를시퀀스의마지막에추가하며필요하다면메모리할당을더하고크기를증가시켜야한다. 클래스를구현할때사용자의입장에서어떻게쉽게사용할수있는지고민하자. 간결하게표현할수있도록 실수하지않도록 Sungjoo Ha 14 / 30
Class Variables class Block { public static String message = "What I cannot create, I do not understand"; public class BlockTest { public static void main(string[] args) { System.out.println(Block.message); 특정인스턴스가아닌클래스에달린변수를만들고싶을때가있다. static 키워드를사용하여달성할수있다. message 는특정인스턴스가없이바로접근가능함을주시하라. Sungjoo Ha 15 / 30
Class Variable Lifetime class Block2 { static int count = 0; public Block2() { count += 1; System.out.println("Block #" + count); public class BlockTest2 { public static void main(string[] args) { new Block2(); new Block2(); new Block2(); static 변수는특정인스턴스에묶여있지않고클래스에달려있다. 새인스턴스가생긴다고새로초기화되는것이아니다. Sungjoo Ha 16 / 30
Class Methods class Block3 { private static int count = 0; private int id = 0; public Block3() { count += 1; id = count; public int getid() { return id; public void printranking() { System.out.println(id + " out of " + getcount() + " blocks"); public static int getcount() { return count; public class BlockTest3 { public static void main(string[] args) { Block3 b1 = new Block3(); Block3 b2 = new Block3(); Block3 b3 = new Block3(); System.out.println(Block3.getCount()); b2.printranking(); Sungjoo Ha 17 / 30
Class Methods static 메소드도특정인스턴스에묶여있지않고클래스에달려있다. 특정인스턴스에묶여있지않기에인스턴스변수에접근하는것은성립하지않는다. 인스턴스메소드는인스턴스변수와인스턴스메소드에직접적으로접근할수있다. 인스턴스메소드는클래스변수와클래스메소드에직접적으로접근할수있다. 클래스메소드는클래스변수와클래스메소드에직접적으로접근할수있다. 클래스메소드는인스턴스변수와인스턴스메소드에직접적으로접근할수없다. Sungjoo Ha 18 / 30
Class Methods class Mathematics { static int abs(int a) { if (a > 0) { return a; else { return -a; public class MathematicsTest { public static void main(string[] args) { System.out.println(Mathematics.abs(-10)); 절대값을계산하는메소드는특정인스턴스에묶이는것이자연스럽지않다. static 메소드를만들기전에특정인스턴스가없어도해당메소드를부르는게적합한지질문해보자. Sungjoo Ha 19 / 30
Word of Caution I public class BigIntStatic { public static int[] add(string left, String right) { // magic happens return new int[10]; public static void main(string[] args) { // somehow the input is represented as a string String leftstr = "123456789"; String rightstr = "987654321"; char op = + ; int[] result = add(leftstr, rightstr); 자주하는실수 논리적단위로코드를나누며메소드를추출하지만 main 메소드에서바로호출하기위해 static 메소드를다량만드는경우. OOP 는객체가서로메시지를주고받는방식으로프로그램을구성해서복잡도관리를꾀한다. 클래스메소드로모든것을만들지마라. Sungjoo Ha 20 / 30
Word of Caution II class Mathematics { public int abs(int a) { if (a > 0) { return a; else { return -a; public class InstanceHell { public static void main(string[] args) { int input = -1234; Mathematics math = new Mathematics(); System.out.println(math.abs(input)); 자주하는실수 클래스메소드를피하기위해객체를만들고인스턴스메소드만사용하는경우. 클래스메소드를피한다고모든것을인스턴스메소드로만들지마라. Sungjoo Ha 21 / 30
Numbers public class Box { public static void main(string[] args) { int a = new Integer(10); Integer b = 30; 숫자를다룰때기본형에대응되는클래스가있다. int와 Integer float과 Float... http://docs.oracle.com/javase/tutorial/java/data/ numbers.html 이런클래스는기본형을감싸서 (wrap) 객체로다룰수있게만들어주는역할을한다. 편의를위해컴파일러가감싸고푸는것을자동으로해준다. 이를 autoboxing, unboxing 이라부른다. Sungjoo Ha 22 / 30
Wrapper Objects import java.util.arraylist; public class Conversion { public static void main(string[] args) { String a = "123124"; int b = Integer.parseInt(a); System.out.println(b); System.out.println(Integer.MAX_VALUE); ArrayList<Integer> l = new ArrayList<>(); Wrapper object 를굳이사용하는이유 객체를기대하는곳에사용하기위해 ( 메소드호출인자, 제네릭타입인자 ) 객체가제공하는클래스변수나클래스메소드를사용하기위해 http://docs.oracle.com/javase/tutorial/java/data/ numberclasses.html Sungjoo Ha 23 / 30
String public class StringTest { public static void main(string[] args) { String a = "Knowledge and productivity are"; String b = " like compound interest"; int c = 10; System.out.println(a.length()); System.out.println(a.charAt(0)); System.out.println(a + b); System.out.println(c); System.out.println(c + " times"); 문자열도객체로다양한메소드를지원한다. 정수형을바로 println 하면사실내부적으로 Integer.toString 이호출된다. 마찬가지로 10 + times 는 10 이문자열로변환된뒤문자열간의 + 연산이실행된다. http://docs.oracle.com/javase/tutorial/java/data/ strings.html Sungjoo Ha 24 / 30
String and StringBuilder String 은불변형 (immutable) 이다. 객체의데이터에변환이일어나면새객체가생성된다. concat(), replace(),... Mutable 한 String 의짝으로 StringBuilder 가있다. StringBuilder 는코드가매우간결해지거나성능이필요할때만사용한다. String 간의 + 연산은사실 StringBuilder 로변환된뒤 append 로추가된다. http://docs.oracle.com/javase/tutorial/java/data/ buffers.html Sungjoo Ha 25 / 30
Reverse public class Reverse { static String stringreverse(string str) { int len = str.length(); char[] tempchararray = new char[len]; char[] chararray = new char[len]; for (int i = 0; i < len; ++i) { tempchararray[i] = str.charat(i); for (int i = 0; i < len; ++i) { chararray[i] = tempchararray[len - 1 - i]; String reversed = new String(charArray); return reversed; static String stringbuilderreverse(string str) { StringBuilder sb = new StringBuilder(str); sb.reverse(); return sb.tostring(); public static void main(string[] args) { String str = "Laziness"; System.out.println(stringReverse(str)); System.out.println(stringBuilderReverse(str)); Sungjoo Ha 26 / 30
String vs StringBuilder public class StringConcatComparison { private static String s = "1234567890"; private static int loopcnt = 100000; private static String stringbuilderconcat() { StringBuilder sb = new StringBuilder();; for (int i = 0; i < loopcnt; ++i) sb.append(s); return sb.tostring(); private static String stringconcat() { String c = ""; for (int i = 0; i < loopcnt; ++i) c += s; return c; public static void main(string[] args) { System.out.println(stringBuilderConcat().length()); System.out.println(stringConcat().length()); // slow Sungjoo Ha 27 / 30
Regex import java.util.regex.pattern; import java.util.regex.matcher; public class RegexTest { public static void main(string[] args) { String patternstr = "(?<sign>[[+][-]]?)(?<num>[0-9]+)"; String str = "12312-321"; Pattern pattern = Pattern.compile(patternStr); Matcher matcher = pattern.matcher(str); while (matcher.find()) { System.out.println(matcher.group() + " beginning at " + matcher.start() + " and ending at " + matcher.end()); System.out.println(matcher.group("sign")); System.out.println(matcher.group("num")); http://docs.oracle.com/javase/tutorial/essential/ regex/index.html Sungjoo Ha 28 / 30
Advice 코드로의도를분명히표현하라. 가능하면일련의데이터조작이아닌객체간의메시지주고받기로코드를작성하라. 각각의객체는마치기본형을사용하는것과비슷한느낌으로사용할수있도록한다. 객체가제공하는연산은상식적으로동작해야한다. 두객체가논리적으로같음을표현하기위해 equals 메소드를사용한다. equals 메소드와함께 hashcode 메소드를정의해줘야한다. Sungjoo Ha 29 / 30
Advice 인스턴스변수는개별객체의상태를표현한다. 인스턴스메소드는객체의내부적인데이터에접근해야하면사용한다. 특정인스턴스에묶이지않은변수를만들기위해클래스변수를사용한다. 클래스변수는모든객체가공유한다. 클래스메소드는특별히객체가없는상황에서동작하는행동을만들기위해사용한다. Sungjoo Ha 30 / 30