我有一个班级和一个界面:
public interface A {
public void getNum();
}
public class B {
public void getNum() {
System.out.println("4");
}
}
public class C extends B implements A {
protected void getNum() {
System.out.println("3");
}
}
现在我的问题是,为什么这段代码会出现编译错误,我们怎么能避免它。我们有什么方法可以在C类中覆盖这个方法吗?
答案 0 :(得分:13)
来自Java语言规范:
覆盖或隐藏方法的访问修饰符(第6.6节)必须至少提供与重写或隐藏方法一样多的访问权限,如下所示:
- 如果被覆盖或隐藏的方法是公开的,那么覆盖或隐藏方法必须是公开的;否则,发生编译时错误。
- ...
请注意,您尝试覆盖public
方法getNum()
继承自类B
(以及界面A
)的新方法protected
访问修饰符。这意味着您正在尝试降低此方法的可见性,这种方法根据规范不正确
为了能够覆盖此方法,您需要将public
访问修饰符与该方法的新版本一起使用。
为什么你不能降低能见度?看一下使用你的类的下面的代码,但是放在其他的包中并问自己“这段代码应该怎么样?”。
package my.pckage;
import your.pckage.A;
import your.pckage.C;
public class Test{
public static void main (String[] args){
C C = new C();
c.getNum();// ERROR: Test class doesn't have access to `c`s protected method.
// Why should it have, Test doesn't extend C.
A a = (A)c;// Lets try using other reference
a.getNum();// Should `a` have access to method that is protected in `C`?
// If yes, then what is the point of declaring this method
// protected if all I would have to do to get access to it is
// casting instance of C to A interface?
}
}
答案 1 :(得分:6)
修复拼写错误,然后重试;)
public interface A {
public void getNum();
}
public class B {
protected void getNum() {
System.out.println("4");
}
}
public class C extends B implements A {
public void getNum() {
System.out.println("3");
}
}
答案 2 :(得分:6)
首先,当你在Java中重写方法时,范围应该从低到高。子类方法的范围应该高于超级类,例如
有效改写
class B {
protected void getNum() {
System.out.println("4");
}
class C extends B {
public void getNum() {
System.out.println("3");
}
InValid Overriding
class B {
public void getNum() {
System.out.println("4");
}
class C extends B {
protected void getNum() {
System.out.println("3");
}
你的第二个问题是你创建了两个无效的公共类,你只能在java文件中创建一个公共类。
答案 3 :(得分:5)
实现接口时,需要强制覆盖它以提供函数的具体实现(除非实现接口的类是抽象的)。在您的情况下,您正在实现一个使您实现getNum()
函数的接口,并且由于覆盖了类,您将拥有另一个具有相同签名的函数,这是不允许的。所以你得到了编译错误。
可能的解决方案:您可以将B作为界面。
答案 4 :(得分:2)
Pshemo的解释完全正确,您无法降低overridden
或interface
功能的可见性。
让我们来看看
class B
{
protected void getProtected1()
{
System.out.println("4");
}
protected void getProtected2()
{
System.out.println("4");
}
public void getPublic1()
{
System.out.println("4");
}
public void getPublic2()
{
System.out.println("4");
}
}
class C extends B
{
@Override
private void getPublic1() //COMPILATION ERROR : Cannot reduce the visibility of the inherited method from myzeromqApp.B
{
System.out.println("3");
}
@Override
protected void getPublic2() //COMPILATION ERROR :Cannot reduce the visibility of the inherited method from myzeromqApp.B
{
System.out.println("3");
}
@Override
private void getProtected1() //COMPILATION ERROR : Cannot reduce the visibility of the inherited method from myzeromqApp.B
{
System.out.println("3");
}
@Override
public void getProtected2() // NO ERROR IT MEANS YOU ARE ALLOWED TO INCREASE THE VISIBILITY
{
System.out.println("3");
}
}
从上面的示例可以看出,在任何情况下都不允许降低功能的可见性。
在你的问题中,你正在尝试实现interface
函数,我们知道Java中的interface
有规则,
public
&允许abstract
public
,static
&允许final
作为规则的大拇指,您永远不会降低overridden
或已实施的方法或变量的可见度,对于interface
,它始终为public
(如果涉及可见性),那么应该在实施的类中始终为public
。
答案 5 :(得分:2)
如上所述,每个文件只能使用一个公共类。因此,要将它们全部公开,必须创建三个单独的 .java 文件。我将在下面编写代码,并详细说明如何在每种情况下覆盖方法以使用它的正确版本。
可能总是有相同名称的方法,但是为了覆盖,它们必须具有不同的参数列表。这是编译器错误之一,您有三个具有相同参数列表的方法,即无。您可以使用正确的参数列表创建并调用该方法,以获得所需的结果。
A.java:
package stackOverflow.tests; // Sample package for visibility
public Interface A {
public void getNum(int a); // Method takes a single integer argument
}
B.java:
package stackOverflow.tests;
public class B {
protected void getNum(int a, int b) { // Method takes two integer arguments, differing in the argument list but equal in name
System.out.println("4");
}
}
C.java:
package stackOverflow.tests;
import stackOverflow.tests.A; // Importing both classes to use their methods
import stackOverflow.tests.B;
public class C extends B implements A {
public void getNum(int a, String x) { // Takes an integer and a string argument
System.out.println("3");
}
public void getNum(int a) {
//Do nothing, as in A.java, this code is necessary to be able to override the method.
}
public static void main(String[] arguments) { // Sample main method for implementation
C c = new C(); // Instantiating class C
int test = 0; // Initializing two integer variables and one String variable
int test2 = 0;
String test3 = "";
c.getNum(test); // takes one integer, using getNum() from A.java
c.getNum(test, test2); // takes two integers, using getNum() from B.java
c.getNum(test, test3); // takes an integer and a String, using getNum() from C.java
}
}
输出:
4
3
如上面的代码所示,参数列表定义了使用该方法的哪个版本。作为旁注,定义getNum(int a)
与getNum(int b)
没有区别,因此这会导致它无法编译。
答案 6 :(得分:1)
为了实现这一点,您可以执行类似的操作,因为每个文件只能有一个公共类,文件名应该与类的名称相同
public class HelloWorld{
public static void main(String []args){
C obj=new C();
obj.getNum();
}
}
//interface
interface A {
public void getNum();
}
class B {
protected void getNum() {
System.out.println("4");
}
}
class C extends B implements A {
public void getNum() {
System.out.println("3");
}
}
<强>输出:强> 3
答案 7 :(得分:1)
java类文件只能有一个公共类或接口。 将接口和已定义类的可见性更改为默认级别,或将其声明为单独的文件。
只有public和abstract修饰符可以应用于接口方法。实现接口的类不能改变方法的可见性(我们不能将它从public更改为protected)。