简体   繁体   English

有关将Java多态性应用于Calendar和GregoriaCalendar案例的一些疑问

[英]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 . 因此,一般规则是使用满足您需求的最高级别的接口

Example: Collections 示例:集合

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. 这样做不会破坏任何期望使用ListCollection代码,但是会破坏任何期望使用ArrayList调用代码。

List<String> list = new LinkedList<>();

Calendar & GregorianCalendar CalendarGregorianCalendar

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 . 实际上这意味着:您应该避免使用TemporalAccessorChronoLocalDate等类型,或者在旧世界中:避免使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM