有没有一种方法可以重写Java中的类变量?
函数doIt将打印“dad”。有没有办法让它打印“son”?是的,只需覆盖有没有一种方法可以重写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
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());
}
}