有没有办法在Java中覆盖类变量?

Dik*_*kla 152 java inheritance overriding

class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String me = "son";
}

public void doIt()
{
    new Son().printMe();
}
Run Code Online (Sandbox Code Playgroud)

功能doIt将打印"爸爸".有没有办法让它打印"儿子"?

Mik*_*ike 94

简而言之,不,没有办法覆盖类变量.

您不会覆盖Java中隐藏它们的类变量.覆盖是例如方法.隐藏不同于重写.

在您给出的示例中,通过在类Son中声明名为"me"的类变量,您可以隐藏它将从其超类Dad继承的类变量,其名称为"me".以这种方式隐藏变量不会影响超类爸爸中类变量'me'的值.

对于你的问题的第二部分,如何使它打印"儿子",我将通过构造函数设置值.虽然下面的代码与你原来的问题有很大的不同,但我会写这样的东西;

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void printName() {
        System.out.println(name);
    }
}
Run Code Online (Sandbox Code Playgroud)

JLS在第8.3- 字段声明中提供了更多关于隐藏的细节


Viv*_*MVK 62

是.但是就变量而言,它是覆盖(给变量赋予新值.给函数赋予新的定义是覆盖).Just don't declare the variable but initialize (change) in the constructor or static block.

在父类的块中使用时,将反映该值

如果变量是静态的,那么在初始化过程中使用静态块更改值,

class Son extends Dad {
    static { 
       me = 'son'; 
    }
}
Run Code Online (Sandbox Code Playgroud)

或者改变构造函数.

您也可以稍后在任何块中更改该值.它会反映在超级课程中

  • 我认为答案应该有一些代码以提高可读性.只需将Son实现更改为`class Son extends Dad {static {me ='son'}}` (9认同)

Rom*_*las 31

是的,只需覆盖printMe()方法:

class Son extends Dad {
        public static final String me = "son";

        @Override
        public void printMe() {
                System.out.println(me);
        }
}
Run Code Online (Sandbox Code Playgroud)

  • 为了使它成为一个更真实的例子,您可以考虑“printMe”方法可能是一个非常复杂的函数,其逻辑您不想重复。在此示例中,您只想更改人名,而不是打印它的逻辑。您应该创建一个名为“getName”的方法,您将重写该方法以返回“son”,并且 printMe 方法将调用 getName 方法作为其打印的一部分。 (2认同)

Joh*_*ler 17

您可以创建一个getter,然后覆盖该getter.如果您覆盖的变量本身就是一个子类,那么它尤其有用.想象一下,你的超级类有一个Object成员,但是在你的子类中,这个现在被定义为一个Integer.

class Dad
{
        private static final String me = "dad";

        protected String getMe() {
            return me;
        }

        public void printMe()
        {
                System.out.println(getMe());
        }
}

class Son extends Dad
{
        private static final String me = "son";

        @Override
        protected String getMe() {
            return me;
        }
}

public void doIt()
{
        new Son().printMe(); //Prints "son"
}
Run Code Online (Sandbox Code Playgroud)


nck*_*brz 10

如果你要覆盖它,我没有看到保持静态的正当理由.我建议使用抽象(参见示例代码).:

     public interface Person {
        public abstract String getName();
       //this will be different for each person, so no need to make it concrete
        public abstract void setName(String name);
    }
Run Code Online (Sandbox Code Playgroud)

现在我们可以添加爸爸:

public class Dad implements Person {

    private String name;

    public Dad(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
    return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}
Run Code Online (Sandbox Code Playgroud)

儿子:

public class Son implements Person {

    private String name;

    public Son(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
        return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}
Run Code Online (Sandbox Code Playgroud)

和爸爸见过一位好女士:

public class StepMom implements Person {

    private String name;

    public StepMom(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
        return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}
Run Code Online (Sandbox Code Playgroud)

看起来我们有一个家庭,让我们告诉全世界他们的名字:

public class ConsoleGUI {

    public static void main(String[] args) {
        List<Person> family = new ArrayList<Person>();
        family.add(new Son("Tommy"));
        family.add(new StepMom("Nancy"));
        family.add(new Dad("Dad"));
        for (Person person : family) {
            //using the getName vs printName lets the caller, in this case the
            //ConsoleGUI determine versus being forced to output through the console. 
            System.out.print(person.getName() + " ");
            System.err.print(person.getName() + " ");
            JOptionPane.showMessageDialog(null, person.getName());
    }
}
Run Code Online (Sandbox Code Playgroud)

}

System.out输出:Tommy Nancy Dad
System.err与上面相同(只有红色字体)
JOption输出:
Tommy 然后
Nancy 然后
爸爸


Pat*_*sen 6

这看起来像是一个设计缺陷.

删除static关键字并在构造函数中设置变量.这样,Son只需在其构造函数中将变量设置为不同的值.


Ser*_*kov 6

虽然类变量确实只能隐藏在子类中,而不会被重写,但仍然可以在不重写printMe ()子类中做你想做的事情,而反射是你的朋友。为了清楚起见,在下面的代码中我省略了异常处理。请注意,在这种情况下声明measprotected似乎没有多大意义,因为它将隐藏在子类中......

class Dad
  {
    static String me = "dad";

    public void printMe ()
      {
        java.lang.reflect.Field field = this.getClass ().getDeclaredField ("me");
        System.out.println (field.get (null));
      }
  }
Run Code Online (Sandbox Code Playgroud)


小智 5

https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html

这就是所谓的隐藏字段

从上面的链接

在类中,与超类中的字段同名的字段会隐藏超类的字段,即使它们的类型不同。在子类中,超类中的字段不能通过其简单名称来引用。相反,必须通过 super 访问该字段,这将在下一节中介绍。一般来说,我们不建议隐藏字段,因为这会使代码难以阅读。