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()); //
}
} 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()方法调用父类的构造方法。
也就是,在构造子类的同时,为子类构造出跟父类相同的域。如此就在子类的对象中,也拥有了父类声明的域了。
Java关于继承中的内存分配的更多相关文章
- Java基础-Java中的内存分配与回收机制
Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二.
- java中子类实例化过程中的内存分配
知识点: 子类继承父类之后,实例化子类时,内存中子类是如何分配内存的呢? 下面,自己会结合一个例子,解释一下,一个子类实例化过程中,内存是如何分配的 参考博客:http://www.cnblogs.c ...
- Java实例化对象过程中的内存分配
Java实例化对象过程中的内存分配: https://blog.csdn.net/qq_36934826/article/details/82685791 问题引入这里先定义一个很不标准的“书”类,这 ...
- Netty 中的内存分配浅析-数据容器
本篇接续前一篇继续讲 Netty 中的内存分配.上一篇 先简单做一下回顾: Netty 为了更高效的管理内存,自己实现了一套内存管理的逻辑,借鉴 jemalloc 的思想实现了一套池化内存管理的思路: ...
- C++之继承和动态内存分配
C++之继承和动态内存分配 如果基类使用动态内存分配,并重新定义赋值和复制构造函数,这将如何影响派生类的实现呢?这取决于派生类的属性,如果派生类也使用动态内存分配,这将如何实现呢?这种 ...
- Java虚拟机垃圾收集器与内存分配策略
Java虚拟机垃圾收集器与内存分配策略 概述 那些内存须要回收,什么时候回收.怎样回收是GC须要完毕的3件事情. 程序计数器.虚拟机栈与本地方法栈这三个区域都是线程私有的,内存的分配与回收都具有确定性 ...
- C语言中的内存分配与释放
C语言中的内存分配与释放 对C语言一直都是抱着学习的态度,很多都不懂,今天突然被问道C语言的内存分配问题,说了一些自己知道的,但感觉回答的并不完善,所以才有这篇笔记,总结一下C语言中内存分配的主要内容 ...
- rt-thread中动态内存分配之小内存管理模块方法的一点理解
@2019-01-18 [小记] rt-thread中动态内存分配之小内存管理模块方法的一点理解 > 内存初始化后的布局示意 lfree指向内存空闲区首地址 /** * @ingroup Sys ...
- Netty 中的内存分配浅析
Netty 出发点作为一款高性能的 RPC 框架必然涉及到频繁的内存分配销毁操作,如果是在堆上分配内存空间将会触发频繁的GC,JDK 在1.4之后提供的 NIO 也已经提供了直接直接分配堆外内存空间的 ...
随机推荐
- python 小题
python 小题:给定一个字符串,找出不含有重复字符的最长子串的长度.示例 1:输入: "abcabcbb"输出: 3 解释: 无重复字符的最长子串是 "abc&quo ...
- python深度学习:矩阵转置(transpose)
转置:即行列转换. import numpy as np import matplotlib.pyplot as plt C=np.array([[1,2,3],[4,5,6]]) # Display ...
- guava中Multimap、Multiset使用
guava中的Multimap接口 Multimap和java.util.Map接口没有任何继承关系.同Map一样,也是放键值对,但是Multimap的值是一个集合.同样支持泛型,假如键值对的key的 ...
- BZOJ 3398: [Usaco2009 Feb]Bullcow 牡牛和牝牛 水题~
水~ #include <cstdio> #define N 100004 #define mod 5000011 #define setIO(s) freopen(s".in& ...
- 【学习小记】Berlekamp-Massey算法
Preface BM算法是用来求一个数列的最短线性递推式的. 形式化的,BM算法能够对于长度为n的有穷数列或者已知其满足线性递推的无穷数列\(a\),找到最短的长度为m的有穷数列\(c\),满足对于所 ...
- Spring Cloud Config教程(五)客户端使用
要在应用程序中使用这些功能,只需将其构建为依赖于spring-cloud-config-client的Spring引导应用程序(例如,查看配置客户端或示例应用程序的测试用例).添加依赖关系的最方便的方 ...
- ffmpeg摄像头推流
ffmpeg -f dshow -i video="Integrated Camera" -vcodec libx264 -preset:v ultrafast -tune:v z ...
- [python] Pythonic语法笔记
Pythonic语法笔记 __new__ 在类实例化之前执行的,也就是在init之前执行,可以为这个类写操作.接受的参数不是self而是cls.只有在new方法里返回类才会执行init操作,需要返回父 ...
- VBA通过C#以API方式调用JS脚本函数
http://www.cnblogs.com/Charltsing/p/JSDotNetAPI.html 在网页采集中,很多时候需要运行网站下载的某个js文件中的函数,以计算Request参数.VBA ...
- Text Classification
Text Classification For purpose of word embedding extrinsic evaluation, especially downstream task. ...