質問

Answering this question: How to GUI - Using paintcomponent() to initialize a GUI and then to add GUI based on mouse I've stated this:

You don't override paintComponent() properly. This is a protected method, not public. If you add @Override annotation on this method then the compiler will complain.

But @peeskillet wisely pointed out this:

The compiler will not complain about public or protected with paintComponent. You can override with a higher visibility but not a lower one. public is higher than protected so there's no problem.

Which is certainly true. But now it arises this question: Is it good practice override with a higher visibility?

Addendum

Link to JComponent.paintComponent() javadoc.

Image of Netbeans not complaining at all:

enter image description here

役に立ちましたか?

解決

One reason to do this is if you have a method you need to override elsewhere in your project and the current scope does not allow you to. Typically when using default instead of protected.

By creating a new sub class in the right package elsewhere in your project with revised scope, you can then create an anonymous class in your code where you need it as you are now allowed to override the troublesome method instead of having to do with reflection (which makes for quite unreadable code).

This is also a reason for library classes never to be final because then you cannot do things like this.


EDIT: I was asked to elaborate on why this is relevant for Dependency Injection. I can only speak based on my own experiences, first with Guice and now with Dagger.

Dagger uses Constructor Injection which basically mean that a class will get all its dependencies provided as arguments to the constructor (and only there) and that the glue code binding this together is listed in a Dagger @Module. In this module it is usually very convenient to return a subclass of a library class augmenting with log statements or providing a custom toString() method. In order to actually DO this without reflection tricks the clasess cannot be final and you need to be able to override methods and to use fields in the superclass directly. Hence no final classes and both types need to be at least protected instead of private!

(and I can strongly recommend using Dagger because it moves the dependency resolving in the java compiler giving the IDE the information needed to help you resolve problems at compile time, instead of depending on magic in the runtime in the wild. I am still amazed at the insight in the Java ecosystem the Dagger designers had to even get this idea and then realize it)

他のヒント

From Java Tutorial, Controlling Access to Members of a Class:

If other programmers use your class, you want to ensure that errors from misuse cannot happen. Access levels can help you do this.

  • Use the most restrictive access level that makes sense for a particular member. Use private unless you have a good reason not to.
  • Avoid public fields except for constants. (Many of the examples in the tutorial use public fields. This may help to illustrate some
    points concisely, but is not recommended for production code.) Public fields tend to link you to a particular implementation and limit your flexibility in changing your code.

This advice is aimed to reduce coupling:

To achieve the best encapsulation (information hiding) you should always declare methods with the least visibility that works. In small programs there's really no problem, but in large programs this problem of excessive coupling is very serious. Coupling occurs when one part depends on the specific implementation of another. The more coupling there is the more costly it becomes to make changes because too much code depends on specific implementations. This causes software rot - a program becomes progressively less usable because it can't be easily upgraded.

So, increasing visibility is actually not a good idea. Such code could couse trouble in future development and maintenance.

If you NEED to access the method from outside the class/subclass it resides in, then a solution is to override the visibility with the public parameter. Best practice is to have your variables and methods on the lowest visibility possible.

You can advance a method's visibility to become more visible but not less visible, and so paintComponent can be overridden and declared as a public method. Having said that, I'll add that you shouldn't do this. When overriding the method, you should instead keep the visibility unchanged unless you have a very good reason to make it more visible.

From the OOP point of view there is no problem with it. By extending a class you can do the following things:

  • change some of the functionality (by overriding a method)
  • extend the class' interface (by adding a new public method)

When you override a method and change its visibility you are doing both: You - obviously - change the functionality but also extend the interface. From the class' client's perspective you are actually creating a new method in the class' interface. This new method coincidentally has the same name as some internal method in the superclass, but the client doesn't care (or doesn't even know about this). So why should you not?

On the other hand there is the question "why do you need to do this?". The superclass' author probably had some thoughts about the visibility of this method and found that its functionality is not meant for the outside world. I don't mean that it's wrong to do so but you have to question your motives to increase the visibility, because it might be a hint for probably bad design in either your or the superclass' code.

Btw: As pointed out here disallowing this language feature can even be harmful.

Overridden methods, just like all other methods, should only be declared public if you want external code to be able to call them (unless you have no choice because the overridden method is declared public). In your case the overridden method paintComponent should only be called by Swing, thus keeping it protected is the best option.

To add to what Francois was saying, the OOP principle at play here is the "Open Close Principle," which says you should be able to extend, but not modify an object. 'Raising' the visibility of a method by overriding it is simply extension as Francois pointed out.

There are many arguments to be made for changing the visibility. But just think about the fact that you would be changing the interface (in the sense of API) of that class. Read up on evolving APIs and associate that information to your question.

So in my book good practise would be to not change the visibility - if at all possible. Otherwise you have to carefully consider the consequences - if only in the long run.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top