有没有一种方法可以重写Java中的类变量?

有没有一种方法可以重写Java中的类变量?,java,inheritance,overriding,Java,Inheritance,Overriding,函数doIt将打印“dad”。有没有办法让它打印“son”?是的,只需覆盖printMe()方法: class Dad { protected static String me = "dad"; public void printMe() { System.out.println(me); } } class Son extends Dad { protected static String me = "son"; } public

函数doIt将打印“dad”。有没有办法让它打印“son”?

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

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();
}

仅通过重写
printMe()


Dad.printMe
方法中对
me
的引用隐式指向静态字段
Dad.me
,因此您以某种方式更改了
printMe
Son
中的操作……这看起来像是设计缺陷


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

您不能重写类中的变量。只能重写方法。您应该将变量保持私有,否则会出现很多问题。

简而言之,不,没有办法重写类变量

在Java中不重写类变量,而是隐藏它们。重写的是实例方法。隐藏不同于覆盖

在您给出的示例中,通过在class Son中声明名为“me”的类变量,可以隐藏该类变量,该类变量将从名为“me”的超类Dad继承。以这种方式隐藏变量不会影响超类Dad中类变量“me”的值

对于问题的第二部分,如何使其打印“son”,我将通过构造函数设置值。虽然下面的代码与您最初的问题有很大的不同,但我会这样写

class Son extends Dad 
{
    public void printMe() 
    {
        System.out.println("son");
    }
}

JLS提供了更多关于隐藏的详细信息,您可以创建一个getter,然后覆盖该getter。如果要重写的变量是其自身的子类,那么它特别有用。假设您的超类有一个
对象
成员,但在您的子类中,现在将其定义为一个
整数

public class Person {
    private String name;

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

    public void printName() {
        System.out.println(name);
    }
}

当然,建议使用私有属性、getter和setter,但我测试了以下内容,它是有效的。。。请参见代码中的注释

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"
}
所以。。。我只是重新定义了继承的规则,还是将Oracle置于了一个棘手的境地?
对我来说,受保护的静态字符串me显然被覆盖,正如您在执行该程序时看到的那样。另外,属性为什么不应该被重写对我来说也没有任何意义。

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

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

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

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

    /* 
    Adding Method printMe() to this class, outputs son 
    even though Attribute me from class Dad can apparently not be overridden
    */

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

class Tester
{
    public static void main(String[] arg)
    {
        new Son().printMe();
    }
}

。。。将打印“son”。

如果要覆盖它,我看不到保持此静态的有效原因。我建议使用抽象(参见示例代码):

现在我们可以添加Dad:

     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);
    }
儿子:

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;
    }
}
爸爸遇到了一位很好的女士:

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;
    }
}
看起来我们有一个家庭,让我们告诉世界他们的名字:

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;
    }
}
公共类控制台GUI{
公共静态void main(字符串[]args){
列表族=新的ArrayList();
添加(新儿子(“汤米”);
添加(新继母(“南希”);
添加(新爸爸(“爸爸”));
(个人:家庭){
//使用getName vs printName可以让调用方
//ConsoleGUI决定是否强制通过控制台输出。
System.out.print(person.getName()+);
System.err.print(person.getName()+);
showMessageDialog(null,person.getName());
}
}
}

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

JOption输出:
汤米然后
南希然后
爸爸

是。但就变量而言,它是覆盖的(给变量赋予新的值,给函数赋予新的定义就是覆盖)。只是不要声明变量,而是在构造函数或静态块中初始化(更改)

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

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

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());
    }
}
或者改变构造器


您也可以稍后在任何块中更改该值。它将反映在超级类中,它确实会打印“dad”,因为该字段不是被覆盖的,而是隐藏的。有三种方法可以让它打印“儿子”:

方法1:覆盖printMe

class Son extends Dad {
    static { 
       me = "son"; 
    }
}
方法2:不要隐藏字段并在构造函数中初始化它

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

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

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

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

public void doIt()
{
    new Son().printMe();
}
class Dad
{
    protected static String me = "dad";

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

class Son extends Dad
{
    public Son()
    {
        me = "son";
    }
}

public void doIt()
{
    new Son().printMe();
}
Inside Honda
Inside Honda
Inside bike

Max_Speed = 150
Max_Speed = 90
Max_Speed = 90
方法3:使用静态值初始化构造函数中的字段

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

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

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

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

public void doIt()
{
    new Son().printMe();
}
class Dad
{
    protected static String me = "dad";

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

class Son extends Dad
{
    public Son()
    {
        me = "son";
    }
}

public void doIt()
{
    new Son().printMe();
}
Inside Honda
Inside Honda
Inside bike

Max_Speed = 150
Max_Speed = 90
Max_Speed = 90

当您可以在子类中轻松地重新分配变量时,为什么要重写它们

我遵循这种模式围绕语言设计展开工作。假设您的框架中有一个重要的服务类,它需要在多个派生应用程序中以不同的风格使用。在这种情况下,配置超类逻辑的最佳方法是重新分配其“定义”变量

class Dad
{
    private static String meInit = "Dad";

    protected String me;

    public Dad() 
    {
       me = meInit;
    }

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

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

    public Son()
    {
        me = meInit;
    }

}

public void doIt()
{
    new Son().printMe();
}

这叫做隐藏场

从上面的链接

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

不可以。类变量(也适用于实例变量)在Java中不具有覆盖特性,因为类变量是根据调用对象的类型调用的。在层次结构中又添加了一个类(人类),以使其更加清晰。所以现在我们
    class Human
{
    static String me = "human";

    public void printMe()
    {
        System.out.println(me);
    }
}
class Dad extends Human
{
    static String me = "dad";

}

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


public class ClassVariables {
    public static void main(String[] abc)   {
        Human[] humans = new Human[3];
        humans[0] = new Human();
        humans[1] = new Dad();
        humans[2] = new Son();
        for(Human human: humans)   {
            System.out.println(human.me);        // prints human for all objects
        }
    }
}
    System.out.println(((Dad)humans[1]).me);        // prints dad

    System.out.println(((Son)humans[2]).me);        // prints son
Son().printMe();
package com.demo;

class Bike {
  int max_speed = 90;
  public void disp_speed() {
    System.out.println("Inside bike");
 }
}

public class Honda_bikes extends Bike {
  int max_speed = 150;
  public void disp_speed() {
    System.out.println("Inside Honda");
}

public static void main(String[] args) {
    Honda_bikes obj1 = new Honda_bikes();
    Bike obj2 = new Honda_bikes();
    Bike obj3 = new Bike();

    obj1.disp_speed();
    obj2.disp_speed();
    obj3.disp_speed();

    System.out.println("Max_Speed = " + obj1.max_speed);
    System.out.println("Max_Speed = " + obj2.max_speed);
    System.out.println("Max_Speed = " + obj3.max_speed);
  }

}
Inside Honda
Inside Honda
Inside bike

Max_Speed = 150
Max_Speed = 90
Max_Speed = 90
public abstract class Beverage {

int cost;


int getCost() {

    return cost;

}

}`

public class Coffee extends Beverage {


int cost = 10;
Coffee(){
    super.cost = cost;
}


}`

public class Driver {

public static void main(String[] args) {

    Beverage coffee = new Coffee();

    System.out.println(coffee.getCost());

}

}