001 /* 002 * Copyright 2001-2005 Stephen Colebourne 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.joda.time; 017 018 import java.util.Locale; 019 020 /** 021 * Defines the calculation engine for date and time fields. 022 * The interface defines a set of methods that manipulate a millisecond datetime 023 * with regards to a single field, such as monthOfYear or secondOfMinute. 024 * <p> 025 * This design is extensible so, if you wish, you can extract a different field from 026 * the milliseconds. A number of standard implementations are provided to assist. 027 * 028 * @author Guy Allard 029 * @author Stephen Colebourne 030 * @author Brian S O'Neill 031 * @since 1.0 032 */ 033 public abstract class DateTimeField { 034 035 /** 036 * Get the type of the field. 037 * 038 * @return field type 039 */ 040 public abstract DateTimeFieldType getType(); 041 042 /** 043 * Get the name of the field. 044 * <p> 045 * By convention, names follow a pattern of "dddOfRrr", where "ddd" represents 046 * the (singular) duration unit field name and "Rrr" represents the (singular) 047 * duration range field name. If the range field is not applicable, then 048 * the name of the field is simply the (singular) duration field name. 049 * 050 * @return field name 051 */ 052 public abstract String getName(); 053 054 /** 055 * Returns true if this field is supported. 056 * 057 * @return true if this field is supported 058 */ 059 public abstract boolean isSupported(); 060 061 /** 062 * Returns true if the set method is lenient. If so, it accepts values that 063 * are out of bounds. For example, a lenient day of month field accepts 32 064 * for January, converting it to February 1. 065 * 066 * @return true if this field is lenient 067 */ 068 public abstract boolean isLenient(); 069 070 // Main access API 071 //------------------------------------------------------------------------ 072 /** 073 * Get the value of this field from the milliseconds. 074 * 075 * @param instant the milliseconds from 1970-01-01T00:00:00Z to query 076 * @return the value of the field, in the units of the field 077 */ 078 public abstract int get(long instant); 079 080 /** 081 * Get the human-readable, text value of this field from the milliseconds. 082 * If the specified locale is null, the default locale is used. 083 * 084 * @param instant the milliseconds from 1970-01-01T00:00:00Z to query 085 * @param locale the locale to use for selecting a text symbol, null for default 086 * @return the text value of the field 087 */ 088 public abstract String getAsText(long instant, Locale locale); 089 090 /** 091 * Get the human-readable, text value of this field from the milliseconds. 092 * 093 * @param instant the milliseconds from 1970-01-01T00:00:00Z to query 094 * @return the text value of the field 095 */ 096 public abstract String getAsText(long instant); 097 098 /** 099 * Get the human-readable, text value of this field from a partial instant. 100 * If the specified locale is null, the default locale is used. 101 * 102 * @param partial the partial instant to query 103 * @param fieldValue the field value of this field, provided for performance 104 * @param locale the locale to use for selecting a text symbol, null for default 105 * @return the text value of the field 106 */ 107 public abstract String getAsText(ReadablePartial partial, int fieldValue, Locale locale); 108 109 /** 110 * Get the human-readable, text value of this field from a partial instant. 111 * If the specified locale is null, the default locale is used. 112 * 113 * @param partial the partial instant to query 114 * @param locale the locale to use for selecting a text symbol, null for default 115 * @return the text value of the field 116 */ 117 public abstract String getAsText(ReadablePartial partial, Locale locale); 118 119 /** 120 * Get the human-readable, text value of this field from the field value. 121 * If the specified locale is null, the default locale is used. 122 * 123 * @param fieldValue the numeric value to convert to text 124 * @param locale the locale to use for selecting a text symbol, null for default 125 * @return the text value of the field 126 */ 127 public abstract String getAsText(int fieldValue, Locale locale); 128 129 /** 130 * Get the human-readable, short text value of this field from the 131 * milliseconds. If the specified locale is null, the default locale is used. 132 * 133 * @param instant the milliseconds from 1970-01-01T00:00:00Z to query 134 * @param locale the locale to use for selecting a text symbol, null for default 135 * @return the short text value of the field 136 */ 137 public abstract String getAsShortText(long instant, Locale locale); 138 139 /** 140 * Get the human-readable, short text value of this field from the 141 * milliseconds. 142 * 143 * @param instant the milliseconds from 1970-01-01T00:00:00Z to query 144 * @return the short text value of the field 145 */ 146 public abstract String getAsShortText(long instant); 147 148 /** 149 * Get the human-readable, short text value of this field from a partial instant. 150 * If the specified locale is null, the default locale is used. 151 * 152 * @param partial the partial instant to query 153 * @param fieldValue the field value of this field, provided for performance 154 * @param locale the locale to use for selecting a text symbol, null for default 155 * @return the text value of the field 156 */ 157 public abstract String getAsShortText(ReadablePartial partial, int fieldValue, Locale locale); 158 159 /** 160 * Get the human-readable, short text value of this field from a partial instant. 161 * If the specified locale is null, the default locale is used. 162 * 163 * @param partial the partial instant to query 164 * @param locale the locale to use for selecting a text symbol, null for default 165 * @return the text value of the field 166 */ 167 public abstract String getAsShortText(ReadablePartial partial, Locale locale); 168 169 /** 170 * Get the human-readable, short text value of this field from the field value. 171 * If the specified locale is null, the default locale is used. 172 * 173 * @param fieldValue the numeric value to convert to text 174 * @param locale the locale to use for selecting a text symbol, null for default 175 * @return the text value of the field 176 */ 177 public abstract String getAsShortText(int fieldValue, Locale locale); 178 179 /** 180 * Adds a value (which may be negative) to the millis value, 181 * overflowing into larger fields if necessary. 182 * <p> 183 * The value will be added to this field. If the value is too large to be 184 * added solely to this field, larger fields will increase as required. 185 * Smaller fields should be unaffected, except where the result would be 186 * an invalid value for a smaller field. In this case the smaller field is 187 * adjusted to be in range. 188 * <p> 189 * For example, in the ISO chronology:<br> 190 * 2000-08-20 add six months is 2001-02-20<br> 191 * 2000-08-20 add twenty months is 2002-04-20<br> 192 * 2000-08-20 add minus nine months is 1999-11-20<br> 193 * 2001-01-31 add one month is 2001-02-28<br> 194 * 2001-01-31 add two months is 2001-03-31<br> 195 * 196 * @param instant the milliseconds from 1970-01-01T00:00:00Z to add to 197 * @param value the value to add, in the units of the field 198 * @return the updated milliseconds 199 */ 200 public abstract long add(long instant, int value); 201 202 /** 203 * Adds a value (which may be negative) to the millis value, 204 * overflowing into larger fields if necessary. 205 * 206 * @param instant the milliseconds from 1970-01-01T00:00:00Z to add to 207 * @param value the long value to add, in the units of the field 208 * @return the updated milliseconds 209 * @throws IllegalArgumentException if value is too large 210 * @see #add(long,int) 211 */ 212 public abstract long add(long instant, long value); 213 214 /** 215 * Adds a value (which may be negative) to the partial instant, 216 * throwing an exception if the maximum size of the instant is reached. 217 * <p> 218 * The value will be added to this field, overflowing into larger fields 219 * if necessary. Smaller fields should be unaffected, except where the 220 * result would be an invalid value for a smaller field. In this case the 221 * smaller field is adjusted to be in range. 222 * <p> 223 * Partial instants only contain some fields. This may result in a maximum 224 * possible value, such as TimeOfDay being limited to 23:59:59:999. If this 225 * limit is breached by the add an exception is thrown. 226 * <p> 227 * For example, in the ISO chronology:<br> 228 * 2000-08-20 add six months is 2000-02-20<br> 229 * 2000-08-20 add twenty months is 2000-04-20<br> 230 * 2000-08-20 add minus nine months is 2000-11-20<br> 231 * 2001-01-31 add one month is 2001-02-28<br> 232 * 2001-01-31 add two months is 2001-03-31<br> 233 * 234 * @param instant the partial instant 235 * @param fieldIndex the index of this field in the instant 236 * @param values the values of the partial instant which should be updated 237 * @param valueToAdd the value to add, in the units of the field 238 * @return the passed in values 239 * @throws IllegalArgumentException if the value is invalid or the maximum instant is reached 240 */ 241 public abstract int[] add(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd); 242 243 /** 244 * Adds a value (which may be negative) to the partial instant, 245 * wrapping the whole partial if the maximum size of the partial is reached. 246 * <p> 247 * The value will be added to this field, overflowing into larger fields 248 * if necessary. Smaller fields should be unaffected, except where the 249 * result would be an invalid value for a smaller field. In this case the 250 * smaller field is adjusted to be in range. 251 * <p> 252 * Partial instants only contain some fields. This may result in a maximum 253 * possible value, such as TimeOfDay normally being limited to 23:59:59:999. 254 * If ths limit is reached by the addition, this method will wrap back to 255 * 00:00:00.000. In fact, you would generally only use this method for 256 * classes that have a limitation such as this. 257 * <p> 258 * For example, in the ISO chronology:<br> 259 * 10:20:30 add 20 minutes is 10:40:30<br> 260 * 10:20:30 add 45 minutes is 11:05:30<br> 261 * 10:20:30 add 16 hours is 02:20:30<br> 262 * 263 * @param instant the partial instant 264 * @param fieldIndex the index of this field in the partial 265 * @param values the values of the partial instant which should be updated 266 * @param valueToAdd the value to add, in the units of the field 267 * @return the passed in values 268 * @throws IllegalArgumentException if the value is invalid or the maximum instant is reached 269 */ 270 public abstract int[] addWrapPartial(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd); 271 272 /** 273 * Adds a value (which may be negative) to the millis value, 274 * wrapping within this field. 275 * <p> 276 * The value will be added to this field. If the value is too large to be 277 * added solely to this field then it wraps. Larger fields are always 278 * unaffected. Smaller fields should be unaffected, except where the 279 * result would be an invalid value for a smaller field. In this case the 280 * smaller field is adjusted to be in range. 281 * <p> 282 * For example, in the ISO chronology:<br> 283 * 2000-08-20 addWrapField six months is 2000-02-20<br> 284 * 2000-08-20 addWrapField twenty months is 2000-04-20<br> 285 * 2000-08-20 addWrapField minus nine months is 2000-11-20<br> 286 * 2001-01-31 addWrapField one month is 2001-02-28<br> 287 * 2001-01-31 addWrapField two months is 2001-03-31<br> 288 * 289 * @param instant the milliseconds from 1970-01-01T00:00:00Z to add to 290 * @param value the value to add, in the units of the field 291 * @return the updated milliseconds 292 */ 293 public abstract long addWrapField(long instant, int value) ; 294 295 /** 296 * Adds a value (which may be negative) to the partial instant, 297 * wrapping within this field. 298 * <p> 299 * The value will be added to this field. If the value is too large to be 300 * added solely to this field then it wraps. Larger fields are always 301 * unaffected. Smaller fields should be unaffected, except where the 302 * result would be an invalid value for a smaller field. In this case the 303 * smaller field is adjusted to be in range. 304 * <p> 305 * For example, in the ISO chronology:<br> 306 * 2000-08-20 addWrapField six months is 2000-02-20<br> 307 * 2000-08-20 addWrapField twenty months is 2000-04-20<br> 308 * 2000-08-20 addWrapField minus nine months is 2000-11-20<br> 309 * 2001-01-31 addWrapField one month is 2001-02-28<br> 310 * 2001-01-31 addWrapField two months is 2001-03-31<br> 311 * 312 * @param instant the partial instant 313 * @param fieldIndex the index of this field in the instant 314 * @param values the values of the partial instant which should be updated 315 * @param valueToAdd the value to add, in the units of the field 316 * @return the passed in values 317 * @throws IllegalArgumentException if the value is invalid 318 */ 319 public abstract int[] addWrapField(ReadablePartial instant, int fieldIndex, int[] values, int valueToAdd); 320 321 /** 322 * Computes the difference between two instants, as measured in the units 323 * of this field. Any fractional units are dropped from the result. Calling 324 * getDifference reverses the effect of calling add. In the following code: 325 * 326 * <pre> 327 * long instant = ... 328 * int v = ... 329 * int age = getDifference(add(instant, v), instant); 330 * </pre> 331 * 332 * The value 'age' is the same as the value 'v'. 333 * 334 * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to 335 * subtract from 336 * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to 337 * subtract off the minuend 338 * @return the difference in the units of this field 339 */ 340 public abstract int getDifference(long minuendInstant, long subtrahendInstant); 341 342 /** 343 * Computes the difference between two instants, as measured in the units 344 * of this field. Any fractional units are dropped from the result. Calling 345 * getDifference reverses the effect of calling add. In the following code: 346 * 347 * <pre> 348 * long instant = ... 349 * long v = ... 350 * long age = getDifferenceAsLong(add(instant, v), instant); 351 * </pre> 352 * 353 * The value 'age' is the same as the value 'v'. 354 * 355 * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to 356 * subtract from 357 * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to 358 * subtract off the minuend 359 * @return the difference in the units of this field 360 */ 361 public abstract long getDifferenceAsLong(long minuendInstant, long subtrahendInstant); 362 363 /** 364 * Sets a value in the milliseconds supplied. 365 * <p> 366 * The value of this field will be set. 367 * If the value is invalid, an exception if thrown. 368 * <p> 369 * If setting this field would make other fields invalid, then those fields 370 * may be changed. For example if the current date is the 31st January, and 371 * the month is set to February, the day would be invalid. Instead, the day 372 * would be changed to the closest value - the 28th/29th February as appropriate. 373 * 374 * @param instant the milliseconds from 1970-01-01T00:00:00Z to set in 375 * @param value the value to set, in the units of the field 376 * @return the updated milliseconds 377 * @throws IllegalArgumentException if the value is invalid 378 */ 379 public abstract long set(long instant, int value); 380 381 /** 382 * Sets a value using the specified partial instant. 383 * <p> 384 * The value of this field (specified by the index) will be set. 385 * If the value is invalid, an exception if thrown. 386 * <p> 387 * If setting this field would make other fields invalid, then those fields 388 * may be changed. For example if the current date is the 31st January, and 389 * the month is set to February, the day would be invalid. Instead, the day 390 * would be changed to the closest value - the 28th/29th February as appropriate. 391 * 392 * @param instant the partial instant 393 * @param fieldIndex the index of this field in the instant 394 * @param values the values of the partial instant which should be updated 395 * @param newValue the value to set, in the units of the field 396 * @return the passed in values 397 * @throws IllegalArgumentException if the value is invalid 398 */ 399 public abstract int[] set(ReadablePartial instant, int fieldIndex, int[] values, int newValue); 400 401 /** 402 * Sets a value in the milliseconds supplied from a human-readable, text value. 403 * If the specified locale is null, the default locale is used. 404 * <p> 405 * If setting this field would make other fields invalid, then those fields 406 * may be changed. For example if the current date is the 31st January, and 407 * the month is set to February, the day would be invalid. Instead, the day 408 * would be changed to the closest value - the 28th/29th February as appropriate. 409 * 410 * @param instant the milliseconds from 1970-01-01T00:00:00Z to set in 411 * @param text the text value to set 412 * @param locale the locale to use for selecting a text symbol, null for default 413 * @return the updated milliseconds 414 * @throws IllegalArgumentException if the text value is invalid 415 */ 416 public abstract long set(long instant, String text, Locale locale); 417 418 /** 419 * Sets a value in the milliseconds supplied from a human-readable, text value. 420 * <p> 421 * If setting this field would make other fields invalid, then those fields 422 * may be changed. For example if the current date is the 31st January, and 423 * the month is set to February, the day would be invalid. Instead, the day 424 * would be changed to the closest value - the 28th/29th February as appropriate. 425 * 426 * @param instant the milliseconds from 1970-01-01T00:00:00Z to set in 427 * @param text the text value to set 428 * @return the updated milliseconds 429 * @throws IllegalArgumentException if the text value is invalid 430 */ 431 public abstract long set(long instant, String text); 432 433 /** 434 * Sets a value in the milliseconds supplied from a human-readable, text value. 435 * If the specified locale is null, the default locale is used. 436 * <p> 437 * If setting this field would make other fields invalid, then those fields 438 * may be changed. For example if the current date is the 31st January, and 439 * the month is set to February, the day would be invalid. Instead, the day 440 * would be changed to the closest value - the 28th/29th February as appropriate. 441 * 442 * @param instant the partial instant 443 * @param fieldIndex the index of this field in the instant 444 * @param values the values of the partial instant which should be updated 445 * @param text the text value to set 446 * @param locale the locale to use for selecting a text symbol, null for default 447 * @return the passed in values 448 * @throws IllegalArgumentException if the text value is invalid 449 */ 450 public abstract int[] set(ReadablePartial instant, int fieldIndex, int[] values, String text, Locale locale); 451 452 // Extra information API 453 //------------------------------------------------------------------------ 454 /** 455 * Returns the duration per unit value of this field. For example, if this 456 * field represents "hour of day", then the duration is an hour. 457 * 458 * @return the duration of this field, or UnsupportedDurationField if field 459 * has no duration 460 */ 461 public abstract DurationField getDurationField(); 462 463 /** 464 * Returns the range duration of this field. For example, if this field 465 * represents "hour of day", then the range duration is a day. 466 * 467 * @return the range duration of this field, or null if field has no range 468 */ 469 public abstract DurationField getRangeDurationField(); 470 471 /** 472 * Returns whether this field is 'leap' for the specified instant. 473 * <p> 474 * For example, a leap year would return true, a non leap year would return 475 * false. 476 * 477 * @param instant the instant to check for leap status 478 * @return true if the field is 'leap' 479 */ 480 public abstract boolean isLeap(long instant); 481 482 /** 483 * Gets the amount by which this field is 'leap' for the specified instant. 484 * <p> 485 * For example, a leap year would return one, a non leap year would return 486 * zero. 487 * 488 * @param instant the instant to check for leap status 489 * @return the amount, in units of the leap duration field, that the field is leap 490 */ 491 public abstract int getLeapAmount(long instant); 492 493 /** 494 * If this field were to leap, then it would be in units described by the 495 * returned duration. If this field doesn't ever leap, null is returned. 496 * 497 * @return the leap duration field if field can be leap, null if it can't 498 */ 499 public abstract DurationField getLeapDurationField(); 500 501 /** 502 * Get the minimum allowable value for this field. 503 * 504 * @return the minimum valid value for this field, in the units of the 505 * field 506 */ 507 public abstract int getMinimumValue(); 508 509 /** 510 * Get the minimum value for this field evaluated at the specified time. 511 * 512 * @param instant the milliseconds from 1970-01-01T00:00:00Z to query 513 * @return the minimum value for this field, in the units of the field 514 */ 515 public abstract int getMinimumValue(long instant); 516 517 /** 518 * Get the minimum value for this field evaluated at the specified time. 519 * 520 * @param instant the partial instant to query 521 * @return the minimum value for this field, in the units of the field 522 */ 523 public abstract int getMinimumValue(ReadablePartial instant); 524 525 /** 526 * Get the minimum value for this field using the partial instant and 527 * the specified values. 528 * 529 * @param instant the partial instant to query 530 * @param values the values to use 531 * @return the minimum value for this field, in the units of the field 532 */ 533 public abstract int getMinimumValue(ReadablePartial instant, int[] values); 534 535 /** 536 * Get the maximum allowable value for this field. 537 * 538 * @return the maximum valid value for this field, in the units of the 539 * field 540 */ 541 public abstract int getMaximumValue(); 542 543 /** 544 * Get the maximum value for this field evaluated at the specified time. 545 * 546 * @param instant the milliseconds from 1970-01-01T00:00:00Z to query 547 * @return the maximum value for this field, in the units of the field 548 */ 549 public abstract int getMaximumValue(long instant); 550 551 /** 552 * Get the maximum value for this field evaluated at the specified time. 553 * 554 * @param instant the partial instant to query 555 * @return the maximum value for this field, in the units of the field 556 */ 557 public abstract int getMaximumValue(ReadablePartial instant); 558 559 /** 560 * Get the maximum value for this field using the partial instant and 561 * the specified values. 562 * 563 * @param instant the partial instant to query 564 * @param values the values to use 565 * @return the maximum value for this field, in the units of the field 566 */ 567 public abstract int getMaximumValue(ReadablePartial instant, int[] values); 568 569 /** 570 * Get the maximum text value for this field. 571 * 572 * @param locale the locale to use for selecting a text symbol 573 * @return the maximum text length 574 */ 575 public abstract int getMaximumTextLength(Locale locale); 576 577 /** 578 * Get the maximum short text value for this field. 579 * 580 * @param locale the locale to use for selecting a text symbol 581 * @return the maximum short text length 582 */ 583 public abstract int getMaximumShortTextLength(Locale locale); 584 585 // Calculation API 586 //------------------------------------------------------------------------ 587 /** 588 * Round to the lowest whole unit of this field. After rounding, the value 589 * of this field and all fields of a higher magnitude are retained. The 590 * fractional millis that cannot be expressed in whole increments of this 591 * field are set to minimum. 592 * <p> 593 * For example, a datetime of 2002-11-02T23:34:56.789, rounded to the 594 * lowest whole hour is 2002-11-02T23:00:00.000. 595 * 596 * @param instant the milliseconds from 1970-01-01T00:00:00Z to round 597 * @return rounded milliseconds 598 */ 599 public abstract long roundFloor(long instant); 600 601 /** 602 * Round to the highest whole unit of this field. The value of this field 603 * and all fields of a higher magnitude may be incremented in order to 604 * achieve this result. The fractional millis that cannot be expressed in 605 * whole increments of this field are set to minimum. 606 * <p> 607 * For example, a datetime of 2002-11-02T23:34:56.789, rounded to the 608 * highest whole hour is 2002-11-03T00:00:00.000. 609 * 610 * @param instant the milliseconds from 1970-01-01T00:00:00Z to round 611 * @return rounded milliseconds 612 */ 613 public abstract long roundCeiling(long instant); 614 615 /** 616 * Round to the nearest whole unit of this field. If the given millisecond 617 * value is closer to the floor or is exactly halfway, this function 618 * behaves like roundFloor. If the millisecond value is closer to the 619 * ceiling, this function behaves like roundCeiling. 620 * 621 * @param instant the milliseconds from 1970-01-01T00:00:00Z to round 622 * @return rounded milliseconds 623 */ 624 public abstract long roundHalfFloor(long instant); 625 626 /** 627 * Round to the nearest whole unit of this field. If the given millisecond 628 * value is closer to the floor, this function behaves like roundFloor. If 629 * the millisecond value is closer to the ceiling or is exactly halfway, 630 * this function behaves like roundCeiling. 631 * 632 * @param instant the milliseconds from 1970-01-01T00:00:00Z to round 633 * @return rounded milliseconds 634 */ 635 public abstract long roundHalfCeiling(long instant); 636 637 /** 638 * Round to the nearest whole unit of this field. If the given millisecond 639 * value is closer to the floor, this function behaves like roundFloor. If 640 * the millisecond value is closer to the ceiling, this function behaves 641 * like roundCeiling. 642 * <p> 643 * If the millisecond value is exactly halfway between the floor and 644 * ceiling, the ceiling is chosen over the floor only if it makes this 645 * field's value even. 646 * 647 * @param instant the milliseconds from 1970-01-01T00:00:00Z to round 648 * @return rounded milliseconds 649 */ 650 public abstract long roundHalfEven(long instant); 651 652 /** 653 * Returns the fractional duration milliseconds of this field. In other 654 * words, calling remainder returns the duration that roundFloor would 655 * subtract. 656 * <p> 657 * For example, on a datetime of 2002-11-02T23:34:56.789, the remainder by 658 * hour is 34 minutes and 56.789 seconds. 659 * 660 * @param instant the milliseconds from 1970-01-01T00:00:00Z to get the 661 * remainder 662 * @return remainder duration, in milliseconds 663 */ 664 public abstract long remainder(long instant); 665 666 /** 667 * Get a suitable debug string. 668 * 669 * @return debug string 670 */ 671 public abstract String toString(); 672 673 }