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 也已经提供了直接直接分配堆外内存空间的 ...
随机推荐
- java HTTP文件断点上传
之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...
- 上传200G文件
最近遇见一个需要上传百G大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...
- 【Leetcode】二叉树的最小深度
题目: 给定一个二叉树,找出其最小深度. 注意最小深度的定义! 最小深度是从根节点到最近叶子节点的最短路径上的节点数量. 说明: 叶子节点是指没有子节点的节点. 一.递归法 时间复杂度:O(n).需要 ...
- wordcloud:让你的词语像云朵一样美
介绍 对文本中出现频率较高的关键词给予视觉化的显示 使用 python import jieba import codecs import wordcloud file = r"C:\U ...
- [BZOJ2560]串珠子:状压DP+容斥原理
分析 为什么我去年6月做过这道题啊,估计当时抄的题解. 具体做法就是令\(f[S]\)表示保证连通点集\(S\)的方案数,\(g[S]\)表示不保证连通点集\(S\)的方案数. 容易想到: \[g[S ...
- Oracle锁处理脚本
----处理死锁进程--查看被锁住的表select b.owner,b.object_name,a.session_id,a.locked_mode from v$locked_object a,db ...
- Oracle-分配用户只读存储过程权限
系统新来了系统运维人员,要求创建数据库账号,只分配对表,视图,存储程序有只读权限 因为表和视图权限接触比较频繁,所以今天花点时间整理下关于存储过程的权限 关于ORACLE账号的权限问题,一般分为两种权 ...
- [CSP-S模拟测试]:stone(结论+桶+前缀和+差分)
题目描述 $Cab$有两行石子,每个石子上有一个字母,为$'C''A''B'$中的一个.一开始,在每行第一个石子上站着一只$lucky$,$Cab$每次可以选择一个字母,使得所站石子上字母为该字母的$ ...
- k8s网络通信
K8s有三种网络, 1.节点网络 2.pod网络 3.service集群网络,由kube-proxy来负责
- tomcat的work目录的作用
最近发现,很多网友喜欢把tomcat的work目录里的东西叫做缓存,其实那不是很恰当,work目录只是tomcat的工作目录,也就是tomcat把jsp转换为class文件的工作目录,这也正是为什么它 ...