子类和父类定义相同的方法只要符合方法覆盖的条件:
子类和父类定义相同属性不会产生覆盖:
解析:
这个问题不仅要考虑变量、静态变量和常量三种情况,还要考虑private、friendly(即不加访问修饰符)、protected和public四种访问权限下对属性的不同影响,private的变量与其它三种访问权限变量的不同,对象无法直接访问私有变量。
子类父类定义相同get,set方法的引起重写(override)。
结论:由于private变量受访问权限的限制,它不能被覆盖。
属性的值取父类还是子类并不取决于我们创建对象的类型,而是取决于我们定义的变量的类型。
friendly、protected和public修饰符并不影响属性的覆盖。
静态变量和静态常量属于类,不属于对象,因此它们不能被覆盖。
常量可以被覆盖。 对于基本类型和对象,它们适用同样的覆盖规律。
java内存管理简图:
静态变量区 | 文本区 | 栈 | 堆 |
存放静态变量 | 存放方法 | 编译时变量 | 运行时变量(类属性) |
那天crm研发人员开会讨论开发中常见的问题:遇到了一个基类与子类中声明了一个相同名称的属性,最终得出的结论是:子类会覆盖父类的属性,并且初始化子类后,通过父类调用该属性和子类调用该属性的值应该相同。
这个结论是错误的。正确结论为:基类与子类中声明了一个相同名称的属性,基类和子类都可以分别管理自己的属性,且属性值不会被覆盖,即使基类与子类中声明了一个相同名称的静态变量,静态变量的值也不会覆盖。
虽然在子类和父类中定义相同名称的属性,在语义上没有多大意义,但理解背后的原理,对学习java还是很有帮助的。
解释如下:
多态和继承作为java面向对象编程的重要特征及其java类加载和初始化的独特实现机制,
确保了子类属性不会覆盖父类属性,及其属性的值。
目前就假定有一个子类和父类同时声明了一个相同名称的属性。
实例化一个类时new Xyz() 执行以下操作:
a. 为对象分配内存。
b. 执行属性的显式初始化。
c. 执行构造器
d. 由 new 运算符返回对象引用。
如果实例化子类,执行步骤a,b后,子类执行构造器会自动调用父类构造器,
如果父类还有父类,父类构造器自动调用父类的父类构造器,直到找到基类后,调用基类构造器,基类构造器完成后,返回到子类构造器继续执行子类的构造及其初始话过程。
这个就是java中一个重要的概念:父类委托。
从现象上看:子类实例化后,子类中定义的属性和方法,对于父类来讲,是子类特有的切片。
用我自己的总结的一句话来概括就是,“java类加载和初始化的过程为:一次性分配内存,分层加载”。
读到这里如果对这部分解释还是有疑问的,可以记住结论并搞清楚单个无子类继承的java类的初始化过程,之后再了解一下java的内存管理机制及其类加载机制,有利于深入理解java子类的初始话过程。由于此部分解释是自己理解的一种表达,虽然做过验证,但有错误的地方,请大家指正。
这个与其他语言中的实现机制有区别:html中定义一个相同名称和属性的标签:后者会覆盖前者。
举例说明:单个无子类继承的java类的初始化过程。
构造和初始化对象
调用 new Xyz() 执行以下操作:
a. 为对象分配内存。
b. 执行属性的显式初始化。
c. 执行构造器
d. 由 new 运算符返回对象引用。
举例:
MyDate my_birth = new MyDate(22, 7, 1964);
ü 声明只为引用分配存储空间:
my_birth XXXXX
MyDate my_birth = new MyDate(22, 7, 1964);
ü 使用 new 运算符为 MyDate 分配空间:
MyDate my_birth = new MyDate(22, 7, 1964);
my_birth ????
day 0
month 0
year 0
ü 执行构造器
执行匹配的构造器(构造器可以重载),如下所示:
MyDate my_birth = new MyDate(22, 7, 1964);
my_birth ????
day 22
month 7
year 1964
ü 变量赋值
将新创建的对象赋值给引用变量,如下所示
MyDate my_birth = new MyDate(22, 7, 1964);
my_birth 0x01abcdef
day 22
month 7
year 1964
--------------------------------------------------------------------
package haolong;
public class Jilei {
static int x =10;
public String public_jtgj="100";
private String private_jtgj="100";
String friendly_jtgj="100";
protected String protected_jtgj="100";
public Jilei() {
System.out.println ("构造父类方法");
}
public void out (){
System.out.println ("父类方法public_jtgj="+public_jtgj);
System.out.println ("父类方法private_jtgj="+private_jtgj);
System.out.println ("父类方法friendly_jtgj="+friendly_jtgj);
System.out.println ("父类方法protected_jtgj="+protected_jtgj);
System.out.println ("Jilei:x="+x);
}
public String getPrivate_jtgj() {
return private_jtgj;
}
public void setPrivate_jtgj(String private_jtgj) {
this.private_jtgj = private_jtgj;
}
}
-------------------------------------------------
package haolong;
public class Zilei extends Jilei {
static int x = 20;
public String public_jtgj="200";
private String private_jtgj="200";
String friendly_jtgj="200";
protected String protected_jtgj="200";
public Zilei() {
System.out.println ("构造子类方法");
}
public void out (){
System.out.println ("该方法在内存中被覆盖掉了");
System.out.println ("覆盖子类方法public_jtgj="+public_jtgj);
System.out.println ("覆盖子类方法private_jtgj="+private_jtgj);
System.out.println ("覆盖子类方法friendly_jtgj="+friendly_jtgj);
System.out.println ("覆盖子类方法protected_jtgj="+protected_jtgj);
}
/**
* @param args
*/
public static void main(String[] args) {
// System.out.println("Jilei jl= new Jilei();");
// Jilei jl= new Jilei();
// jl.out();
// System.out.println("Zilei j2= new Zilei();");
// Zilei j2= new Zilei();
// j2.out();
// System.out.println("Jilei z2= new Zilei();");
Jilei z2= new Zilei();
z2.out();
System.out.println ("public_jtgj="+z2.public_jtgj);
System.out.println ("private_jtgj="+z2.getPrivate_jtgj());
System.out.println ("friendly_jtgj="+z2.friendly_jtgj);
System.out.println ("protected_jtgj="+z2.protected_jtgj);
System.out.println("z2 = (Jilei) z2 ;");
z2 = (Jilei) z2 ;
z2.out();
System.out.println ("public_jtgj="+z2.public_jtgj);
System.out.println ("private_jtgj="+z2.getPrivate_jtgj());
System.out.println ("friendly_jtgj="+z2.friendly_jtgj);
System.out.println ("protected_jtgj="+z2.protected_jtgj);
}
public String getPrivate_jtgj() {
return private_jtgj;
}
public void setPrivate_jtgj(String private_jtgj) {
this.private_jtgj = private_jtgj;
}
}
---------------------------------------------------------------