Java关于继承中的内存分配
另一个例子:
public static void main(String[] args) { A test = new B(); System.out.println(test.a); } class A { int a = 1; } class B extends A { int a = 2; }
结果是1,是父类中的属性.这个时候是否存在父类对象?
这时候将父类A用abstract修饰,按理说abstract累不能实例化吧,肯定不能得到父类中的a属性,结果还是一样的,怎么理解?
分析结果:
不会产生父类对象,只是用了父类的构造函数而已,并不是用到构造函数就会产生对象,构造函数只是起对象初始化作用的,而不是起产生对象作用的,如果new A();即只有new语句才会产生父类A的对象。
变量是静态绑定 ,方法是动态绑定。 这里面变量在编译期间实现了变量调用语句与变量定义赋值语句的绑定,绑定的自然是父类的,因为调用时类型是父类的,所以值是父类中定义的值
其实你可以这么理解 创建了一个子类对象时,在子类对象内存中,有两份这个变量,一份继承自父类,一份子类。
绝对不会产生父类对象,父类中的成员被继承到子类对象中,用指向子类对象的父类引用调用父类成员,只不过是从 子类对象内存空间中找到那个被继承来的父类成员,也就是说实质是用子类对象调用变量a,这样就可以解释成员必须通过对象调用的规定,只不过这时调用的是子类对象中的继承自父类的a(子类对象中有两个a,一个继承自父类,一个属于自己)
看另一个例子:
public class FieldDemo { public static void main(String[] args){ Student t = new Student("Jack"); Person p = t;//父类创建的引用指向子类所创建的对象 System.out.println(t.name+","+p.name); System.out.println(t.getName()+","+p.getName()); } } class Person{ String name; int age; public String getName(){ return this.name; } } class Student extends Person{ String name; // 属性和父类属性名相同,但在做开发时一般不会和父类属性名相同!! public Student(String name){ this.name = name; super.name = "Rose"; // 为父类中的属性赋值 } public String getName(){ return this.name; } }
返回结果是:Jack,Rose
Jack,Jack
原因是:在Java中,属性绑定到类型,方法绑定到对象!
内存图如下:
3. java中静态属性和和静态方法的继承问题 以及多态的实质
首先结论是:java中静态属性和和静态方法可以被继承,但是没有被重写(overwrite)而是被隐藏。
静态方法和属性是属于类的,调用的时候直接通过类名.方法名完成的,不需继承机制就可以调用如果子类里面定义了静态方法和属性,那么这时候父类的静态方法 或属性称之为“隐藏”,你如果想要调用父类的静态方法和属性,直接通过父类名.方法名或变量名完成,至于是否继承一说,子类是有继承静态方法和属性,但是 跟实例方法和属性不太一样,存在“隐藏”的这种情况。
多态之所以能够实现是依赖于 继承 接口和 重写 、重载(继承和重写最为关键)。有了继承和重写就可以 实现父类的引用可以指向不同子类的对象。重写的功能是:“重写”后子类的优先级要高于父类的优先级,但是“隐藏”是没有这个优先级之分的。
静态属性、静态方法和非静态的属性都可以被 继承 和 隐藏 而不能够被重写,因此不能实现多态,不能实现父类的引用可以指向不同子类的对象。 非静态的方法可以被继承和重写,因此可以实现多态。
##接口中的实现和类中的继承是两个不同的概念,因此不可以说实现接口的子类从接口那里继承了常量和方法
例证如下:
public class Test3 { public static void main(String[] args) { C c = new C(); System.out.println(c.name); System.out.println(c.str); c.sing();//输出的结果都是父类中的非静态属性、静态属性和静态方法,推出静态属性和静态方法可以被继承 System.out.println("-----------"); A c1 = new C(); System.out.println(c1.name); System.out.println(c1.str); c1.sing();//结果同上,输出的结果都是父类中的非静态属性、静态属性和静态方法,推出静态属性和静态方法可以被继承 System.out.println("-----------"); B b = new B(); System.out.println(b.name); System.out.println(b.str); b.sing();//结果都是子类的非静态属性,静态属性和静态方法,这里和非静态属性和非静态类的继承相同 System.out.println("-----------"); A b1 = new B(); System.out.println(b1.str);//结果是父类的静态属性,说明静态属性不可以被重写,不能实现多态 System.out.println(b1.name);//结果是父类的非静态属性,说明非静态属性不可以被重写,不能实现多态 b1.sing();//结果都是父类的静态方法,说明静态方法不可以被重写,不能实现多态 } } class A//父类 { public static String str = "父类静态属性"; public String name = "父类非静态属性"; public static void sing() { System.out.println("父类静态方法"); } public void run() { System.out.println("父类非静态方法"); } } class B extends A //子类B { public static String str = "B该改写后的静态属性"; public String name ="B改写后的非静态属性"; public static void sing() { System.out.println("B改写后的静态方法"); } } class C extends A //子类C继承A中的所有属性和方法 { }
结果:
Java 父子类构造方法中的this变量
代码如下
public class Father { private Integer a = 10; // 为了便于展示初始化的过程 private String name; public Father(String name) { this.name = name; } Father() { System.out.println(this instanceof Father); // true System.out.println(this instanceof Son); // true System.out.println(this.a); // 10 变量是静态绑定的 所以在父类中,this.(变量名)输出的只能是父类中的变量 System.out.println(((Son)this).a); // null 把this强转成了Son,此时Son中的a还没进行初始化,使用的是默认值null System.out.println(this.getClass().getName()); // com.gdut.test1.Son 当前的this实例对象是子类Son } public String getName() { return name; } public void setName(String name) { this.name = name; } public static void main(String[] args) { Father s = new Son("sonName"); System.out.println(s.getName()); // sonName } } class Son extends Father { public Integer a = 100; private String name; public Son() { //显示调用super() 写不写都一样 super(); } public Son(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
思考另一个问题:父类变量私有化后,在子类的构造方法中,为什么使用父类构造方法super(参数),可以给子类对象赋值?
例如:
public class Test7 { public static void main(String[] args) { Student s = new Student("aa", 12, 90); System.out.println(s.getName()); System.out.println(s.getAge()); } } class Person1{ private String name; private int age; // 无参构造方法 public Person1(){ } public Person1(String name, int age){ this.name = name; this.age = age; } // 公有的set get public String getName(){ return name; } public void setName(String name){ this.name = name; } public int getAge(){ return age; } public void setAge(int age){ this.age = age; } } class Student extends Person1{ //属性 private int score; public Student(){} public Student(String name, int age, int score){ super(name, age); this.score = score; } //生成get/set方法 public int getScore(){ return score; } public void setScore(int score){ this.score = score; } }
输出结果:
aa
12
为什么子类中的构造器调用父类的构造器给变量赋值的时候,可以给子类继承的变量也赋值了?
public Student(String name, int age, int score){ super(name, age); this.score = score; } // super到下面 public Person1(String name, int age){ this.name = name; this.age = age; }
这时候可以测试一下就知道了
public class Test7 { public static void main(String[] args) { Student s = new Student("aa", 12, 90); System.out.println(s.getName()); // bb System.out.println(s.getAge()); // 12 } } class Person1{ private String name; private int age; // 无参构造方法 public Person1(){ } public Person1(String name, int age){ this.name = name; this.age = age; System.out.println(name); // aa System.out.println(this.name); // aa System.out.println(this instanceof Student); // true this.name = "bb"; System.out.println(this.name); // bb } // 公有的set get public String getName(){ return name; } public void setName(String name){ this.name = name; } public int getAge(){ return age; } public void setAge(int age){ this.age = age; } } class Student extends Person1{ //属性 private int score; public Student(){} public Student(String name, int age, int score){ super(name, age); this.score = score; } //生成get/set方法 public int getScore(){ return score; } public void setScore(int score){ this.score = score; } }
输出结果:
这时候可以得出的结论是,子类Student继承了父类的Person1的两个变量属性:name、age,当Student中的构造器调用super(name, age)的时候,这需要去初始化父类Person1,在Person1的构造器public Person1(String name, int age){......} 中,this.name = name; this.age = age; 这个this对象其实就是Student的实例对象,这里是初始化子类Student的name、age属性变量。
Java中子类继承了父类的私有属性及方法吗?
结论:子类对象确实拥有父类对象中所有的属性和方法,但是父类对象中的私有属性和方法,子类是无法访问到的,只是拥有,但不能使用。就像有些东西你可能拥有,但是你并不能使用。所以子类对象是绝对大于父类对象的,所谓的子类对象只能继承父类非私有的属性及方法的说法是错误的。可以继承,只是无法访问到而已。
子类不能直接访问父类的私有属性,子类只能在父类中写一个public的getXXX的方法来获取父类中的private属性,子类就调用父类的getXXX来获取private属性
父类中的公有方法和域(属性),在类继承中将会被子类继承,但是私有的将不能被继承。
那么在继承中子类如何才能继承到父类的私有域呢?
答案是:在子类的构造方法中通过super()方法调用父类的构造方法。
也就是,在构造子类的同时,为子类构造出跟父类相同的域。如此就在子类的对象中,也拥有了父类声明的域了。