[英]Some doubts about Java polymorphism applied to the Calendar and GregoriaCalendar case
I have the following doubt. 我有以下疑问。
Into my code I have: 在我的代码中,我有:
Calendar today = Calendar.getInstance();
where today variable is an instance of Calendar so I can't use methods as isLeapYear() on it. 今天的变量是Calendar的一个实例,因此我不能在它上使用isLeapYear()方法。
Doing in this way I can perform this method: 通过这种方式,我可以执行以下方法:
GregorianCalendar today = (GregorianCalendar) Calendar.getInstance();
int currentYear = today.get(Calendar.YEAR);
boolean bisestile = today.isLeapYear(currentYear);
My doubt is: exatly why? 我的疑问是:为什么? I am casting the same result instange returned by Calendar.getInstance() to be a GregorianCalendar .
我将由Calendar.getInstance()返回的相同结果强制转换为GregorianCalendar 。
Reading here: http://tutorials.jenkov.com/java-date-time/java-util-calendar.html 在这里阅读: http : //tutorials.jenkov.com/java-date-time/java-util-calendar.html
it seems to me to understand that The java.util.Calendar class is abstract so I cannot instantiate it so I think that the Calendar.getInstance() automatically return a GregorianCalendar object that have defined the previous isLeapYear() method. 在我看来, java.util.Calendar类是抽象的,所以我无法实例化它,因此我认为Calendar.getInstance()自动返回定义了以前的isLeapYear()方法的GregorianCalendar对象。
But I can't use it if the object is defined as a simple Calendar and not as a GregorianCalendar . 但是,如果将对象定义为简单Calendar而不是GregorianCalendar,我将无法使用它。
I know about polymorphism but how exactly works in this specific case? 我知道多态性,但是在这种特定情况下如何工作?
I think that putting the reference of a GregorianCalendar object (returned by Calendar.getInstance() , is it true?) into a Calendar (I can do it because Calendar is the super type) I can access only to the methods subset defined for this abstract class and not to all the methods defined for the concrete type. 我认为将GregorianCalendar对象的引用(由Calendar.getInstance()返回,是真的吗?)放入日历中 (我可以这样做,因为Calendar是超级类型),我只能访问为此定义的方法子集抽象类而不是为具体类型定义的所有方法。
Is it this reasoning correct or am I missing something? 这是正确的推理还是我错过了什么?
This is polymorphism . 这是多态性 。
Calendar
provides an abstract framework, and subclasses like GregorianCalendar provide implementations. Calendar
提供了一个抽象框架,而类似GregorianCalendar的子类提供了实现。 In other contexts, understand that Calendar.getInstance()
maybe could return (for instance) a Chinese or a Hebrew calendar depending on the locality and system setup. 在其他情况下,请理解
Calendar.getInstance()
可能会返回(例如)中文或希伯来语日历,具体取决于位置和系统设置。
If what you really want is a GregorianCalendar
explicitly, declare the variable as such. 如果您真正想要的是显式的
GregorianCalendar
,则声明该变量。
GregorianCalendar cal = new GregorianCalendar();
The Answer by ControlAltDel is correct. ControlAltDel的答案是正确的。
One of the benefits of Object-Oriented Programming is preventing fragile software that breaks after making some change. 面向对象编程的好处之一是可以防止脆弱的软件在进行某些更改后崩溃。 One of the ways to accomplish that is where we define an interface with one or more implementations.
实现此目标的方法之一是定义一个或多个实现的接口。 When other code refers to the interface, we can switch out the implementation without breaking the calling code.
当其他代码引用该接口时,我们可以在不破坏调用代码的情况下切换实现。
So the general rule is to use the highest level of interface that meets your needs . 因此,一般规则是使用满足您需求的最高级别的接口 。
For example in Java Collections , use the Collection
interface where it meets your needs. 例如,在Java Collections中 ,使用满足您需求的
Collection
接口。
Collection<String> col = new ArrayList<>() ;
Get more specific only if your code requires the additional methods offered by a more specific interface. 仅当您的代码需要更特定的接口提供的其他方法时,才更加具体。 Here we use
List
, a sub-interface of Collection
that promises additional methods. 在这里,我们使用
List
,它是Collection
的子接口,承诺其他方法。
List<String> list = new ArrayList<>() ;
Use the ArrayList
as an ArrayList
only if absolutely necessary, only if that class offers certain methods you require that are not included in its more general interfaces. 仅当绝对必要时,才使用
ArrayList
作为ArrayList
,仅当该类提供您需要的某些方法(未包含在其更通用的接口中)时才使用。
ArrayList<String> list = new ArrayList<>() ;
Later we may decide to replace that ArrayList
with a LinkedList
. 稍后,我们可能决定用
LinkedList
替换该ArrayList
。 Doing so won't break any code that was expecting a List
or Collection
but would break any calling code that expected an ArrayList
specifically. 这样做不会破坏任何期望使用
List
或Collection
代码,但是会破坏任何期望使用ArrayList
调用代码。
List<String> list = new LinkedList<>();
Calendar
& GregorianCalendar
Calendar
和GregorianCalendar
Similarly, you should use Calendar
wherever possible, rather than GregorianCalendar
. 同样,应尽可能使用
Calendar
而不是GregorianCalendar
。
Calendar cal = new GregorianCalendar() ;
But if the code absolutely needs the special features of GregorianCalendar
then track the object as a GregorianCalendar
as shown in the Answer by ControlAltDel . 但是,如果代码是绝对有需要的特殊功能
GregorianCalendar
然后跟踪的对象作为GregorianCalendar
如图所示的ControlAltDel答案 。
GregorianCalendar cal = new GregorianCalendar() ;
You can mix this up, using a more-specific type internally and a more-general type externally. 您可以混合使用内部更具体的类型和外部更一般的类型。 If you only need those special
GregorianCalendar
features inside your own class, but want to expose the calendar to other classes, you can declare the calendar object as a GregorianCalendar
as the private member of your class while returning Calendar
from a getter method. 如果您只需要在自己的类中使用那些特殊的
GregorianCalendar
功能,但想将日历公开给其他类,则可以在从getter方法返回Calendar
同时,将Calendar
对象声明为GregorianCalendar
作为类的私有成员。
…
private GregorianCalendar gregCal = new GregorianCalendar() ;
…
public Calendar getCalendar() {
return this.gregCal ; // Automatically upcast. Appears to any calling code to be a `Calendar`.
}
PS The java.util.Calendar
& .GregorianCalendar
are part of the troublesome old legacy date-time classes now supplanted by the java.time classes built into Java 8 and later. PS
java.util.Calendar
和.GregorianCalendar
是麻烦的旧旧日期时间类的一部分,现在已由Java 8及更高版本中内置的java.time类取代。 Avoid these old classes. 避免使用这些旧的类。
If you are in Thailand then your code 如果您在泰国,则您的代码
GregorianCalendar today = (GregorianCalendar) Calendar.getInstance();
will probably fail by throwing a ClassCastException
because Calendar.getInstance()
can yield the Thai-Buddhist calendar as default in that country. 可能会因为抛出
ClassCastException
而失败,因为Calendar.getInstance()
可以将泰国佛教日历生成为该国家/地区的默认日历。 This use-case indicates a strong warning to use Calendar.getInstance()
if you are really sitting in Thailand. 如果您真的坐在泰国,此用例表明强烈建议您使用
Calendar.getInstance()
。 And then you cannot make your gregorian-based assumptions when you are going to interprete expressions like calendar.get(Calendar.YEAR)
(maybe yielding year values like 2543). 然后,当您要解释诸如
calendar.get(Calendar.YEAR)
类的表达式时(可能会产生类似2543的年份calendar.get(Calendar.YEAR)
您将无法做出基于calendar.get(Calendar.YEAR)
高利的假设。
Conclusion: When handling date and time, it is much better NOT to use generic interfaces but to be as concrete as possible. 结论:处理日期和时间时,最好不要使用通用接口,而要尽可能具体。 I assume you are only interested into the gregorian calendar, so please use:
我假设您只对公历感兴趣,所以请使用:
GregorianCalendar today = new GregorianCalendar();
By the way, the main designers of new java.time-package in Java-8 have also adopted this view to be as concrete as possible : 顺便说一下,Java-8中新的java.time-package的主要设计者也采用了这种观点,使其尽可能具体 :
Most applications should declare method signatures, fields and variables as LocalDate, not this interface.
大多数应用程序应将方法签名,字段和变量声明为LocalDate,而不是此接口。
Practically this means: You should avoid types like TemporalAccessor
, ChronoLocalDate
etc., or in old world: Avoid types like java.util.Calendar
in favor of concrete types like GregorianCalendar
. 实际上这意味着:您应该避免使用
TemporalAccessor
, ChronoLocalDate
等类型,或者在旧世界中:避免使用java.util.Calendar
之类的类型,而应使用GregorianCalendar
类的具体类型。 Polymorphism is not a very good idea in the world of date and time. 在日期和时间的世界中,多态并不是一个好主意。 The concrete types are too different (sometimes in a very subtile way).
具体类型太不同了(有时以非常微妙的方式)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.