私はこのコードでそれを理解しています:
_class Foo {
public static void method() {
System.out.println("in Foo");
}
}
class Bar extends Foo {
public static void method() {
System.out.println("in Bar");
}
}
_
.. Bar
の静的メソッドは、ポリモーフィズムの意味でオーバーライドするのではなく、Foo
で宣言された静的メソッドを「非表示」にします。
_class Test {
public static void main(String[] args) {
Foo.method();
Bar.method();
}
}
_
...出力されます:
フーに
バーで
final
をFoo
としてmethod()
として再定義すると、Bar
がそれを非表示にする機能が無効になり、main()
を再実行します出力されます:
フーに
フー
(Edit:メソッドをfinal
としてマークするとコンパイルが失敗し、削除したときにのみ再度実行されますBar.method()
)
静的メソッドをfinal
として宣言することは、サブクラスが意図的または誤ってメソッドを再定義することを停止する場合、悪い習慣と見なされますか?
( this は、final
を使用した場合の動作をよく説明しています。)
static
メソッドをfinal
としてマークすることは悪い習慣だとは思いません。
ご存知のように、final
は、メソッドがサブクラスによって隠されないようにしますこれは非常に良いニュースです。
私はあなたの発言にかなり驚いています:
Fooでmethod()をfinalとして再定義すると、Barがそれを非表示にする機能が無効になり、main()を再実行すると出力されます。
フーに
フー
いいえ、final
でメソッドをFoo
としてマークすると、Bar
がコンパイルできなくなります。少なくともEclipseでは私は得ています:
スレッド「メイン」の例外Java.lang.Error:未解決のコンパイルの問題:Fooからfinalメソッドをオーバーライドできません
また、クラス自体の内部でも、クラス名で修飾するstatic
メソッドを常に呼び出す必要があると思います。
class Foo
{
private static final void foo()
{
System.out.println("hollywood!");
}
public Foo()
{
foo(); // both compile
Foo.foo(); // but I prefer this one
}
}
静的メソッドは、Javaの最も紛らわしい機能の1つです。これを修正するためのベストプラクティスがあり、すべての静的メソッドfinal
を作成することがこれらのベストプラクティスの1つです!
静的メソッドの問題は、
したがって、あなたはすべきです
final
そして、あなたはすべきです
注意:プログラムの2番目のバージョンではコンパイルエラーが発生します。IDEがこの事実を隠していると思います!
私がpublic static
メソッドを持っている場合、そのメソッドは、多くの場合、いわゆるユーティリティクラスにあり、static
メソッドのみが含まれています。自己説明的な例は、StringUtil
、SqlUtil
、IOUtil
などです。これらのユーティリティクラスは、final
として既に宣言されており、private
コンストラクターで提供されます。例えば。
public final class SomeUtil {
private SomeUtil() {
// Hide c'tor.
}
public static SomeObject doSomething(SomeObject argument1) {
// ...
}
public static SomeObject doSomethingElse(SomeObject argument1) {
// ...
}
}
この方法では、それらを上書きすることはできません。
あなたのユーティリティクラスの種類にない場合は、public
修飾子の値を質問します。 private
にすべきではありませんか?それ以外の場合は、ユーティリティクラスに移動します。 「通常の」クラスをpublic static
メソッドで乱雑にしないでください。このように、それらにfinal
をマークする必要もありません。
もう1つのケースは、一種の抽象ファクトリクラスで、public static
メソッドを介してselfの具象実装を返します。そのような場合、メソッドにfinal
をマークすることは完全に意味があります。具体的な実装がメソッドをオーバーライドできるようにしたくない場合です。
通常、ユーティリティクラス(静的メソッドのみを含むクラス)では、継承を使用することは望ましくありません。このため、クラスをfinalとして定義して、他のクラスがそれを拡張しないようにすることができます。これは、ユーティリティクラスメソッドにfinal修飾子を配置することを無効にします。
コードはコンパイルされません:
Test.Java:8:Barのmethod()はFooのmethod()をオーバーライドできません。オーバーライドされたメソッドはstatic final public static void method(){
静的メソッドは定義上、オーバーライドできないため、このメッセージは誤解を招く可能性があります。
コーディング時に次のことを行います(常に100%とは限りませんが、ここで「間違っている」ことはありません。
(「ルール」の最初のセットはほとんどの場合に行われます-いくつかの特別なケースは後でカバーされます)
インターフェイスには静的メソッドを含めることができないため、問題を解決する必要はありません。抽象クラスまたは具象クラスの静的メソッドをプライベートにする必要がある場合、それらをオーバーライドしようとする方法はありません。
特殊なケース:
ユーティリティクラス(すべての静的メソッドを持つクラス):
プライベートではない具象クラスまたは抽象クラスに静的メソッドが必要な場合は、代わりにユーティリティクラスを作成することをお勧めします。
値クラス(Java.awt.Pointのように、本質的にデータを保持するために非常に特殊化されたクラスで、x値とy値をほぼ保持しています):
上記のアドバイスに従うと、責任がかなり明確に分離されたかなり柔軟なコードが作成されます。
値クラスの例は、次のLocationクラスです。
import Java.util.ArrayList;
import Java.util.HashMap;
import Java.util.List;
import Java.util.Map;
public final class Location
implements Comparable<Location>
{
// should really use weak references here to help out with garbage collection
private static final Map<Integer, Map<Integer, Location>> locations;
private final int row;
private final int col;
static
{
locations = new HashMap<Integer, Map<Integer, Location>>();
}
private Location(final int r,
final int c)
{
if(r < 0)
{
throw new IllegalArgumentException("r must be >= 0, was: " + r);
}
if(c < 0)
{
throw new IllegalArgumentException("c must be >= 0, was: " + c);
}
row = r;
col = c;
}
public int getRow()
{
return (row);
}
public int getCol()
{
return (col);
}
// this ensures that only one location is created for each row/col pair... could not
// do that if the constructor was not private.
public static Location fromRowCol(final int row,
final int col)
{
Location location;
Map<Integer, Location> forRow;
if(row < 0)
{
throw new IllegalArgumentException("row must be >= 0, was: " + row);
}
if(col < 0)
{
throw new IllegalArgumentException("col must be >= 0, was: " + col);
}
forRow = locations.get(row);
if(forRow == null)
{
forRow = new HashMap<Integer, Location>(col);
locations.put(row, forRow);
}
location = forRow.get(col);
if(location == null)
{
location = new Location(row, col);
forRow.put(col, location);
}
return (location);
}
private static void ensureCapacity(final List<?> list,
final int size)
{
while(list.size() <= size)
{
list.add(null);
}
}
@Override
public int hashCode()
{
// should think up a better way to do this...
return (row * col);
}
@Override
public boolean equals(final Object obj)
{
final Location other;
if(obj == null)
{
return false;
}
if(getClass() != obj.getClass())
{
return false;
}
other = (Location)obj;
if(row != other.row)
{
return false;
}
if(col != other.col)
{
return false;
}
return true;
}
@Override
public String toString()
{
return ("[" + row + ", " + col + "]");
}
public int compareTo(final Location other)
{
final int val;
if(row == other.row)
{
val = col - other.col;
}
else
{
val = row - other.row;
}
return (val);
}
}
特に他の人が拡張することを期待するフレームワークを開発している場合は特に、静的メソッドをfinalとしてマークすることは良いことかもしれません。これにより、ユーザーが誤って静的メソッドをクラスに隠してしまうことがなくなります。ただし、フレームワークを開発している場合は、最初から静的メソッドの使用を避けたい場合があります。
このfinal
の問題のほとんどは、VMが非常に愚かで保守的であったときまで遡ります。当時、メソッドfinal
をマークした場合、(とりわけ)VMはメソッドをインライン化できるため、メソッドの呼び出しを回避できます。これは、long-long(またはlong double: P)時間: http://Java.Sun.com/developer/technicalArticles/Networking/HotSpot/inlining.html 。
私はguessfinal
最適化のためのキーワードと彼らはあなたがそれが現代のVMで不要であるという事実に気づいていないと思います.
ちょうど私の2セント...
SpringのAOPとMVCを使用してfinalメソッドを使用することに1つの問題が発生しました。最終的に宣言されたAbstractFormControllerのメソッドの1つにセキュリティフックを配置したSpringのAOPを使用しようとしました。春はクラスでのインジェクションにbcelライブラリを使用していたと思いますが、そこにはいくつかの制限がありました。
静的メソッドはクラスのプロパティであり、オブジェクトではなくクラスの名前で呼び出されるためです。親クラスのメソッドもfinalにすると、finalメソッドはメモリの場所を変更できないため、オーバーロードされませんが、同じメモリの場所で最終データメンバーを更新できます...
純粋なユーティリティクラスを作成するときは、プライベートコンストラクターで宣言して、拡張できないようにします。通常のクラスを作成するとき、クラスインスタンス変数を使用していない場合は、メソッドを静的に宣言します(または、場合によっては、使用している場合でも、メソッドに引数を渡して静的にすると、見やすくなりますメソッドが何をしているか)。これらのメソッドは静的であると宣言されていますが、プライベートでもあります。これらは、コードの重複を回避したり、コードを理解しやすくするためにあります。
そうは言っても、静的なパブリックメソッドを持つクラスがあり、それを拡張できる、または拡張する必要がある場合に遭遇したことを覚えていません。しかし、ここで報告された内容に基づいて、静的メソッドをfinalと宣言します。