a.
代码块
在java中,用{}扩起来的叫做代码块。
分类
根据位置和声明的不同,可分为局部(方法中的),构造,静态,同步代码块(多线程再讲)
代码块的应用
局部代码块 [方法中]
* 在方法中出现的。随着实例化对象的创建而存在,用来限制变量生命周期,及早释放,可提高代码利用率。
* 跟for循环类似,int i的访问范围一样。
构造代码块 [类中方法外](又叫初始化块)
* 在类中方法外出现。每创建一次对象,都要执行一次构造代码块,并且优先于构造方法前先被执行。
* 且多个构造方法中相同的代码放在一起,每次调用都有执行,每次创造对象后,先执行构造代码块,再构造方法,再普通方法。
静态代码块 [优先于主方法前先被执行]
* 在类中方法外出现,加上static来做修饰,用于给类进行初始化的,在类加载的时候执行,有且只执行一次。
* 作用:
* 给类做初始化用的,一般用于加载驱动(驱动也加载一次)。
* 因为被static修饰的,所以静态代码块是随着类的加载而加载的,当在类加载时,static静态代码块就会被执行,因为类只加载一次,所以static一只加载一次。
* 无论创建多少个对象,static静态代码块都执行一次。
* 一般用于加载驱动的。
作业题一:
1、代码块是什么,分为哪几类,各自有什么特点?
含义:
* 在java中用{}扩起来的就称为代码块。
代码块分类:
* 静态代码块
* 局部代码块
* 构造代码块
* 同步代码块
各自特点:
* 静态代码块,在类中方法外,用 static 来做修饰,用于给类进行初始化用的,是随着.class 字节码文件的加载而加载的,优先于主方法先存在,随着类的消失而消失,一般用于加载驱动,且只能执行一次。
* 局部代码块,在方法中出现,用于限定变量的生命周期,可用于提高内存的利用率。
* 构造代码块,在类中方法外,多个构造方法相同的代码存放在一起,每次再调用构造方法前执行。
* 同步代码块,多线程再讲。
注意事项:
局部/构造/静态/代码块的执行顺序:
静态 > 局部 > 构造
例子:
参考:G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\Demo1_代码块_局部代码块.java
静态代码块,构造代码块,构造方法的执行流程?
静态代码块
* 当jvm加载.class字节码文件时,给类进行初始化的,且只执行一次。
构造代码块
* 在构造方法之前被执行。
构造方法
* 随着实例化对象的创建而执行,且每次创建对象,都执行一次构造方法,随着对象的释放而消失。
作业题二:
2、子父类都有静态代码块、构造代码块、构造方法,那么他们六者之间的执行流程是什么?
分析:
1) 因为子继承父,所以先执行父类的字节码文件,因为静态代码块是随着类的加载而加载的,所以第一步先执行:父类的静态代码块。
2)父类的静态代码块执行完成后,子类的字节码文件也同样加载到内存,所以第二步是:子类的静态代码块。
3)因为new的是子类的对象,又因为构造代码块是在构造方法之前执行的,且二者存在继承关系,所以第三步执行的是:父类的构造代码块。
4)执行完第三步:父类构造代码块后,紧接着执行第四步:父类的构造方法。
5)当父类的构造方法执行完后,开始执行子类的构造方法,因为构造代码块是在构造方法前执行的,所以第五步执行:子类的构造代码块。
6)当子类的构造代码块执行完后,开始执行子类的构造方法。
所以顺序是:
1)父类静态代码块
2)子类静态代码块
3)父类构造代码块
4)父类构造方法
5)子类构造代码块
6)子类构造方法
代码块面试题
分析程序中的代码的执行顺序?
例子:
根据 静态 > 局部 > 构造这个顺序来分析:
参考:G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\Demo2_Student_构造代码块面试题.java
b.
继承
概念
* extends 表示关键字,用于让类与类之间产生关系,只存在于子父类当中。(子继承父,不可父继承子)
* 他们是一种满足 is a的一种关系,如猫是动物的一种。
* java中只支持单继承,不支持多继承,但支持多实现和多层继承。
* 多层继承:子 继承 父, 父 继承 爷 ,子 继承 爷(子继承爷就是多层继承)
好处
* 提高代码复用性 (父类有了,子类就不需要再写了,继承即可)
* 提高代码维护性 (新添加属性,只要在父类中添加了,其他子类也就都有了)
* 让类与类之间产生关系,这是多态的前提 (多态:即多种形态) 因为要:父类有用指向子类对象。
弊端
* 增强了代码的耦合性,因为优秀的代码都是围绕着 “高内聚,低耦合”的原则去开发的。
(耦合性:两个类过分紧密,父类有什么,子类就必须有什么。)
开发原则
* 高内聚,低耦合(使用装饰者模式,就能降低耦合性)
* 内聚:自己完成某件事情的能力,耦合性低,之间能完成是事情不求他人。【公司离开你,还能活】
* 耦合:类与类之间的关系。【你离开公司,就不能活】
高内聚:自己能完成的事情,自己做。
低耦合:合作式开发,但是要主次分明。
p.s.
子类只能访问父类中非私有的成员(属性和方法)。
子类无法继承父类中私有的内容。
父类怎么来的? 共性内容不断向上抽象来的。
p.s.贝贝2017/8/19 1:07:35
作业题三:
3、继承的好处、弊端分别是什么?
好处:
* 提高代码复用性。
* 提高代码维护性。
* 让类与类之间产生关系,是多态的前提。
弊端:
增强了代码之间的耦合性,优秀的代码开发一直遵循的是一种 “高内聚,低耦合” 的一种开发规则。
高内聚:自己完成的事情,一般不求他人(在开发的意思是,本类能完成的功能尽量在本类完成,即本类完成功能的能力度。)
低耦合:合作式开发,但是要分清主次关系(一般开发规则有:分模块开发 和 分功能开发。)
装饰者模式
好处:降低耦合性,被装饰的类与装饰的类无关。
代码实现:
1. 获取被装饰类的引用
2. 在装饰类的构造方法中传入被装饰类的对象
3. 对原有功能进行升级
例
class Demo2_装饰者模式 {
public static void main(String[] args) {
HmStudent hm = new HmStudent(new Student());
hm.name="哈哈";
hm.age=22;
hm.study();
System.out.println(hm.name+"..."+hm.age);
}
}
//黑马学生 继承 学生类 且 实现 方法Coder类的接口。
//在实现接口类中,完成具体的方法实现。
class HmStudent extends Student implements Coder{
//1. 获取被装饰类的引用
private Student s;
//2、在装饰类的构造方法中传入被装饰类的对象
public HmStudent(Student s){
this.s = s;
}
public void code(){
//3. 对原有功能进行升级
}
//在实现接口类中,完成具体的方法实现
public void study(){
System.out.println("程序员敲代码.");
}
}
//接口 接口中定义的都是方法,且都是没有方法体的方法。
interface Coder{
public void study();
}
class Student {
String name;
int age;
}
继承特点
* java中只支持单继承,不支持多继承,但支持多实现(即实现接口)。
* 但有些语言可支持多继承,如: a类 extends c类,d类,e类...
原因?
* 因为多继承容易出问题,如果两个父类中有相同的方法,子类就不知道该具体调用哪一个方法了。
* 这种机制就换来了另一种安全的方式来体现,即多态。
* java中存在多层继承的关系(即继承体系)
* 子 extends 父
* 父 extends 爷
* 子 extends 爷
* 由继承的特点可看出:
* 如果想用这个体系的【所有功能】, 看【最底层(儿子类)的类去创建对象】【即子类是用于扩展的功能】
* 如果想用这个体系的【共性功能】, 看【最顶层(爷爷类)的类,即最先继承的类】
Java中继承的特点
* java中只支持单继承,不支持多继承,但支持多实现和多层继承。
* 当创建对象时:
如果是想要其共性部分,就去找顶层(即父类)
如果想要知道功能性最全的,就去找底层(即子类)
p.s.
子类中所有的构造函数默认都会访问父类中的空参构造函数,因为每一个构造函数的第一行都有一个默认的super语句,去访问父类的空参构造,即使一个普通类第一行也有一个super语句,因为他会去访问Object类。
为什么子类实例化的时候要去访问父类中的构造函数?
因为子类继承父类,获取到父类中的内容,所以在使用父类内容之前,要先看看父类是如何自己的内容进行初始化的。
1. 当父类中没有空参构造时,子类的构造函数必须通过this或super语句指定要访问的构造函数。
2. 子类构造函数中如果使用this调用本类的构造函数,那么默认的super就没有了,因为super和this不同同时定义在的第一行,所以只能存在一个,但是可以保证的是,子类中肯定有其他的构造繁琐去访问父类的构造函数
3. super必须存在子类的构造函数的第一行,因为父类的初始化动作要先完成。
作业题四:
4、Java中继承的特点是什么?
特点:
* Java只支持单继承,不支持多继承,但支持多实现和多层继承。
多实现:一个类可以实现多个接口。接口:后面说。
多层继承:子继承父,父继承爷,子继承爷,存在这种关系后,子继承爷就是多层继承了。
当创建对象时,
如果想要其共性部分功能,就找顶层(父类,即创建父类对象)。
如果想要其全部功能,就找底层(子类,即创建子类对象)。
例子
class Demo3_Extends继承的特点 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in); //in表示键盘录入的意思。
DemoC c = new DemoC();
c.show(); //结果是:DemoB
}
}
//最顶层的类 即爷爷类 有最完善的【共性功能】
//爷爷类
class DemoA {
public void show(){
System.out.println("DemoA ");
}
}
//父亲类
class DemoB extends DemoA {
public void show(){
System.out.println("DemoB ");
}
}
//最底层的类 即儿子类 有最完善的【全部功能】
//儿子类
class DemoC extends DemoB {
}
//不能让C类即去继承A类,也继承B类,这不符合Java对于继承的规定,
//只能【多层继承】,即通过 B extends A, 再让C extends B 来完成对A类和B类所有功能的继承。
//不能多继承的原因?有安全隐患,如果让C类同时继承A,B类,当创建C类对象时,就不知道该具体调用AB中哪个同样的show方法了。
//当C类去 extends B类(B 已经extends A了)时,创建C类对象后,c调用show()方法, 输出的结果是 :DemoB,因为 B extends A时,b中有同样有show方法,就将A中的show方法给覆盖了,所以打印c.show(),结果自然是DemoB。
继承的注意事项和什么时候去使用继承
注意事项:
* 子类只能继承父类所有(非)私有的成员[即成员方法和成员变量],因为私有成员只能在本类使用。 【但想继承也可以,通过暴力反射完成 最后一天课程说】
* 子类不能去继承父类中构造方法,但是可以通过super来访问父类的构造方法。
* 子类不能继承父类的构造方法?因为两个类的类名不同,且构造方法是在创建对象的时候使用的,如果继承了,系统在创建对象后,就不知道具体该调用哪个构造方法了。
* 不能为了部分功能去继承。
* * 项目经理 姓名 工号 工资 奖金
* 程序员 姓名 工号 工资
* 【只能向上抽取出来一个员工类,放共性功能,让项目经理类和程序员类都去继承该员工类即可】
什么时候使用继承:
不能为了单独继承而继承,他们之间是一种 is a的关系,只有满足了这种情况才考虑去使用继承。
即:
动物
猫
狗
(猫是动物的一种 狗是动物的一种) 即 is a 的关系。
水果
苹果
香蕉
桃子
(苹果是水果的一种 香蕉是水果的一种)即 is a 的关系。
采用假设法:
如果有两个类A,B 只有满足A是B的一种,或B是A的一种的时候,才考虑使用继承。
继承中局部变量的关系
情况一:
* 不同名的变量
* 在子父类中出现不同名变量,结果都输出。
情况二:
* 同名变量
* 在子父类中出现了同名变量,就采用就近原则,即子类当中有,就使用子类的。
【子父类中出现同名变量,只在讲课中有,开发中是不会出现的。因为子类继承父类,就是为了让子类去使用父
类中的成员,如果子类中都有了父类中同名的成员变量,就没有任何意义了。】
作业题五:
5、Java中继承的注意事项是什么?我们什么时候使用继承? 继承中局部变量的关系?
注意事项:
* 子类只能继承父类非私有的成员,如果子类或其他想要访问私有成员,必须使用get()方法进行访问。
什么时候使用继承:
* 不能为了部分功能去实现继承,只有他们满足一种 “is a” 的关系(苹果是水果的一种)时,才考虑使用继承,一般两个类或以上的类都满足 “is a” 的关系时,就向上抽取出父类,即公共类。
注意;子类不能继承父类的构造方法,只能通过super关键字去调用父类的构造方法,不然jvm无法识别使用是子类的构造方法还是父类的构造方法。
如:
子类:
名字:苹果,颜色:红,功能(方法):补充营养。
名字:香蕉,颜色:黄,功能(方法):利肠道。
因为存在多个重名属性,即向上抽取父类:
父类:
* 相同属性:名字 和 颜色。
* 方法:功能(食用保持身体健康)。
且在子类中重写方法,完成其特有的功能即:
* 子类苹果:补充营养。
* 子类香蕉:利肠道。
继承中局部变量的关系:
同名变量名称:
采用就近原则,谁离子类进,就使用哪个,即就近原则。
异同变量名称:
如果是异同变量名称,结果都输出。
c.
this和super的区别和使用
this
* 代表当前对象的引用,即谁来使用我,我就代表谁。
super
* 代表当前对象父类的引用,即子类继承父类后,想要去使用父类的成员时,可
* 使用super。
p.s.
子父类中,成员的特点体现:
1)成员变量:
* 在本类中成员变量和局部变量可以用this来区分, this表示成员变量。因为局部变量一般在方法里或方法声明上。
* 当子父类中出现同名成员变量时,可以用super来区分父类。
2)成员方法:
* 当子父类中出现成员方法一模一样的情况的时候,会运行子类中的方
法,这种现象被称为:覆盖操作(重写)。这是方法在子父类中的特性。
* 在子类覆盖(重写)父类方法后,还想继续使用被覆盖的父类方法时,可以通过super.方法名()来获取。
方法的两个特性:
1) 重载,只出现在本类中,即overload。
2) 重写,出现在子父类当中,即override。 有道词典翻译: vt. 推翻;不顾;践踏
this和super的使用区别 (3种区别)
* 调用成员变量
* this.成员变量 即可调用本类的成员变量,也可调用父类的成员变量。
* 前提是本类当中没有,才能去使用父类的,因为他们存在继承关系。
* super.成员变量 只能调用父类中的成员变量。
* 调用构造方法
* this(语句) 只能调用本类的构造方法
* super(语句) 只能调用父类的构造方法
* 调用成员方法
* this.成员方法() 即可调用本类的成员方法,也可调用父类的成员方法
* super.成员方法() 只能调用父类的成员方法
继承中构造方法的关系(继承中构造方法的执行流程)
* 子类中所有的构造方法默认都会去访问父类中的空参构造。【前提:必须是继承关系】
* 为什么?
* 因为子类继承父类中的数据,还可能会去使用到父类中的数据,所以子类在完成初始化之前,一定会
去完成对父类数据的初始化。
其实
每个构造方法的第一句默认都是调用:super()。 Object类是最顶层的父类,所有的类都继承他,自定义的类也一样继承他。
子类中的构造方法都有一个默认的super(),去访问父类的空参构造。
原因?
因为子类继承父类的属性,很可能会去访问父类中属性的数据,所以要必须先对这些属性进行初始化,才能去访问父类的构造方法。
继承中构造方法的注意事项
父类没有无参构造,子类该怎么办?
* super解决 可在在子类中,调用父类中的无参构造。(也能调用父类的有参构造)
* this解决 可在在子类中,调用本类的有参构造。
【注意】
super()或this必须出现在构造方法的第一条语句上,不能同时出现。
但是在普通方法中this.父类方法()和 super.父类方法() 可以不用放在第一行。
具体可参考:G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\day08_最新作业代码\Work3_存在继承关系的猫咪_狗狗类.java 中的Dog lookHome()方法里的写法。
作业题六
6、this关键字和super关键字分别代表什么,以及他们各自的作用分别是什么?
分别代表:
this 代表当前对象的引用,谁使用我,我就代表谁,即哪个对象使用this,this就代表哪个对象。
super 代表当前对象父类的引用,用于在子类中去访问父类的成员及构造。
this 和 super 的区别:(3种)
* 调用成员变量
this 既能调用父类的成员变量,也能调用子类的成员变量。
super 只能调用父类的成员变量。
* 调用成员方法
this.成员方法 既能调用父类成员方法,也能调用子类成员方法。
super.成员方法 只能调用父类的成员方法
* 调用构造方法
this 只能调用子类的构造方法
super 只能调用父类的构造方法
作业题八
(没有7)8、继承中构造方法的执行流程是什么?
执行顺序:
先执行父类中的构造方法,再执行子类中的构造方法。
作业题九
9、为什么子类中所有的构造方法默认都会访问父类的空参构造?
假如父类没有无参构造方法,子类应该怎么办?
答:
问题一:因为在子类对象在访问父类数据前,用于对父类数据进行初始化的。
问题二:如果父类中没有无参构造,可在子类中使用super();来访问父类的有参构造,或使用this();来调用本类的其他构造。
作业题十
10、super关键字和this关键字可以在构造方法中共存吗?
额可以,只能放在第一行,如果是其他普遍方法,super或this可以不用放在第一行。
子类{
super(); //调用的是父类的构造。
this.setName(name); //因为存在继承关系,所以也就相当于调用子类的set方法
}
继承中的面试题
看程序写结果1
class Fu{
public int num = 10;
public Fu(){
System.out.println("fu");
}
}
class Zi extends Fu{
public int num = 20;
public Zi(){
super(); //有个隐藏的super();每个构造方法中都有一个默认的super,去调用父类的完成构造方法
System.out.println("zi"); // num=20;
}
public void show(){
int num = 30;
System.out.println(num); //采用就近原则 即30
System.out.println(this.num); //this是用于区分重名的成员变量和局部变量,这里的this表示成员变量,即20
System.out.println(super.num); //super调用是的父类的成员变量,即10
}
}
class Test1_Extends {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
执行顺序:
fu 1)首先Zi(),会去调用zi的无参构造,因为zi的无参构造中有super(),所以先去调用父类的无参构造,即fu。
zi 2)输出fu后,zi()中的无参构造里还有一个语句,即:zi。
30 3)接着调用z的show()方法, 第一个输出语句num,即采用就近原则,所以num=30。
20 4)this.num 是访问重名的成员变量和局部变量时,用来访问成员变量用的,即:this.num=20。
10 5)super.num 中的super是访问父类的,所以super.num = 10;
看程序写结果2
class Fu {
static {
System.out.println("静态代码块Fu");
}
{
System.out.println("构造代码块Fu");
}
public Fu() {
System.out.println("构造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("静态代码块Zi");
}
{
System.out.println("构造代码块Zi");
}
public Zi() {
System.out.println("构造方法Zi");
}
}
Zi z = new Zi();
结果: 静态代码块Fu 1)因为创建的是zi()的无参对象,又因为zi继承fu,所以fu类先加载到内存,即 先输出:静态代码块Fu。
静态代码块Zi 2)又因为创建时zi类的对象,所以zi类也要加载到内存,即输出:静态代码块Zi
构造代码块Fu 3)访问zi的无参构造对象时,必须要先访问父类的无参构造,又因为无参构造是在构造代码块后面出现的,所以先输出:构造代码块Fu
构造方法Fu 4)随着构造代码块的输出后,再输出无参构造。
构造代码块Zi 5)只有先访问完父类的无参构造时,再能访问子类的无参构造,因为构造代码块时先于构造方法前先执行的,所以先输出:构造代码块Zi
构造方法Zi 6)构造代码块输出后,才能输出构造方法,所以是:构造方法Zi
老师说法:
1) jvm调用main方法, 方法都进栈,所以main方法进栈。
2) 首先遇到Zi z = new Zi(),因为zi类继承父类,所以会先将fu.class和zi.class分别加载到内存,当fu.class加载进内存时,静态代码块也会随着fu.class一起加载, 当zi.class加载进内存时,静态代码块也会随着zi.class一起加载。所以第一个输出:静态代码块Fu 第二个输出:静态代码块Zi
3) 加载完后,走zi类的构造方法,因为java是分层初始化的(在子类的构造方法中,每个子类中都有一个super),所以先去走父类的构造方法, 但是在执行父类构造时,发现父类有构造代码块,构造代码块是优先于构造方法前先执行的,所以第三个输出的是:构造代码块Fu 第四个输出的是:构造方法Fu。
4) fu类初始化后,就该子类初始化,所以第五个输出是:构造代码块Zi 第六个输出的是:构造方法Zi
原则:
* 静态代码块是,随着类的加载而加载的。
* 构造代码块先于构造方法前先被执行。
顺序:
静态代码块 > 构造代码块 > 构造方法
继承中成员方法的关系
--出现的情况:
* 不同名方法时:
* 都能够调用,即可调用父类中的方法, 也能调用子类中的方法
* 同名方法时:
* 如果子类定义了父类中重名的方法, 就使用子类中的方法,这种叫【方法的重写或覆盖】
* 如果还想使用父类中重名的方法的话,可以在子类中重名方法里的
第一行使用:super.父类重名成员方法(); 即可完成对父类重名方法的调用。
d.
方法的重写
概述
在子父类中出现了一模一样的方法(返回值类型可以是子父类,面向对象再说)【方法名,返回值相同,参数列表一样理解为方法的重写】
应用
当子类需要父类中的功能,而功能的主题子类自己特有的内容时,可以重写父类中的方法,这样既延续了父类功能,也完成了子类的特殊性。如果在子类重名方法中还想使用父类中的重名方法,可以通过super.父类方法();来调用即可,该方法可以不用放在第一行,只有在构造方法中super才只能放在第一行。
为什么使用继承和重写
主要是为了系统的升级和功能的扩展。
【注意:只有在构造方法中super只能放在第一行,其他方法中使用super可以不再第一行】
【Java采用的是Unicode的编码,Unicode的编码容纳了世界上的所有语言,所以支持中文编写程序,但一般建议不使用中文。】
例子:
G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\02_继承\Demo6_方法的重写.java
重写注意事项 (4个)
1. 子类不能继承父类私有的方法
* 因为父类中的私有方法,无法被其他类所继承。
2. 子类重写父类时,访问权限不能低于父类(即子类>=父类的访问权限) (public最大)
* 因为定义子类是希望子类比父类更加强大。如果子类权限比父类越来越小,最终会导致子类无法被使用(即子类无法被当成父类被其他类所继承)。
* 最好权限修饰符一致,如果父类没有权限修饰符,子类也可不写
3. 父类中的静态方法,子类也必须通过静态方法来实现重写
* 静态只能覆盖静态,非静态不能覆盖静态,且静态也不能覆盖非静态,因为jvm无法识别去调用具体哪个方法 其实这种形式不属于方法的重写,多态中再具体解释。
4. 子类重写父类方法,最好声明一模一样
方法重写面试题
over:之前,理解为再此之前。
ride:推翻
load:装填
override: 再此之前推翻原先的,即重写。 只能出现子父类中
overload: 再此之前装填更多的,即重载。 只能出现本类中
重载(overload[装填])和重写(override[推翻])的区别 (2个)
* overload(重载): 只能在本类中,出现了方法名相同,与返回值类型无关,只看参数列表的形式。
* override(重写): 只能出现子父类中,出现了方法名相同,且与返回值类型有关的。
重载:本类中出现方法名相同,且与返回类型无关,只看参数列表的方法。
重写:子类中出现了父类中一模一样的方法,且与返回值类型有关,返回值类型一致的或是父类。
* overload(重载) 能改变返回值类型,方法名相同,与返回值类型无关,只看参数列表。
* override(重写)不能改变返回值类型(方法名和参数列表必须相同,多态再具体说明) 返回值类型可以是父类。
p.s.
方法的两个特性:
1) 重载,只出现在本类中, 即overload。
2) 重写,出现在子父类当中,即override。
子类调用方法的顺序:
先找本类,再找父类。(就近原则)
p.s.
什么时候使用重写重载?
当子类需要父类功能,当功能主体是子类特有的内容是,就可以覆盖父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
* 父类中私有成员不能被重写。
* 父类中static的方法不能被重写。
* 重写时,子类方法权限必须大于或等于父类方法权限。
作业题十一
11、Overload和Override的区别是什么?方法重载能改变返回值类型吗?
overload 是重载,只能出现在本类当中,规则:方法名相同,与返回值类型无关,只看参数类别的一种形式,且能改变返回值类型。
override 是重写,只能出现在子父类当中,在继承关系中,出现了子父类规一模一样的方法就是重写,规则:必须方法名相同,返回值类型相同,参数列表也相同的一种形式,且无法改变返回值类型。
overload 重载 可以改变返回值类型。
orveride 重写 无法改变返回值类型。
继承中的细节问题
案例1:
* A:案例演示
* 使用继承后的学生和老师案例
* 使用继承后,增强了代码复用性,减少了代码的冗余。
* 分析:
* a.首先将两者的共性抽取出来,创建一个共性父类Person,封装其共性属性,完成共性内容。
* b.然后创建子类学生和老师,让他们去继承Person父类。
* c.然后在学生和老师中完成特有的功能。
* d.两种赋值方式:setXXX() 和 new对象实际传参。
this.getName() 是子类继承了父类,相当于本类中也有了this.name = name;
super.getName() 是子类去直接调用了父类中的方法。
getName() 是隐藏了this,其实还是this.getName();
该例子必须去看看。
地址:
G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\02_继承\Test2_使用继承后的学生和老师案例.java
案例2:
* A:猫狗案例分析
* B:案例演示
* 猫狗案例继承版
* 属性:毛的颜色,腿的个数
* 行为:吃饭
* 猫特有行为:抓老鼠catchMouse
* 狗特有行为:看家lookHome
分析:
1. 将两者共性内容,抽取出来放入父类Animal中,完成共性属性和内容。
2. 再创建子类猫,狗分别去继承父类Animal
3. 再在子类中完成其特性部分。
子类中有参构造方法的写法:
*可通过super(name, age); 去调用父类中的有参构造。super是本类对象父类的引用。
子类中属性的访问可使用3种形式:
* getName(); 该方法隐藏了this, 因为存在继承关系,所以访问的相当于也是本类的 this.name = name;
* this.name(); 因为存在继承关系,所以访问的相当于也是本类的 this.name = name;
* super.name(); super是本类对象父类的引用,所以直接就是调用父类中的getName()的方法。
地址:
G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\02_继承\Test3_猫狗案例分析和实现及测试.java
e.
final关键字
概述
final是关键字,翻译为 "最终",只要被final修饰的,都不能修改和继承。
应用
* 修饰类时,类不能被继承,但能继承其他类。
* 如: public final class Animal{}
* 修饰方法时,方法不能被重写。
* public final void method(){}
* 修饰成员变量时,变量变常量,要求所有字母大写,多个单词用下滑线隔开,【且只能被赋值一次,且必须赋初始化值,不能为空。】
* final int AGE = 4; (不能被修改的常量)
* public static final int LEG =3; (静态且不能改变的常量)
* final修饰的变量叫常量,所有字母都大写,一般和public static 一起被使
用,即:public static final String NAME="张三";
例子:G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\04_final\Demo1_final_关键字概述.java
作业题十二
12、final关键字可以做什么,有什么特点?
含义:
final 是关键字,被翻译为 最终,可用于修饰类,变量,方法。
特点:
修饰类时,该类不能被继承,但可以继承其他类。
修饰变量时,变量变常量,必须初始化,不能为空和只能被赋值一次,即所有字母大写,如果存在多个单词,用下滑写将每个单词隔开,一般和 public static 一起使用,即 public static int AGE =7;。
修饰方法时,该方法不能被其他类重写。
作业题十三
13、final修饰局部变量时,有什么特点?
有两种情况:
当局部变量是 基本数据类型:其值不能被改变。
引用数据类型:地址值不能被改变,但对象中的属性值能被改变。
注意事项
A:案例演示
* 方法内部或者方法声明上都演示一下(了解)
* 修饰局部变量
* 基本数据类型: 值不能被修改。
* 引用数据类型: 只是地址值不能被改变,但对象的属性值是可以改变。
//方法内部
基本数据类型:
final int a = 3;
a=10;
sop(a);//3 因为final修饰基本数据类型,其值不变。
引用数据类型:
final Person p = new Person("呵呵",7);
p = new Person("哈哈", 13); //直接报错,因为被final修饰的对象,即就是地址值,不能被重新赋予一个新的地址值。
但可以:
p.setName("楚乔");
p.setAge(6);
sop(name, age); //结果:楚乔 6 ,因为被final修饰的引用数据类型,其对象的属性值是可以改变的,但地址值是不能改变的。
//方法声明上
method(5); //5
method(6); //6 最终值改变,因为每个方法都是调用完后,都弹栈,下一个方法进来是新的方法即新的属性值,所以值是改变的。
例子:
G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\04_final\Demo2_final_局部变量的注意事项.java
final修饰变量的初始化时机
* 必须显示初始化。
* 在对象的构造方法完毕前完成初始化即可。
例子:
G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\04_final\Demo3_final_修饰变量的初始化时机.java
p.s.
为什么要用final来修饰变量,其实在程序中如果有一个数据是固定的,那么直接使用这个数据就可以了,但是这样的阅读性差,所以要给这个数据起个名字,而且这个变量名称的值不能任意改变,所以要加上final来固定。
写法: 常量所有字母大写,多个单词,中间用_来隔开。
代码块
在java中,用{}扩起来的叫做代码块。
分类
根据位置和声明的不同,可分为局部(方法中的),构造,静态,同步代码块(多线程再讲)
代码块的应用
局部代码块 [方法中]
* 在方法中出现的。随着实例化对象的创建而存在,用来限制变量生命周期,及早释放,可提高代码利用率。
* 跟for循环类似,int i的访问范围一样。
构造代码块 [类中方法外](又叫初始化块)
* 在类中方法外出现。每创建一次对象,都要执行一次构造代码块,并且优先于构造方法前先被执行。
* 且多个构造方法中相同的代码放在一起,每次调用都有执行,每次创造对象后,先执行构造代码块,再构造方法,再普通方法。
静态代码块 [优先于主方法前先被执行]
* 在类中方法外出现,加上static来做修饰,用于给类进行初始化的,在类加载的时候执行,有且只执行一次。
* 作用:
* 给类做初始化用的,一般用于加载驱动(驱动也加载一次)。
* 因为被static修饰的,所以静态代码块是随着类的加载而加载的,当在类加载时,static静态代码块就会被执行,因为类只加载一次,所以static一只加载一次。
* 无论创建多少个对象,static静态代码块都执行一次。
* 一般用于加载驱动的。
作业题一:
1、代码块是什么,分为哪几类,各自有什么特点?
含义:
* 在java中用{}扩起来的就称为代码块。
代码块分类:
* 静态代码块
* 局部代码块
* 构造代码块
* 同步代码块
各自特点:
* 静态代码块,在类中方法外,用 static 来做修饰,用于给类进行初始化用的,是随着.class 字节码文件的加载而加载的,优先于主方法先存在,随着类的消失而消失,一般用于加载驱动,且只能执行一次。
* 局部代码块,在方法中出现,用于限定变量的生命周期,可用于提高内存的利用率。
* 构造代码块,在类中方法外,多个构造方法相同的代码存放在一起,每次再调用构造方法前执行。
* 同步代码块,多线程再讲。
注意事项:
局部/构造/静态/代码块的执行顺序:
静态 > 局部 > 构造
例子:
参考:G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\Demo1_代码块_局部代码块.java
静态代码块,构造代码块,构造方法的执行流程?
静态代码块
* 当jvm加载.class字节码文件时,给类进行初始化的,且只执行一次。
构造代码块
* 在构造方法之前被执行。
构造方法
* 随着实例化对象的创建而执行,且每次创建对象,都执行一次构造方法,随着对象的释放而消失。
作业题二:
2、子父类都有静态代码块、构造代码块、构造方法,那么他们六者之间的执行流程是什么?
分析:
1) 因为子继承父,所以先执行父类的字节码文件,因为静态代码块是随着类的加载而加载的,所以第一步先执行:父类的静态代码块。
2)父类的静态代码块执行完成后,子类的字节码文件也同样加载到内存,所以第二步是:子类的静态代码块。
3)因为new的是子类的对象,又因为构造代码块是在构造方法之前执行的,且二者存在继承关系,所以第三步执行的是:父类的构造代码块。
4)执行完第三步:父类构造代码块后,紧接着执行第四步:父类的构造方法。
5)当父类的构造方法执行完后,开始执行子类的构造方法,因为构造代码块是在构造方法前执行的,所以第五步执行:子类的构造代码块。
6)当子类的构造代码块执行完后,开始执行子类的构造方法。
所以顺序是:
1)父类静态代码块
2)子类静态代码块
3)父类构造代码块
4)父类构造方法
5)子类构造代码块
6)子类构造方法
代码块面试题
分析程序中的代码的执行顺序?
例子:
根据 静态 > 局部 > 构造这个顺序来分析:
参考:G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\Demo2_Student_构造代码块面试题.java
b.
继承
概念
* extends 表示关键字,用于让类与类之间产生关系,只存在于子父类当中。(子继承父,不可父继承子)
* 他们是一种满足 is a的一种关系,如猫是动物的一种。
* java中只支持单继承,不支持多继承,但支持多实现和多层继承。
* 多层继承:子 继承 父, 父 继承 爷 ,子 继承 爷(子继承爷就是多层继承)
好处
* 提高代码复用性 (父类有了,子类就不需要再写了,继承即可)
* 提高代码维护性 (新添加属性,只要在父类中添加了,其他子类也就都有了)
* 让类与类之间产生关系,这是多态的前提 (多态:即多种形态) 因为要:父类有用指向子类对象。
弊端
* 增强了代码的耦合性,因为优秀的代码都是围绕着 “高内聚,低耦合”的原则去开发的。
(耦合性:两个类过分紧密,父类有什么,子类就必须有什么。)
开发原则
* 高内聚,低耦合(使用装饰者模式,就能降低耦合性)
* 内聚:自己完成某件事情的能力,耦合性低,之间能完成是事情不求他人。【公司离开你,还能活】
* 耦合:类与类之间的关系。【你离开公司,就不能活】
高内聚:自己能完成的事情,自己做。
低耦合:合作式开发,但是要主次分明。
p.s.
子类只能访问父类中非私有的成员(属性和方法)。
子类无法继承父类中私有的内容。
父类怎么来的? 共性内容不断向上抽象来的。
p.s.贝贝2017/8/19 1:07:35
作业题三:
3、继承的好处、弊端分别是什么?
好处:
* 提高代码复用性。
* 提高代码维护性。
* 让类与类之间产生关系,是多态的前提。
弊端:
增强了代码之间的耦合性,优秀的代码开发一直遵循的是一种 “高内聚,低耦合” 的一种开发规则。
高内聚:自己完成的事情,一般不求他人(在开发的意思是,本类能完成的功能尽量在本类完成,即本类完成功能的能力度。)
低耦合:合作式开发,但是要分清主次关系(一般开发规则有:分模块开发 和 分功能开发。)
装饰者模式
好处:降低耦合性,被装饰的类与装饰的类无关。
代码实现:
1. 获取被装饰类的引用
2. 在装饰类的构造方法中传入被装饰类的对象
3. 对原有功能进行升级
例
class Demo2_装饰者模式 {
public static void main(String[] args) {
HmStudent hm = new HmStudent(new Student());
hm.name="哈哈";
hm.age=22;
hm.study();
System.out.println(hm.name+"..."+hm.age);
}
}
//黑马学生 继承 学生类 且 实现 方法Coder类的接口。
//在实现接口类中,完成具体的方法实现。
class HmStudent extends Student implements Coder{
//1. 获取被装饰类的引用
private Student s;
//2、在装饰类的构造方法中传入被装饰类的对象
public HmStudent(Student s){
this.s = s;
}
public void code(){
//3. 对原有功能进行升级
}
//在实现接口类中,完成具体的方法实现
public void study(){
System.out.println("程序员敲代码.");
}
}
//接口 接口中定义的都是方法,且都是没有方法体的方法。
interface Coder{
public void study();
}
class Student {
String name;
int age;
}
继承特点
* java中只支持单继承,不支持多继承,但支持多实现(即实现接口)。
* 但有些语言可支持多继承,如: a类 extends c类,d类,e类...
原因?
* 因为多继承容易出问题,如果两个父类中有相同的方法,子类就不知道该具体调用哪一个方法了。
* 这种机制就换来了另一种安全的方式来体现,即多态。
* java中存在多层继承的关系(即继承体系)
* 子 extends 父
* 父 extends 爷
* 子 extends 爷
* 由继承的特点可看出:
* 如果想用这个体系的【所有功能】, 看【最底层(儿子类)的类去创建对象】【即子类是用于扩展的功能】
* 如果想用这个体系的【共性功能】, 看【最顶层(爷爷类)的类,即最先继承的类】
Java中继承的特点
* java中只支持单继承,不支持多继承,但支持多实现和多层继承。
* 当创建对象时:
如果是想要其共性部分,就去找顶层(即父类)
如果想要知道功能性最全的,就去找底层(即子类)
p.s.
子类中所有的构造函数默认都会访问父类中的空参构造函数,因为每一个构造函数的第一行都有一个默认的super语句,去访问父类的空参构造,即使一个普通类第一行也有一个super语句,因为他会去访问Object类。
为什么子类实例化的时候要去访问父类中的构造函数?
因为子类继承父类,获取到父类中的内容,所以在使用父类内容之前,要先看看父类是如何自己的内容进行初始化的。
1. 当父类中没有空参构造时,子类的构造函数必须通过this或super语句指定要访问的构造函数。
2. 子类构造函数中如果使用this调用本类的构造函数,那么默认的super就没有了,因为super和this不同同时定义在的第一行,所以只能存在一个,但是可以保证的是,子类中肯定有其他的构造繁琐去访问父类的构造函数
3. super必须存在子类的构造函数的第一行,因为父类的初始化动作要先完成。
作业题四:
4、Java中继承的特点是什么?
特点:
* Java只支持单继承,不支持多继承,但支持多实现和多层继承。
多实现:一个类可以实现多个接口。接口:后面说。
多层继承:子继承父,父继承爷,子继承爷,存在这种关系后,子继承爷就是多层继承了。
当创建对象时,
如果想要其共性部分功能,就找顶层(父类,即创建父类对象)。
如果想要其全部功能,就找底层(子类,即创建子类对象)。
例子
class Demo3_Extends继承的特点 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in); //in表示键盘录入的意思。
DemoC c = new DemoC();
c.show(); //结果是:DemoB
}
}
//最顶层的类 即爷爷类 有最完善的【共性功能】
//爷爷类
class DemoA {
public void show(){
System.out.println("DemoA ");
}
}
//父亲类
class DemoB extends DemoA {
public void show(){
System.out.println("DemoB ");
}
}
//最底层的类 即儿子类 有最完善的【全部功能】
//儿子类
class DemoC extends DemoB {
}
//不能让C类即去继承A类,也继承B类,这不符合Java对于继承的规定,
//只能【多层继承】,即通过 B extends A, 再让C extends B 来完成对A类和B类所有功能的继承。
//不能多继承的原因?有安全隐患,如果让C类同时继承A,B类,当创建C类对象时,就不知道该具体调用AB中哪个同样的show方法了。
//当C类去 extends B类(B 已经extends A了)时,创建C类对象后,c调用show()方法, 输出的结果是 :DemoB,因为 B extends A时,b中有同样有show方法,就将A中的show方法给覆盖了,所以打印c.show(),结果自然是DemoB。
继承的注意事项和什么时候去使用继承
注意事项:
* 子类只能继承父类所有(非)私有的成员[即成员方法和成员变量],因为私有成员只能在本类使用。 【但想继承也可以,通过暴力反射完成 最后一天课程说】
* 子类不能去继承父类中构造方法,但是可以通过super来访问父类的构造方法。
* 子类不能继承父类的构造方法?因为两个类的类名不同,且构造方法是在创建对象的时候使用的,如果继承了,系统在创建对象后,就不知道具体该调用哪个构造方法了。
* 不能为了部分功能去继承。
* * 项目经理 姓名 工号 工资 奖金
* 程序员 姓名 工号 工资
* 【只能向上抽取出来一个员工类,放共性功能,让项目经理类和程序员类都去继承该员工类即可】
什么时候使用继承:
不能为了单独继承而继承,他们之间是一种 is a的关系,只有满足了这种情况才考虑去使用继承。
即:
动物
猫
狗
(猫是动物的一种 狗是动物的一种) 即 is a 的关系。
水果
苹果
香蕉
桃子
(苹果是水果的一种 香蕉是水果的一种)即 is a 的关系。
采用假设法:
如果有两个类A,B 只有满足A是B的一种,或B是A的一种的时候,才考虑使用继承。
继承中局部变量的关系
情况一:
* 不同名的变量
* 在子父类中出现不同名变量,结果都输出。
情况二:
* 同名变量
* 在子父类中出现了同名变量,就采用就近原则,即子类当中有,就使用子类的。
【子父类中出现同名变量,只在讲课中有,开发中是不会出现的。因为子类继承父类,就是为了让子类去使用父
类中的成员,如果子类中都有了父类中同名的成员变量,就没有任何意义了。】
作业题五:
5、Java中继承的注意事项是什么?我们什么时候使用继承? 继承中局部变量的关系?
注意事项:
* 子类只能继承父类非私有的成员,如果子类或其他想要访问私有成员,必须使用get()方法进行访问。
什么时候使用继承:
* 不能为了部分功能去实现继承,只有他们满足一种 “is a” 的关系(苹果是水果的一种)时,才考虑使用继承,一般两个类或以上的类都满足 “is a” 的关系时,就向上抽取出父类,即公共类。
注意;子类不能继承父类的构造方法,只能通过super关键字去调用父类的构造方法,不然jvm无法识别使用是子类的构造方法还是父类的构造方法。
如:
子类:
名字:苹果,颜色:红,功能(方法):补充营养。
名字:香蕉,颜色:黄,功能(方法):利肠道。
因为存在多个重名属性,即向上抽取父类:
父类:
* 相同属性:名字 和 颜色。
* 方法:功能(食用保持身体健康)。
且在子类中重写方法,完成其特有的功能即:
* 子类苹果:补充营养。
* 子类香蕉:利肠道。
继承中局部变量的关系:
同名变量名称:
采用就近原则,谁离子类进,就使用哪个,即就近原则。
异同变量名称:
如果是异同变量名称,结果都输出。
c.
this和super的区别和使用
this
* 代表当前对象的引用,即谁来使用我,我就代表谁。
super
* 代表当前对象父类的引用,即子类继承父类后,想要去使用父类的成员时,可
* 使用super。
p.s.
子父类中,成员的特点体现:
1)成员变量:
* 在本类中成员变量和局部变量可以用this来区分, this表示成员变量。因为局部变量一般在方法里或方法声明上。
* 当子父类中出现同名成员变量时,可以用super来区分父类。
2)成员方法:
* 当子父类中出现成员方法一模一样的情况的时候,会运行子类中的方
法,这种现象被称为:覆盖操作(重写)。这是方法在子父类中的特性。
* 在子类覆盖(重写)父类方法后,还想继续使用被覆盖的父类方法时,可以通过super.方法名()来获取。
方法的两个特性:
1) 重载,只出现在本类中,即overload。
2) 重写,出现在子父类当中,即override。 有道词典翻译: vt. 推翻;不顾;践踏
this和super的使用区别 (3种区别)
* 调用成员变量
* this.成员变量 即可调用本类的成员变量,也可调用父类的成员变量。
* 前提是本类当中没有,才能去使用父类的,因为他们存在继承关系。
* super.成员变量 只能调用父类中的成员变量。
* 调用构造方法
* this(语句) 只能调用本类的构造方法
* super(语句) 只能调用父类的构造方法
* 调用成员方法
* this.成员方法() 即可调用本类的成员方法,也可调用父类的成员方法
* super.成员方法() 只能调用父类的成员方法
继承中构造方法的关系(继承中构造方法的执行流程)
* 子类中所有的构造方法默认都会去访问父类中的空参构造。【前提:必须是继承关系】
* 为什么?
* 因为子类继承父类中的数据,还可能会去使用到父类中的数据,所以子类在完成初始化之前,一定会
去完成对父类数据的初始化。
其实
每个构造方法的第一句默认都是调用:super()。 Object类是最顶层的父类,所有的类都继承他,自定义的类也一样继承他。
子类中的构造方法都有一个默认的super(),去访问父类的空参构造。
原因?
因为子类继承父类的属性,很可能会去访问父类中属性的数据,所以要必须先对这些属性进行初始化,才能去访问父类的构造方法。
继承中构造方法的注意事项
父类没有无参构造,子类该怎么办?
* super解决 可在在子类中,调用父类中的无参构造。(也能调用父类的有参构造)
* this解决 可在在子类中,调用本类的有参构造。
【注意】
super()或this必须出现在构造方法的第一条语句上,不能同时出现。
但是在普通方法中this.父类方法()和 super.父类方法() 可以不用放在第一行。
具体可参考:G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\day08_最新作业代码\Work3_存在继承关系的猫咪_狗狗类.java 中的Dog lookHome()方法里的写法。
作业题六
6、this关键字和super关键字分别代表什么,以及他们各自的作用分别是什么?
分别代表:
this 代表当前对象的引用,谁使用我,我就代表谁,即哪个对象使用this,this就代表哪个对象。
super 代表当前对象父类的引用,用于在子类中去访问父类的成员及构造。
this 和 super 的区别:(3种)
* 调用成员变量
this 既能调用父类的成员变量,也能调用子类的成员变量。
super 只能调用父类的成员变量。
* 调用成员方法
this.成员方法 既能调用父类成员方法,也能调用子类成员方法。
super.成员方法 只能调用父类的成员方法
* 调用构造方法
this 只能调用子类的构造方法
super 只能调用父类的构造方法
作业题八
(没有7)8、继承中构造方法的执行流程是什么?
执行顺序:
先执行父类中的构造方法,再执行子类中的构造方法。
作业题九
9、为什么子类中所有的构造方法默认都会访问父类的空参构造?
假如父类没有无参构造方法,子类应该怎么办?
答:
问题一:因为在子类对象在访问父类数据前,用于对父类数据进行初始化的。
问题二:如果父类中没有无参构造,可在子类中使用super();来访问父类的有参构造,或使用this();来调用本类的其他构造。
作业题十
10、super关键字和this关键字可以在构造方法中共存吗?
额可以,只能放在第一行,如果是其他普遍方法,super或this可以不用放在第一行。
子类{
super(); //调用的是父类的构造。
this.setName(name); //因为存在继承关系,所以也就相当于调用子类的set方法
}
继承中的面试题
看程序写结果1
class Fu{
public int num = 10;
public Fu(){
System.out.println("fu");
}
}
class Zi extends Fu{
public int num = 20;
public Zi(){
super(); //有个隐藏的super();每个构造方法中都有一个默认的super,去调用父类的完成构造方法
System.out.println("zi"); // num=20;
}
public void show(){
int num = 30;
System.out.println(num); //采用就近原则 即30
System.out.println(this.num); //this是用于区分重名的成员变量和局部变量,这里的this表示成员变量,即20
System.out.println(super.num); //super调用是的父类的成员变量,即10
}
}
class Test1_Extends {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
执行顺序:
fu 1)首先Zi(),会去调用zi的无参构造,因为zi的无参构造中有super(),所以先去调用父类的无参构造,即fu。
zi 2)输出fu后,zi()中的无参构造里还有一个语句,即:zi。
30 3)接着调用z的show()方法, 第一个输出语句num,即采用就近原则,所以num=30。
20 4)this.num 是访问重名的成员变量和局部变量时,用来访问成员变量用的,即:this.num=20。
10 5)super.num 中的super是访问父类的,所以super.num = 10;
看程序写结果2
class Fu {
static {
System.out.println("静态代码块Fu");
}
{
System.out.println("构造代码块Fu");
}
public Fu() {
System.out.println("构造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("静态代码块Zi");
}
{
System.out.println("构造代码块Zi");
}
public Zi() {
System.out.println("构造方法Zi");
}
}
Zi z = new Zi();
结果: 静态代码块Fu 1)因为创建的是zi()的无参对象,又因为zi继承fu,所以fu类先加载到内存,即 先输出:静态代码块Fu。
静态代码块Zi 2)又因为创建时zi类的对象,所以zi类也要加载到内存,即输出:静态代码块Zi
构造代码块Fu 3)访问zi的无参构造对象时,必须要先访问父类的无参构造,又因为无参构造是在构造代码块后面出现的,所以先输出:构造代码块Fu
构造方法Fu 4)随着构造代码块的输出后,再输出无参构造。
构造代码块Zi 5)只有先访问完父类的无参构造时,再能访问子类的无参构造,因为构造代码块时先于构造方法前先执行的,所以先输出:构造代码块Zi
构造方法Zi 6)构造代码块输出后,才能输出构造方法,所以是:构造方法Zi
老师说法:
1) jvm调用main方法, 方法都进栈,所以main方法进栈。
2) 首先遇到Zi z = new Zi(),因为zi类继承父类,所以会先将fu.class和zi.class分别加载到内存,当fu.class加载进内存时,静态代码块也会随着fu.class一起加载, 当zi.class加载进内存时,静态代码块也会随着zi.class一起加载。所以第一个输出:静态代码块Fu 第二个输出:静态代码块Zi
3) 加载完后,走zi类的构造方法,因为java是分层初始化的(在子类的构造方法中,每个子类中都有一个super),所以先去走父类的构造方法, 但是在执行父类构造时,发现父类有构造代码块,构造代码块是优先于构造方法前先执行的,所以第三个输出的是:构造代码块Fu 第四个输出的是:构造方法Fu。
4) fu类初始化后,就该子类初始化,所以第五个输出是:构造代码块Zi 第六个输出的是:构造方法Zi
原则:
* 静态代码块是,随着类的加载而加载的。
* 构造代码块先于构造方法前先被执行。
顺序:
静态代码块 > 构造代码块 > 构造方法
继承中成员方法的关系
--出现的情况:
* 不同名方法时:
* 都能够调用,即可调用父类中的方法, 也能调用子类中的方法
* 同名方法时:
* 如果子类定义了父类中重名的方法, 就使用子类中的方法,这种叫【方法的重写或覆盖】
* 如果还想使用父类中重名的方法的话,可以在子类中重名方法里的
第一行使用:super.父类重名成员方法(); 即可完成对父类重名方法的调用。
d.
方法的重写
概述
在子父类中出现了一模一样的方法(返回值类型可以是子父类,面向对象再说)【方法名,返回值相同,参数列表一样理解为方法的重写】
应用
当子类需要父类中的功能,而功能的主题子类自己特有的内容时,可以重写父类中的方法,这样既延续了父类功能,也完成了子类的特殊性。如果在子类重名方法中还想使用父类中的重名方法,可以通过super.父类方法();来调用即可,该方法可以不用放在第一行,只有在构造方法中super才只能放在第一行。
为什么使用继承和重写
主要是为了系统的升级和功能的扩展。
【注意:只有在构造方法中super只能放在第一行,其他方法中使用super可以不再第一行】
【Java采用的是Unicode的编码,Unicode的编码容纳了世界上的所有语言,所以支持中文编写程序,但一般建议不使用中文。】
例子:
G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\02_继承\Demo6_方法的重写.java
重写注意事项 (4个)
1. 子类不能继承父类私有的方法
* 因为父类中的私有方法,无法被其他类所继承。
2. 子类重写父类时,访问权限不能低于父类(即子类>=父类的访问权限) (public最大)
* 因为定义子类是希望子类比父类更加强大。如果子类权限比父类越来越小,最终会导致子类无法被使用(即子类无法被当成父类被其他类所继承)。
* 最好权限修饰符一致,如果父类没有权限修饰符,子类也可不写
3. 父类中的静态方法,子类也必须通过静态方法来实现重写
* 静态只能覆盖静态,非静态不能覆盖静态,且静态也不能覆盖非静态,因为jvm无法识别去调用具体哪个方法 其实这种形式不属于方法的重写,多态中再具体解释。
4. 子类重写父类方法,最好声明一模一样
方法重写面试题
over:之前,理解为再此之前。
ride:推翻
load:装填
override: 再此之前推翻原先的,即重写。 只能出现子父类中
overload: 再此之前装填更多的,即重载。 只能出现本类中
重载(overload[装填])和重写(override[推翻])的区别 (2个)
* overload(重载): 只能在本类中,出现了方法名相同,与返回值类型无关,只看参数列表的形式。
* override(重写): 只能出现子父类中,出现了方法名相同,且与返回值类型有关的。
重载:本类中出现方法名相同,且与返回类型无关,只看参数列表的方法。
重写:子类中出现了父类中一模一样的方法,且与返回值类型有关,返回值类型一致的或是父类。
* overload(重载) 能改变返回值类型,方法名相同,与返回值类型无关,只看参数列表。
* override(重写)不能改变返回值类型(方法名和参数列表必须相同,多态再具体说明) 返回值类型可以是父类。
p.s.
方法的两个特性:
1) 重载,只出现在本类中, 即overload。
2) 重写,出现在子父类当中,即override。
子类调用方法的顺序:
先找本类,再找父类。(就近原则)
p.s.
什么时候使用重写重载?
当子类需要父类功能,当功能主体是子类特有的内容是,就可以覆盖父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
* 父类中私有成员不能被重写。
* 父类中static的方法不能被重写。
* 重写时,子类方法权限必须大于或等于父类方法权限。
作业题十一
11、Overload和Override的区别是什么?方法重载能改变返回值类型吗?
overload 是重载,只能出现在本类当中,规则:方法名相同,与返回值类型无关,只看参数类别的一种形式,且能改变返回值类型。
override 是重写,只能出现在子父类当中,在继承关系中,出现了子父类规一模一样的方法就是重写,规则:必须方法名相同,返回值类型相同,参数列表也相同的一种形式,且无法改变返回值类型。
overload 重载 可以改变返回值类型。
orveride 重写 无法改变返回值类型。
继承中的细节问题
案例1:
* A:案例演示
* 使用继承后的学生和老师案例
* 使用继承后,增强了代码复用性,减少了代码的冗余。
* 分析:
* a.首先将两者的共性抽取出来,创建一个共性父类Person,封装其共性属性,完成共性内容。
* b.然后创建子类学生和老师,让他们去继承Person父类。
* c.然后在学生和老师中完成特有的功能。
* d.两种赋值方式:setXXX() 和 new对象实际传参。
this.getName() 是子类继承了父类,相当于本类中也有了this.name = name;
super.getName() 是子类去直接调用了父类中的方法。
getName() 是隐藏了this,其实还是this.getName();
该例子必须去看看。
地址:
G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\02_继承\Test2_使用继承后的学生和老师案例.java
案例2:
* A:猫狗案例分析
* B:案例演示
* 猫狗案例继承版
* 属性:毛的颜色,腿的个数
* 行为:吃饭
* 猫特有行为:抓老鼠catchMouse
* 狗特有行为:看家lookHome
分析:
1. 将两者共性内容,抽取出来放入父类Animal中,完成共性属性和内容。
2. 再创建子类猫,狗分别去继承父类Animal
3. 再在子类中完成其特性部分。
子类中有参构造方法的写法:
*可通过super(name, age); 去调用父类中的有参构造。super是本类对象父类的引用。
子类中属性的访问可使用3种形式:
* getName(); 该方法隐藏了this, 因为存在继承关系,所以访问的相当于也是本类的 this.name = name;
* this.name(); 因为存在继承关系,所以访问的相当于也是本类的 this.name = name;
* super.name(); super是本类对象父类的引用,所以直接就是调用父类中的getName()的方法。
地址:
G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\02_继承\Test3_猫狗案例分析和实现及测试.java
e.
final关键字
概述
final是关键字,翻译为 "最终",只要被final修饰的,都不能修改和继承。
应用
* 修饰类时,类不能被继承,但能继承其他类。
* 如: public final class Animal{}
* 修饰方法时,方法不能被重写。
* public final void method(){}
* 修饰成员变量时,变量变常量,要求所有字母大写,多个单词用下滑线隔开,【且只能被赋值一次,且必须赋初始化值,不能为空。】
* final int AGE = 4; (不能被修改的常量)
* public static final int LEG =3; (静态且不能改变的常量)
* final修饰的变量叫常量,所有字母都大写,一般和public static 一起被使
用,即:public static final String NAME="张三";
例子:G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\04_final\Demo1_final_关键字概述.java
作业题十二
12、final关键字可以做什么,有什么特点?
含义:
final 是关键字,被翻译为 最终,可用于修饰类,变量,方法。
特点:
修饰类时,该类不能被继承,但可以继承其他类。
修饰变量时,变量变常量,必须初始化,不能为空和只能被赋值一次,即所有字母大写,如果存在多个单词,用下滑写将每个单词隔开,一般和 public static 一起使用,即 public static int AGE =7;。
修饰方法时,该方法不能被其他类重写。
作业题十三
13、final修饰局部变量时,有什么特点?
有两种情况:
当局部变量是 基本数据类型:其值不能被改变。
引用数据类型:地址值不能被改变,但对象中的属性值能被改变。
注意事项
A:案例演示
* 方法内部或者方法声明上都演示一下(了解)
* 修饰局部变量
* 基本数据类型: 值不能被修改。
* 引用数据类型: 只是地址值不能被改变,但对象的属性值是可以改变。
//方法内部
基本数据类型:
final int a = 3;
a=10;
sop(a);//3 因为final修饰基本数据类型,其值不变。
引用数据类型:
final Person p = new Person("呵呵",7);
p = new Person("哈哈", 13); //直接报错,因为被final修饰的对象,即就是地址值,不能被重新赋予一个新的地址值。
但可以:
p.setName("楚乔");
p.setAge(6);
sop(name, age); //结果:楚乔 6 ,因为被final修饰的引用数据类型,其对象的属性值是可以改变的,但地址值是不能改变的。
//方法声明上
method(5); //5
method(6); //6 最终值改变,因为每个方法都是调用完后,都弹栈,下一个方法进来是新的方法即新的属性值,所以值是改变的。
例子:
G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\04_final\Demo2_final_局部变量的注意事项.java
final修饰变量的初始化时机
* 必须显示初始化。
* 在对象的构造方法完毕前完成初始化即可。
例子:
G:\CSDN_Android_\Code\day08 代码块 继承 重写 this和super final关键字\04_final\Demo3_final_修饰变量的初始化时机.java
p.s.
为什么要用final来修饰变量,其实在程序中如果有一个数据是固定的,那么直接使用这个数据就可以了,但是这样的阅读性差,所以要给这个数据起个名字,而且这个变量名称的值不能任意改变,所以要加上final来固定。
写法: 常量所有字母大写,多个单词,中间用_来隔开。