一.代码块
1.含义
用{}括起来的代码
2.分类
局部代码块
用于限定变量的生命周期,及早释放,提高内存利用率
静态代码块
对类的数据进行初始化,仅仅只执行一次
构造代码块
多个构造方法中相同的代码可以放到这里,每个构造方法执行前,先执行构造代码块
同步代码块
3.静态代码块,构造代码块,构造方法的执行顺序?
静态代码块 –> 构造代码块 –> 构造方法
代码示例
/*
代码块:在Java中,使用{}括起来的代码被称为代码块。
根据其位置和声明的不同,可以分为
局部代码块:局部位置,用于限定变量的生命周期。
构造代码块:在类中的成员位置,用{}括起来的代码。每次调用构造方法执行前,都会先执行构造代码块。
作用:可以把多个构造方法中的共同代码放到一起,对对象进行初始化。
静态代码块:在类中的成员位置,用{}括起来的代码,只不过它用static修饰了。
作用:一般是对类进行初始化。
面试题?
静态代码块,构造代码块,构造方法的执行顺序?
静态代码块 -- 构造代码块 -- 构造方法
静态代码块:只执行一次
构造代码块:每次调用构造方法都执行
*/
class Code {
static {
int a = 1000;
System.out.println(a);
}
//构造代码块
{
int x = 100;
System.out.println(x);
}
//构造方法
public Code(){
System.out.println("code");
}
//构造方法
public Code(int a){
System.out.println("code");
}
//构造代码块
{
int y = 200;
System.out.println(y);
}
//静态代码块
static {
int b = 2000;
System.out.println(b);
}
}
class CodeDemo {
public static void main(String[] args) {
//局部代码块
{
int x = 10;
System.out.println(x);
}
//找不到符号
//System.out.println(x);
{
int y = 20;
System.out.println(y);
}
System.out.println("---------------");
Code c = new Code();
System.out.println("---------------");
Code c2 = new Code();
System.out.println("---------------");
Code c3 = new Code(1);
}
}
二.继承
1 .含义
把多个类中相同的成员提取出来,定义到一个独立的类中,然后让这多个类和该独立类产生一个关系,使这多个类也具备这些内容,这个关系就叫继承
2.格式
Java用关键字 extends 表示
格式: class 子类名 extends 父类名 { }
3.好处
提高了代码的复用性
提高了代码的维护性
让类和类产生关系,是多态的前提
4.弊端
开发原则: 高内聚,低耦合
内聚: 自己完成某件事的能力
耦合: 类和类的关系
(1).让类的耦合性增强,这样这个类改变,就会影响其他的相关类
(2).打破了封装性
5.特点
(1).Java只支持单继承,不支持多继承
有些语言是支持多继承,格式:extends 类1,类2,…
(2).Java支持多层继承(继承体系)
6.注意事项
(1).子类不能继承父类的私有成员
(2).子类不能集成父类的构造方法,但可以通过super去访问
(3).不要为了部分功能而去继承
7.使用时机
继承其实体现的是一种 is a 的关系
采用假设法: 如果有两个类A,B.如果符合A是B的一种,或B是A的一种,就可以考虑使用继承
8.继承中成员的关系
(1).成员变量
子类的成员变量名称和父类的成员变量名称一样,如何访问?子类的方法访问变量的查找顺序?
在子类方法的局部范围找,有就使用。
在子类的成员范围找,有就使用。
在父类的成员范围找,有就使用。
找不到,就报错。
(2).构造方法
子类中所有的构造方法默认都会访问父类中空参数的构造方法
因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。
注意:子类每一个构造方法的第一条语句默认都是:super();
父类如果没有构造方法,那么子类的构造方法会报错,如何解决?
a.让父类提供无参构造
b.子类通过super去明确的调用父类的带参构造方法
c.子类通过this调用本类的其他构造方法,子类中一定要有一个去访问了父类的构造方法,否则父类数据就没有初始化。
注意事项
this(…)或者super(…)必须出现在第一条语句上。如果不是放在第一条语句上,就可能对父类的数据进行了多次初始化,所以必须放在第一条语句上。
(3).成员方法
子类的成员方法名称和父类的成员方法名称一样,如何访问?子类对象调用方法的顺序是?
先找子类中,看有没有这个方法,有就使用
再看父类中,有没有这个方法,有就使用
如果没有就报错。
9.this和super
区别
this: 代表本类对应的引用
super: 代表父类存储空间的标识(可以理解为父类引用,可以操作分类成员)
如何使用?
( 1). 调用成员变量
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量
(2). 调用构造方法
this(…) 调用本类的构造方法
super(…) 调用父类的构造方法
(3). 调用成员方法
this.成员方法 调用本类的成员方法
super.成员方法 调用父类的成员方法
10.Override和Overload
Override 方法重写:
含义
在子类中,出现和父类中一模一样的方法声明的现象。
注意事项:子类重写父类方法的时候,最好声明一模一样。
a.父类中私有方法不能被重写,因为父类私有方法子类根本就无法继承
b.子类重写父类方法时,访问权限不能更低,最好就一致
c.父类静态方法,子类也必须通过静态方法进行重写
Overload 方法重载:
含义
同一个类中,出现的方法名相同,参数列表不同的现象。
注意事项
参数列表不同包含: 参数名称,参数类型,参数个数
方法重载能改变返回值类型,因为它和返回值类型无关。
11.final
(1).含义
由于继承中方法有一个现象:方法重写。所以,父类的功能,就会被子类给覆盖调。
有些时候,我们不想让子类去覆盖掉父类的功能,只能让他使用。
这个时候,针对这种情况,Java就提供了一个关键字:final
(2).用法
可以修饰类,方法,变量。
(3).特点
final可以修饰类,该类不能被继承。
final可以修饰方法,该方法不能被重写。(覆盖,复写)
final可以修饰变量,该变量不能被重新赋值。因为这个变量其实常量。
(4).面试相关
final修饰局部变量的问题
基本类型:基本类型的值不能发生改变。
引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。
final修饰变量的初始化时机
被final修饰的变量只能赋值一次。
在构造方法完毕前即定义的时候。(非静态的常量)
12.数据初始化相关面试题
代码示例(1)
/*
看程序写结果:
A:成员变量 就近原则
B:this和super的问题
this访问本类的成员
super访问父类的成员
C:子类构造方法执行前默认先执行父类的无参构造方法
D:一个类的初始化过程
成员变量进行初始化
默认初始化
显示初始化
构造方法初始化
结果:
fu
zi
30
20
10
*/
class Fu{
public int num = 10;
public Fu(){
System.out.println("fu");
}
}
class Zi extends Fu{
public int num = 20;
public Zi(){
System.out.println("zi");
}
public void show(){
int num = 30;
System.out.println(num); //30
System.out.println(this.num); //20
System.out.println(super.num); //10
}
}
class ExtendsTest {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
代码示例(2)
/*
看程序写结果:
A:一个类的静态代码块,构造代码块,构造方法的执行流程
静态代码块 > 构造代码块 > 构造方法
B:静态的内容是随着类的加载而加载
静态代码块的内容会优先执行
C:子类初始化之前先会进行父类的初始化
结果是:
静态代码块Fu
静态代码块Zi
构造代码块Fu
构造方法Fu
构造代码块Zi
构造方法Zi
*/
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");
}
}
class ExtendsTest2 {
public static void main(String[] args) {
Zi z = new Zi();
}
}
代码示例(3)
/*
看程序写结果:
A:成员变量的问题
int x = 10; //成员变量是基本类型
Student s = new Student(); //成员变量是引用类型
B:一个类的初始化过程
成员变量的初始化
默认初始化
显示初始化
构造方法初始化
C:子父类的初始化(分层初始化)
先进行父类初始化,然后进行子类初始化。
结果:
YXYZ
问题:
虽然子类中构造方法默认有一个super()
初始化的时候,不是按照那个顺序进行的。
而是按照分层初始化进行的。
它仅仅表示要先初始化父类数据,再初始化子类数据。
*/
class X {
Y b = new Y();
X() {
System.out.print("X");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y = new Y();
Z() {
//super
System.out.print("Z");
}
public static void main(String[] args) {
new Z();
}
}