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();
}
函数doIt将打印“dad”。有没有办法让它打印“儿子”?
答案 0 :(得分:91)
简而言之,不,没有办法覆盖类变量。
您不会在Java中覆盖隐藏它们的类变量。覆盖是例如方法。隐藏不同于重写。
在您给出的示例中,通过在类Son中声明名为“me”的类变量,您可以隐藏它将从其超类Dad继承的类变量,其名称为“me”。以这种方式隐藏变量不会影响超类爸爸中类变量'me'的值。
对于你的问题的第二部分,关于如何使它打印“son”,我将通过构造函数设置值。虽然下面的代码与你原来的问题有很大的不同,但我会写这样的东西;
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void printName() {
System.out.println(name);
}
}
JLS提供了有关隐藏在8.3 - Field Declarations
部分的更多详细信息答案 1 :(得分:55)
是。但是,就变量而言,它是覆盖(给变量赋予新值。给函数赋予新的定义是覆盖)。Just don't declare the variable but initialize (change) in the constructor or static block.
在父类
的块中使用时,将反映该值如果变量是静态的,那么在初始化期间使用静态块
更改值class Son extends Dad {
static {
me = 'son';
}
}
或者改变构造函数。
您也可以稍后在任何块中更改该值。它将反映在超类
中答案 2 :(得分:31)
是的,只需覆盖printMe()
方法:
class Son extends Dad {
public static final String me = "son";
@Override
public void printMe() {
System.out.println(me);
}
}
答案 3 :(得分:16)
您可以创建一个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"
}
答案 4 :(得分: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);
}
现在我们可以添加爸爸:
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;
}
}
看起来我们有一个家庭,让我们告诉全世界他们的名字:
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());
}
}
}
System.out输出:Tommy Nancy Dad
System.err与上面相同(只有红色字体)
JOption输出:
Tommy 然后
Nancy 然后
爸爸
答案 5 :(得分:6)
这看起来像是一个设计缺陷。
删除static关键字并在构造函数中设置变量。这样Son就可以在构造函数中将变量设置为不同的值。
答案 6 :(得分:4)
虽然类变量可能只隐藏在子类中而且没有被覆盖,但是仍然可以在不重写子类中的printMe ()
的情况下执行您想要的操作,而反射是您的朋友。在下面的代码中,为了清楚起见,我省略了异常处理。请注意,在此上下文中将me
声明为protected
似乎没有多大意义,因为它将隐藏在子类中...
class Dad
{
static String me = "dad";
public void printMe ()
{
java.lang.reflect.Field field = this.getClass ().getDeclaredField ("me");
System.out.println (field.get (null));
}
}
答案 7 :(得分:3)
class Dad
{
protected static String me = "dad";
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
protected static String _me = me = "son";
}
public void doIt()
{
new Son().printMe();
}
...将打印“儿子”。
答案 8 :(得分:2)
仅限覆盖printMe()
:
class Son extends Dad
{
public void printMe()
{
System.out.println("son");
}
}
me
方法中对Dad.printMe
的引用隐式指向静态字段Dad.me
,因此,您正在改变printMe
在{Son
中的作用。 1}} ...
答案 9 :(得分:2)
https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html
它被称为隐藏字段
从上面的链接
在类中,与超类中的字段具有相同名称的字段会隐藏超类的字段,即使它们的类型不同。在子类中,超类中的字段不能通过其简单名称引用。相反,必须通过super访问该字段,这将在下一节中介绍。一般来说,我们不建议隐藏字段,因为它会使代码难以阅读。
答案 10 :(得分:2)
它确实打印了'爸爸',因为该字段没有被覆盖但是被隐藏。有三种方法可以打印出儿子&#39;
方法1:覆盖printMe
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();
}
方法2:不要隐藏字段并在构造函数中初始化
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();
}
方法3:使用静态值初始化构造函数中的字段
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();
}
答案 11 :(得分:2)
您无法覆盖类中的变量。您只能覆盖方法。你应该保持变量私有,否则你会遇到很多问题。
答案 12 :(得分:1)
只需在子类构造函数中调用super.variable
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());
}
}
输出为10。
答案 13 :(得分:0)
当然使用私有属性,getter和setter是推荐的事情,但我测试了以下内容,它可以工作...请参阅代码中的注释
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();
}
}
Sooo ...我刚刚重新定义了继承规则,还是让Oracle陷入了棘手的境地? 对我来说,受保护的静态字符串我被明确覆盖,正如您在执行此程序时所看到的那样。此外,对我来说,为什么属性不应该被覆盖也没有任何意义。
答案 14 :(得分:0)
当您可以轻松地在子类中重新分配变量时,为什么要覆盖变量。
我遵循这种模式来解决语言设计问题。假设您的框架中有一个重量级的服务类,需要在多个派生应用程序中使用不同的版本。在这种情况下,配置超类逻辑的最佳方法是重新分配其定义&#39;变量。
public interface ExtensibleService{
void init();
}
public class WeightyLogicService implements ExtensibleService{
private String directoryPath="c:\hello";
public void doLogic(){
//never forget to call init() before invocation or build safeguards
init();
//some logic goes here
}
public void init(){}
}
public class WeightyLogicService_myAdaptation extends WeightyLogicService {
@Override
public void init(){
directoryPath="c:\my_hello";
}
}
答案 15 :(得分:0)
没有。类变量(也适用于实例变量)在Java中没有表现出覆盖特性,因为类变量是根据调用对象的类型调用的。在层次结构中添加了一个类(Human)以使其更清晰。所以我们现在有了
儿子延伸爸爸延伸人类
在下面的代码中,我们尝试迭代一个Human,Dad和Son对象的数组,但它在所有情况下都会打印Human Class的值,因为调用对象的类型是Human。
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
}
}
}
将打印
所以没有覆盖类变量。
如果我们想从其父类的引用变量访问实际对象的类变量,我们需要通过将父引用(Human对象)转换为其类型来显式地告诉编译器。
System.out.println(((Dad)humans[1]).me); // prints dad
System.out.println(((Son)humans[2]).me); // prints son
将打印
关于这个问题的部分内容: - 已经建议覆盖Son类中的printMe()方法,然后调用
Son().printMe();
爸爸的类变量“我”将被隐藏,因为“我”(在Son类中)最近的声明(来自Son class printme()方法)将获得优先权。
答案 16 :(得分:0)
变量不参与过度清洗。只有方法可以。方法调用在运行时解决,也就是说,调用方法的决定是在运行时做出的,而变量仅在编译时决定。因此,将调用该变量,其引用用于调用,而不是运行时对象。
看看以下片段:
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