Ch7. ObjectクラスとDate and Time API
Objectクラス
getClassメソッド
getClass()
メソッドに更に、getName()
メソッドを繋げることで、インスタンスのクラス名のみを取得することが出来る。
また、ArrayList等ではない普通の配列もオブジェクトとして扱われているので、getClass
でクラス名を取得できる。
int
等基本データ型には利用できない。
class TestClass{} public class Chapter7_2 { public static void main(String[] args) { int[] integerArray = {1,2,3,4,5,6,7}; String[] StringArray = {"Swinburne", "University", "of", "Techonology"}; System.out.println(integerArray.getClass()); //'class [I' System.out.println(StringArray.getClass()); //'class [Ljava.lang.String;' System.out.println(new TestClass().getClass());//'class TestClass' System.out.println(new TestClass().getClass().getName());//'TestClass' } }
equalsメソッド
Objectクラスの実装では、同じ参照先を示しているか(同じオブジェクトを指しているか)を示す同一判定である。
サブクラスでオーバーライドされ同値判定に利用されることが多い。例えばString
クラスでは同値判定が実装されているが、StringBuilder
では実装されていない。
なお、hashCodeが同じであること=同一ということではない。 下記の例では、通常のStringオブジェクトと明示的に初期化した(同一内容の)Stringオブジェクトを比較している。
この2つはhashCode()
が同じであるにもかかわらず、同値性の確認ではfalseとなっている。
(equals()
による比較はStringクラスがこのメソッドをオーバーライドしているため、true
になっている。)
hashCode
自体は直接同一性チェックに利用されるものではなく、HashMap
等で利用されるものらしい。
class TestClass{} public class Chapter7_2 { public static void main(String[] args) { String name = "All Nippon Airline"; String name2 = "All Nippon Airline"; String name3 = new String("All Nippon Airline"); System.out.println("hashcode : " + name.hashCode() + "\nhashcode2: " + name2.hashCode() + "\nhashcode3: " + name3.hashCode()); //hashcode : 1111687863 //hashcode2: 1111687863 //hashcode3: 1111687863 System.out.println("name and name2 == ?: " + (name == name2)); //name and name2 == ?: true System.out.println("name and name3 == ?: " + (name == name3)); //name and name3 == ?: false System.out.println("name and name2 equals?: " + name.equals(name2)); //name and name2 equals?: true } }
JavaにおけるequalsとhashCodeを理解する - Qiita
StringBuilder
クラスのequlas
はオーバーライドされていない。よって同値判定自体が出来ない。
同値判定を行うにはtoString()
メソッドを使ってString型の文字列を取得するしかない。
StringBuilder name4 = new StringBuilder("Aso Taro"); StringBuilder name5 = new StringBuilder("Aso Taro"); System.out.println("name4 and name5 equals?: " + name4.equals(name5)); System.out.println("name4 and name5 equals(toString)?: " + name4.toString().equals(name5.toString())); //name4 and name5 equals?: false //name4 and name5 equals(toString)?: true
Integerクラスでもequals()
メソッドのオーバーライドは行われている。
なお、Integerも-128から127までの間の数のオブジェクトに関しては使いまわしが発生するので、(同値・同一判定を確認するには)明示的に初期化する必要がある。
Integer number0 = 100; Integer number1 = 100; Integer number2 = new Integer(100); System.out.println("number0 and number1 is same(==)?: " + (number0 == number1)); System.out.println("number0 and number2 is same(==)?: " + (number0 == number2)); //number0 and number1 is same(==)?: true //number0 and number2 is same(==)?: false
ラッパークラスとプリミティブ型の比較においても、数値オブジェクトの使いまわしによる同一判定が成立してしまう点に注意する。
int number0Primitive = 100; System.out.println("Primitive and Wrapper Class is same(==)?: " + (number0 == number0Primitive)); //'true'
一方で、AutoBoxingを期待した異なるラッパークラス同士の同値判定はfalseになる。同値判定は必ず引数がNullでなく、同じ型のオブジェクトであることが求められる。
因みにAutoBoxing自体が実はintValue()
というメソッドを利用して成立している。
Chapter 5. Conversions and Contexts
Byte numberByte = 100; Short numberShort = 100; System.out.println("Byte and Number is equals?: " + (numberShort.equals(numberByte)));//'false'
toString()メソッド
このメソッドも下位クラスでオーバーライドされていることが多いがObjectクラス
では
クラス名 + @ + (オブジェクトの)ハッシュコード
が返却されるよう定義されている。
TestClass objectTest = new TestClass(); System.out.println(objectTest.toString());//'TestClass@15db9742' TestClass[] objectArray = {new TestClass(), new TestClass()}; System.out.println(objectArray.toString());//'[LTestClass;@6d06d69c'
2つ目の例では[L
が配列であることを示している。
なお既に述べたのように、toString
のHash値は決してユニークではない。同じ値であっても異なるObjectを指している場合がある。
配列関連のメソッド
arraycopy()メソッド
配列のコピーメソッドはArrayクラスなどではなく、Systemクラスのクラスメソッドとして提供されている。
RubyのようなDeepCopy
ではない点に注意。また、配列→ArrayListのような異なる型へのコピーは出来ない模様。
ArrayList<TestClass> arrayListObj = new ArrayList<>(10); TestClass[] objectArray2 = new TestClass[3]; System.arraycopy(objectArray, 0, objectArray2, 0, 2); System.out.println("element of copied Arrays is same(==)? :" + (objectArray[1] == objectArray2[1]));//'true' System.arraycopy(objectArray, 0, arrayListObj, 0, 2); //'Exception in thread "main" java.lang.ArrayStoreException at java.lang.System.arraycopy(Native Method) at Chapter7_2.main(Chapter7_2.java:70)'
Arrays.asList()メソッド
通常の配列をList
に変換して返却してくれる。
List
はインターフェースである。しかしasList()
で返却されるオブジェクトは配列クラスを参照したArrayList
のオブジェクトである。配列を参照しているだけなので、当然add
などは出来ない。
そのため、asList()
で返却されるオブジェクトは(add
などのArrayListのメソッドがCallできないように)List
型の変数に代入しないとエラーになるような仕組みとなっている。
List<Object> myList = Arrays.asList(objectArray2); //ArrayList<Object> myList2 = Arrays.asList(objectArray2); //'型の不一致: List<TestClass> から ArrayList<Object> には変換できません' //myList.add(new TestClass());//'Exception in thread "main" java.lang.UnsupportedOperationException' System.out.println(Arrays.asList(objectArray2).getClass().getName());//'java.util.Arrays$ArrayList'
また、asList()
の引数に指定される配列はオブジェクト型が要素になった配列である必要がある点にも注意する。
Listで指定するジェネリクスの型にはプリミティブ型は指定できない。また、asList()では配列の中身のAutoBoxingまでは対応していない。
ただし、asListの引数に直接プリミティブ型の数字を指定する場合は、AutoBoxingが効いて可能になる。
//List<Integer> myList2 = Arrays.asList(primitiveArray);//'型の不一致: List<int[]> から List<Integer> には変換できません' List<Integer> myList2 = Arrays.asList(10,2,30);//'OK'
Date andTime API
- LocalDate
- Localtime
- LocalDateTime
の3つのクラスが用意されている。
now
とof
メソッドは全てのクラスメソッドで利用できる。
import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; public class Ch7_3 { public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ LocalTime nowTime = LocalTime.now(); System.out.println(nowTime); //'12:50:54.356' LocalDate nowDate = LocalDate.now(); System.out.println(nowDate); //'2021-01-10' LocalDateTime nowDateTime = LocalDateTime.now(); System.out.println(nowDateTime);//'2021-01-10T12:53:20.088' System.out.println(LocalTime.of(14, 30, 58));//'14:30:58' System.out.println(LocalDate.of(1998, 02, 03));//'1998-02-03' System.out.println(LocalDateTime.of(1994, 8, 10, 14, 15, 20));//'1994-08-10T14:15:20' System.out.println(LocalDate.of(-100, 02, 03));//'-0100-02-03' System.out.println(LocalDate.of(1910, 13, 03));//'Exception in thread "main" java.time.DateTimeException: Invalid value for MonthOfYear (valid values 1 - 12): 13' } }
上記3つのクラスにはparse()
というクラスメソッドが文字列→DateTime(またはDate, Time)の変換を行ってくれる。
parseさせる文字列のフォーマットはデフォルトでは下記のような定数によって指定されている。
- ISO_DATE
- ISO_TIME
- ISO_DATETIME
public void parse() { System.out.println(LocalDate.parse("2019-12-13")); System.out.println(LocalTime.parse("10:43:12")); System.out.println(LocalDateTime.parse("2011-12-03T10:15:30")); //標準で採用されているフォーマッタではTZ情報は持てない System.out.println(LocalDateTime.parse( "2018-12-03T10:15:30+09:00[Asia/Tokyo]", DateTimeFormatter.ISO_ZONED_DATE_TIME)); DateTimeFormatter originalFormetter = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH時mm分"); System.out.println(LocalDateTime.parse( "2020年11月25日15時24分", originalFormetter)); }
更に、Date and Time APIでは、日時・時刻の計算を行うメソッドを用意している。 これらのメソッドは非破壊的なメソッドである。
System.out.println(LocalDate.parse("2019-12-13").plusWeeks(200)); System.out.println(LocalDateTime.parse( "2020年11月25日15時24分", originalFormetter).plusHours(5600));
Duration と Period Class
Durationでは時刻の差を、Periodでは日付の差を扱える。
Duration a1 = Duration.between(nowTime.plusHours(100), nowTime); System.out.println(a1.toDays() + ":" + a1.toHours() + ":" + a1.toMinutes()); Period a2 = Period.between(LocalDate.of(-100, 02, 03), LocalDate.of(1998, 02, 03)); System.out.println(a2);