Java 如何使用实例变量对接口变量进行阴影处理

Java 如何使用实例变量对接口变量进行阴影处理,java,interface,Java,Interface,我在用实例变量跟踪接口变量时遇到了一些问题。我知道如何通过重写方法并在方法中手动分配变量来实现这一点,但我不知道如何使用调用该方法的任何对象的实例变量 public interface ShakesHands { static final String name = "Gabe"; public void shakeHands (ShakesHands other); } class Student implements ShakesHands{ String n

我在用实例变量跟踪接口变量时遇到了一些问题。我知道如何通过重写方法并在方法中手动分配变量来实现这一点,但我不知道如何使用调用该方法的任何对象的实例变量

public interface ShakesHands {

    static final String name = "Gabe";

    public void shakeHands (ShakesHands other);
}

class Student implements ShakesHands{

    String name;

    @Override
    public void shakeHands(ShakesHands other) {
        String othersName = other.name;
        System.out.println(name + " shook " + othersName + "'s hand.");
    }
}

class Parent implements ShakesHands{

    String name;

    @Override
    public void shakeHands(ShakesHands other) {
        String othersName = other.name;
        System.out.println(name + " shook " + othersName + "'s hand.");
    }
}

public class App {

    public static void main(String[] args) {

        Student student1 = new Student();
        student1.name = "Bob";

        Parent parent1 = new Parent();
        parent1.name = "Sally";

        student1.shakeHands(parent1);
    }
}

这段代码将输出“Bob Shaked Gabe's hand”。我有没有办法阻止它引用接口名“Gabe”,而是引用实例名“Sally”,这样我就得到了“Bob Shaked Sally's hand”?

抛开关于编码风格和干净代码的问题,下面是为什么代码总是打印“…Shaked Gabe's hand.”

握手的方法实现引用来自ShakesHands实例的“名称”,而不是其中一个实现类。由于ShakesHands中唯一的“名称”在这里是“在范围内”,因此最终总是使用值为“Gabe”的静态变量

实际上,编译器最好始终使用静态变量值,而不是使用实现类的变量(如果存在此类变量)。派生类或实现类中的数据类型不要求与超类/接口中的数据类型相同,因此您可以让ShakeHand的名称与学生名称的类型不同

例如:

public interface ShakesHands {

    String name = "Gabe";

    public void shakeHands(ShakesHands other);
}

class Student implements ShakesHands {

    Integer name = Integer.valueOf(0);

    @Override
    public void shakeHands(ShakesHands other) {
        System.out.println(name.getClass().getSimpleName() + " (in this class) with value "+name+" vs. " + other.name.getClass().getSimpleName()+" (in other class) with value "+other.name);
    }
}
在我的示例调用中,printet文本是“值为7的整数(在这个类中)与值为Gabe的字符串(在另一个类中)”

另一件事:即使在程序的所有实现中,实现类中都有一个“name”变量:在编译时,编译器不知道在运行时是否仍然是这样。您的JAR可能用于另一个定义了“unnameshakeshand”类(没有“name”变量)的程序中。那么会发生什么呢?如果实现类使用另一个类定义了“name”,那么代码会发生什么变化?它是否应该因为您的“字符串othersName=other.name;”指令而抛出一个“ClassCastException”

长话短说:
在“ShakesHands”接口中引入一个“String getName()”方法。
每个实现类都可以返回其名称的变量值,一切正常。

抛开关于编码风格和干净代码的问题不谈,下面是为什么您的代码总是打印“…握着Gabe的手”。:

握手的方法实现引用来自ShakesHands实例的“名称”,而不是其中一个实现类。由于ShakesHands中唯一的“名称”在这里是“在范围内”,因此最终总是使用值为“Gabe”的静态变量

实际上,编译器最好始终使用静态变量值,而不是使用实现类的变量(如果存在此类变量)。派生类或实现类中的数据类型不要求与超类/接口中的数据类型相同,因此您可以让ShakeHand的名称与学生名称的类型不同

例如:

public interface ShakesHands {

    String name = "Gabe";

    public void shakeHands(ShakesHands other);
}

class Student implements ShakesHands {

    Integer name = Integer.valueOf(0);

    @Override
    public void shakeHands(ShakesHands other) {
        System.out.println(name.getClass().getSimpleName() + " (in this class) with value "+name+" vs. " + other.name.getClass().getSimpleName()+" (in other class) with value "+other.name);
    }
}
在我的示例调用中,printet文本是“值为7的整数(在这个类中)与值为Gabe的字符串(在另一个类中)”

另一件事:即使在程序的所有实现中,实现类中都有一个“name”变量:在编译时,编译器不知道在运行时是否仍然是这样。您的JAR可能用于另一个定义了“unnameshakeshand”类(没有“name”变量)的程序中。那么会发生什么呢?如果实现类使用另一个类定义了“name”,那么代码会发生什么变化?它是否应该因为您的“字符串othersName=other.name;”指令而抛出一个“ClassCastException”

长话短说:
在“ShakesHands”接口中引入一个“String getName()”方法。
每个实现类都可以返回其名称的变量值,一切正常。

为什么
ShakesHands
首先有一个
name
?我会使用访问器(setter和getter),而不是直接访问字段。你的例子很可疑;我想不出这种编码风格的有效用途。如果我没有为ShakesHands指定名称,我会收到“名称无法解析或不是字段”错误,然后不要尝试访问
ShakesHands
参考值上的
name
字段。您正在反向操作。请使用@markspace推荐的方法。为什么
ShakesHands
首先有一个
名称
?我会使用访问器(setter和getter),而不是直接访问字段。你的例子很可疑;我想不出这种编码风格的有效用途。如果我没有为ShakesHands指定名称,我会收到“名称无法解析或不是字段”错误,然后不要尝试访问
ShakesHands
参考值上的
name
字段。您正在反向操作。请使用@markspace推荐的方法。此外,请遵循编码约定。常量的拼写应该是
NAME
,这样就不会有混淆了。另外,请遵循编码约定。常量应该拼写为
名称
,这样混淆就消失了。