好久好久的,没有发表blog,之前都一直是开快车,脑子里的知识一个劲的刷新,虽然装了很多,但依然感到大脑轻飘飘的。难得有个机会停下了,深刻的理解java基础,尝试着探究最简单的问题的深层机制,发现收获还颇多。不多说,来技术总结了。
再探继承:
//父类构造器的隐式调用
class grandFather {
public grandFather(){
System.out.println("这是祖父类");
}
}
class father extends grandFather {
public father(){
System.out.println("这是父类!");
}
}
class child extends father {
public child(){
System.out.println("这是子类");
}
public static void main(String [] args){
new child();
}
}
运行结果:
这是祖父类
这是父类!
这是子类
说明:
只要在程序创建java对象,系统总是先调用最顶层父类的初始化操作,包括初始化块和构造器,然后依次向下调用所有父类的初始化操作,最终执行本类的初始化操作返回本类的实例。(至于为什么要保留隐式调用功能,至今我也没弄明白,也许是没用到这个功能,但是“存在的东西总有它的理由”,求高手解答了)
再看一例:
package cn.Sep.day24.InheritanceTest;
//内存中子类的实例
class Base{
int count = 2;
}
class Mid extends Base{
int count = 20;
}
public class subClass extends Mid {
int count = 200;
public static void main(String[] args) {
subClass s = new subClass();
Mid s2m = s;
Base s2b = s;
System.out.println(s.count);
System.out.println(s2m.count);
System.out.println(s2b.count);
}
}
//这里有个问题,s,s2m,s2b三个变量不是指向同一个变量吗?为什么输出的数值不同呢
//总结:当发生继承时,子类即使定义了与父类里同型同名的变量,但是父类里的该变量不是被覆盖,而是被隐藏了
//当发生转型时,会根据声明的类型调用父类的变量(这个与方法的重写不同)
来一极端例:
package cn.Sep.day24.InheritanceTest;
//父类的内存控制
class BaseClass {
int count = 2;
public void display() {
System.out.println(this.count);
}
}
class DerivedClass extends BaseClass {
int count = 20;
@Override
public void display() {
System.out.println(this.count);
}
}
public class FildAndMethodTest {
public static void main(String[] args) {
BaseClass b = new BaseClass();
System.out.println(b.count);
b.display();
DerivedClass d = new DerivedClass();
System.out.println(d.count);
d.display();
BaseClass bd = new DerivedClass();
System.out.println(bd.count);
bd.display();
BaseClass d2b = d;
System.out.println(d2b.count);
}
}
//输出顺序分别为:2,2,20,20,2,20,2(不信自己可以运行看看)
// 总结:如果在子类重写了父类的方法,就意味着子类里定义的方法彻底覆盖了父类的同名方法,系统将不可能把父类里的
// 方法转移到子类中。对于实例变量则不存在这样的现象,即使子类中定义了与父类完全同名的实例变量,这个实例变量依
// 然不可能覆盖父类中定义的事例变量
又来一极端例:
package cn.Sep.day24.InheritanceTest;
class Fruit {
String color = "蓝色";
public Fruit getThis() {
return this;
}
public void info() {
System.out.println("Fruit方法");
}
}
public class Apple extends Fruit {
@Override
public void info() {
System.out.println("Apple方法");
}
public void AccessSuperInfo() {
super.info();
}
public Fruit getSuper() {
return super.getThis();
}
String color = "红色";
public static void main(String[] args) {
Apple a = new Apple();
Fruit f = a.getSuper();
System.out.println("a和f所引用的对象是否相同" + (a == f));
System.out.println("访问a所引用的对象的color实例变量" + a.color);
System.out.println("访问f所引用的对象的color实例变量" + f.color);
a.info();
f.info();
a.AccessSuperInfo();
}
}
//运行结果:
//a和f所引用的对象是否相同true
//访问a所引用的对象的color实例变量红色
//访问f所引用的对象的color实例变量蓝色
//Apple方法
//Apple方法
//Fruit方法
//解析:从运行结果可以看出,Apple对象的getSuper()方法所返回的实际是该Apple对象本身(此时super.getThis()方法
//中的this指Apple对象),只是他的声明类型是Fruit
//因此通过f变量访问color实例变量时,该实例变量的值由Fruit类决定;但通过f变量调用info()方法时,该方法的行为
//由f变量实际所引用的java对象决定,因此程序输出"Apple方法"。
//总结:至此,对父、子对象在内存中存储有了准确的结论:当程序创建一个子类对象时,系统不仅会为该类中定义的实例变量分配内存
//也会为其父类中定义的所有实例变量分配内存,即使子类定义了与父类中同名实例变量。也就是说,当系统创建一个java对象的
//时候,如果该java类有两个父类(一个直接父类A,一个间接父类B),假设A类中定义了2个实例变量,B类中定义了3个实例变量,
//当前类中定义了2个实例变量,那这个java对象将会保存2+3+2个实例变量
//如果在子类里定义了与父类中已有的同名变量,那么子类中定义的变量会隐藏父类定义的变量。注意不是完全覆盖,因此系统为
//创建子类对象事,依然会为父类中定义的、被隐藏的变量分配内存空间。
到此,初探“继承”已经结束了,在这之中,收获的不只是技术,更重要的是懂得一种方法,有时候,学一样东西,切不可浮于表面,学习到的知识不可模模糊糊的,只知道怎么用是不够的,当自己知道了其中的实现的机制后,不仅知识更扎实,对于创新是很有用的,而且该知识点也会用得更灵活,不至于到后来出了错依然不知所以然,悲哉!不知所云……
分享到:
相关推荐
- 随着Java版本的更新,一些旧有的API会被弃用,新的API和特性会引入以解决这些问题。开发者需要持续学习,跟上技术的步伐,理解新API的设计意图和最佳实践。 总之,理解Java API的"丑陋"面可以帮助我们避免常见的...
Python_在上下文学习极端多标签分类XMC只使用少数的例子
标题中的“极端降水指数-NCL程序”指的是使用NCL(NCAR Command Language)编写的用于计算和分析极端降水事件的程序。NCL是一种专门用于处理气象和地球科学数据的脚本语言,它提供了丰富的功能,便于科学家进行数据...
总结起来,极端学习机是一种高效的神经网络算法,其Java实现可以帮助开发者快速构建和训练模型。提供的文件列表展示了如何将ELM应用于不同数据集,如糖尿病预测和信号处理,通过矩阵运算和最小二乘法实现模型的训练...
总的来说,Java和Smali分别代表了高级语言和底层汇编的两个极端。Java提供了易读易写的代码,适合快速开发,而Smali则为开发者提供了一种直接操作Android系统底层的能力。理解这两者之间的转换和差异,对于提升...
除了堆和栈之外,Java应用程序还可以使用本机内存(Native Memory)。本机内存是指Java虚拟机以外的内存区域,主要用于存储直接缓冲区(Direct Buffers)等对象。直接缓冲区是Java NIO框架的一部分,它可以绕过JVM的...
本资料包“基于JAVA简单简洁的压力测试, QPS测试工具.zip”提供了一种使用Java实现的压力测试解决方案,旨在帮助开发者快速评估其应用的QPS性能。 首先,我们要理解QPS的概念。QPS代表每秒查询率,是衡量一个系统在...
基于ECMWF的极端预报指数(EFI),定义了观测的“观察” EFI(OEFI)并对其进行了校准。 然后设计EFI当量百分位数(EFIEP)和EFI当量分位数(EFIEQ)来定量预测日极端降水量。 该公式表明,EFIEP不仅与EFI相关,而且...
其计算的极端气候指数共有27 种,包括16 个极端温度指数和11 个极端降水指数,这27 个极端气候指数都是世界气象组织气候委员会推荐使用的核心极端气候指数。根据内蒙的实际情况和研究的需要,选择10 个极端气温指数...
### Java线程的同步与死锁 #### 一、引言 在Java中,多线程编程是一项重要的技术,能够显著提升程序的性能和响应能力。然而,随着线程数量的增加,线程间的同步问题变得越来越复杂。本文将深入探讨Java线程中的同步...
本文将围绕“JAVA 商品秒杀demo”这一主题,详细讲解如何使用Java语言来实现一个商品秒杀系统,以及在这个过程中可能涉及的关键技术和注意事项。 首先,我们要明白秒杀系统的几个核心特性: 1. **高并发**:由于...
这意味着应当根据实际使用场景中出现频率高的操作和数据处理进行优化,而不是对那些只在少数极端情况下才会出现的场景进行优化。 为了达到最佳性能,了解和运用JVM的调优标志(tuning flags)是非常关键的。这些...
RClimDex是一款用于计算极端气候指数的专业软件,由加拿大的环境部气象研究分支的Xuebin Zhang和Feng Yang开发并维护。该软件的初期发展得到了加拿大国际发展署通过加拿大-中国气候变化合作项目(C5)的支持。...
在Java中,可以使用HashMap或者TreeMap存储字符及其对应的频率。 2. **构造哈夫曼树**: - **构建最小堆**:使用优先队列(PriorityQueue)或二叉堆来创建一个包含所有字符节点的最小堆。每个节点代表一个字符及其...
" 暗示了这个项目或文章是关于在Java中使用JNI(Java Native Interface)处理温度相关的计算或者数据交互。JNI是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互。这个项目可能是为了演示如何在...
堆是 Java 代码使用的内存,留给开发人员使用的;非堆是 JVM 留给自己的,成为永久代。永久代中保存类信息、方法区、JVM 内部处理或优化所需的内存、每个类结构、方法和构造方法的代码等。 Java 中的堆是 JVM 所...
Java的`java.util`包中提供了多种数据结构,其中哈希表(`Hashtable`)作为一种高效的键值对存储方式,在许多场景下被频繁使用。然而,对于特定的数据输入模式,传统的哈希表实现可能会遇到性能瓶颈。本文将深入探讨...
Java的发展历程经历了从Oak语言到HotJava浏览器的演变,再到Java 1.5的重要版本更新,其中Java 1.5在2004年9月登陆火星,展示了其在极端环境下的稳定性。 Java语言的主要特点包括: 1. **跨平台性**:Java通过Java...
### 使用Java实现计时器的关键知识点 #### 一、背景介绍 在软件开发过程中,对程序执行时间的测量是一项常见的需求。例如,在进行性能测试、分析算法效率或追踪程序运行状态时,都需要精确地记录时间。Java作为一种...
Java应用系统是指使用Java语言开发的应用程序系统;幂律分布通常用来描述复杂网络中节点度数的分布特征;类依赖图和函数依赖图则分别指明了类和函数之间的依赖关系,并且能够以图形的方式表现出来。 7. 研究意义和...