Saya punya masalah dengan penyembunyian nama yang sangat sulit dipecahkan. Berikut adalah versi sederhana yang menjelaskan masalahnya:
Ada kelas: org.A
package org;
public class A{
public class X{...}
...
protected int net;
}
Lalu ada kelas net.foo.X
package net.foo;
public class X{
public static void doSomething();
}
Dan sekarang, inilah kelas bermasalah yang mewarisi dari A
dan ingin dipanggilnet.foo.X.doSomething()
package com.bar;
class B extends A {
public void doSomething(){
net.foo.X.doSomething(); // doesn't work; package net is hidden by inherited field
X.doSomething(); // doesn't work; type net.foo.X is hidden by inherited X
}
}
Seperti yang Anda lihat, ini tidak mungkin. Saya tidak dapat menggunakan nama sederhana X
karena disembunyikan oleh tipe yang diwariskan. Saya tidak dapat menggunakan nama yang sepenuhnya memenuhi syarat net.foo.X
, karena net
disembunyikan oleh bidang warisan.
Hanya kelas yang B
ada di basis kode saya; kelas net.foo.X
dan kelas org.A
perpustakaan, jadi saya tidak bisa mengubahnya!
Solusi saya satu-satunya terlihat seperti ini: Saya dapat memanggil kelas lain yang pada gilirannya memanggil X.doSomething()
; tapi kelas ini hanya akan ada karena nama bentrok, yang nampaknya sangat berantakan! Apakah tidak ada solusi di mana saya bisa langsung menghubungi X.doSomething()
dari B.doSomething()
?
Dalam bahasa yang memungkinkan untuk menentukan namespace global, misalnya, global::
di C # atau ::
di C ++, saya bisa mengawali net
dengan awalan global ini, tetapi Java tidak mengizinkannya.
sumber
public void help(net.foo.X x) { x.doSomething(); }
dan panggil denganhelp(null);
net.foo.X
punya metode, tidakorg.A.X
!A
? Warisan bisa menjadi sangat jahat, seperti yang Anda temukan…I could call another class that in turn calls X.doSomething(); but this class would only exist because of the name clash, which seems very messy
1 untuk sikap kode bersih. Tapi bagi saya sepertinya ini adalah situasi yang harus Anda lakukan pengorbanan. Cukup lakukan ini, dan berikan komentar panjang yang bagus tentang mengapa Anda harus melakukannya (mungkin dengan tautan ke pertanyaan ini).Jawaban:
Anda bisa mentransmisikan a
null
ke tipe dan kemudian memanggil metode itu (yang akan bekerja, karena objek target tidak terlibat dalam pemanggilan metode statis).Ini memiliki manfaat
net.foo.X
),B
nama yang Anda inginkan; itulah mengapa aimport static
tidak akan berfungsi dalam kasus Anda yang sebenarnya),Sisi negatifnya adalah kode ini benar-benar mengerikan! Bagi saya, ini menghasilkan peringatan, dan itu hal yang baik secara umum. Tetapi karena ini mengatasi masalah yang sebaliknya sama sekali tidak praktis, menambahkan file
pada titik penutup yang sesuai (minimal!) akan menutup kompilator.
sumber
doSomething
metode di mana pun dalam hierarki Anda), jadi ya solusi terbaik.Mungkin cara paling sederhana (belum tentu yang termudah) untuk mengelola ini adalah dengan kelas delegasi:
lalu ...
Ini agak bertele-tele, tetapi sangat fleksibel - Anda bisa membuatnya berperilaku sesuka Anda; ditambah itu bekerja dengan cara yang sama baik dengan
static
metode dan objek yang dipakaiLebih lanjut tentang objek delegasi di sini: http://en.wikipedia.org/wiki/Delegation_pattern
sumber
Anda dapat menggunakan impor statis:
Hati-hati
B
danA
jangan mengandung metode bernamadoSomething
sumber
doSomething
sebagai nama metode diB
...doSomething
di mana pun dalam hierarki pewarisan (karena cara target panggilan metode diselesaikan). Jadi Knuth membantu Anda jika Anda ingin memanggiltoString
metode. Solusi yang diusulkan oleh Donal adalah yang ada di buku Java Puzzlers Bloch (saya pikir, belum mencarinya), jadi kami dapat menganggapnya sebagai jawaban yang benar-benar berwibawa :-)Cara yang tepat untuk melakukan sesuatu adalah impor statis, tetapi dalam skenario kasus terburuk absolut, Anda BISA membuat instance kelas menggunakan refleksi jika Anda mengetahui nama yang sepenuhnya memenuhi syarat.
Java: newInstance kelas yang tidak memiliki konstruktor default
Dan kemudian aktifkan metode pada instance.
Atau, panggil saja metode itu sendiri dengan refleksi: Memanggil metode statis menggunakan refleksi
Tentu saja, ini jelas merupakan resor terakhir.
sumber
static import
fitur hanya ditambahkan diJava 1.5
. Saya tidak iri pada orang yang perlu mengembangkan untuk 1.4 atau lebih rendah, saya harus sekali dan itu mengerikan!((net.foo.X)null).doSomething()
solusi yang berfungsi di java lama. Tetapi jika tipeA
mengandung tipe dalamnet
, MAKA ini adalah satu-satunya jawaban yang tetap valid :).Tidak benar-benar jawaban THE tetapi Anda dapat membuat instance X dan memanggil metode statis di atasnya. Itu akan menjadi cara (saya akui kotor) untuk memanggil metode Anda.
sumber
null
ke jenis dan kemudian memanggil metode di atasnya akan lebih baik, karena membuat objek mungkin memiliki efek samping yang tidak saya inginkan.null
tampaknya menjadi salah satu cara bersih untuk melakukannya. Perlu@SuppressWarnings("static-access")
menjadi bebas peringatan ...null
, tetapi castingnull
selalu menjadi penghancur hati bagi saya.Tidak perlu melakukan cast atau menyembunyikan peringatan aneh atau membuat instance yang berlebihan. Hanya trik menggunakan fakta bahwa Anda dapat memanggil metode statis kelas induk melalui sub-kelas. (Mirip dengan solusi hackish saya di sini .)
Buat saja kelas seperti ini
(Konstruktor privat di kelas terakhir ini memastikan tidak ada yang bisa membuat instance kelas ini secara tidak sengaja.)
Kemudian Anda bebas menelepon
X.doSomething()
melalui:sumber
Bagaimana jika Anda mencoba mendapatkan gobalnamespace mengingat semua file berada di folder yang sama. ( http://www.beanshell.org/javadoc/bsh/class-use/NameSpace.html )
sumber
getGlobal()
bukan metode Java standar untuk paket ... (Saya pikir paket tidak dapat memiliki metode apa pun di Java ...)Inilah salah satu alasan komposisi lebih disukai daripada pewarisan.
sumber
Saya akan menggunakan pola Strategi.
Sekarang Anda juga telah memisahkan ketergantungan Anda, sehingga pengujian unit Anda akan lebih mudah untuk ditulis.
sumber
implements SomethingStrategy
padaXSomethingStrategy
deklarasi kelas.