java自学之路-day09
JAVA09
构造方法
引入
- 之前我们创造 人这个类 然后在给他赋予姓名和年龄 这样是滞后性
- 人这个类 出生时就应该有姓名和年龄 所以有了构造方法
- 建立对象的同时明确对象的属性
- 使用new创建对象时给对象赋初值
- 实现这个功能用方法去实现 构造方法 Constructor
- 在new的同时对成员变量进行赋值
- 权限 方法的名字(参数列表){
介绍
定义格式
}
- 不允许写返回值类型 void 也不能写
- 方法名和类名保持一致
- 新建对象时运行就会执行构造方法
- 每个class必须有构造方法,构造方法不写也有
- 编译的时候 javac 会自动 检查类中是否有构造方法
- 如果有就用自己写的,没有就会自动添加一个
- 有参构造器
构造方法默认添加
构造方法赋值
权限 方法名(参数 ){
this.变量名=变量名;
}
构造方法内存图
- main 方法进入栈内存
- 实例化person
- 新建的对象进入堆内存 成员变量跟随进入堆内存并初始化成员变量
- 对象自动调用自己的构造方法
- 构造方法进入栈内存 对传递过来的参数传入构造方法
- 并且把内存地址传递过来 然后根据地址把变量进行赋值
- 构造方法退栈 整个对象此时才完成初始化
- 然后继续执行main方法里面的内存
- main方法退栈
- 整个程序结束
构造方法重载
- 参数列表不同
- 两个构造方法
- 新建对象时任意调用一个构造方法
- 构造方法可以修改权限 改为private 就不能创建不带参数对象了
- 定义 没有void
- 调用 创建对象时执行 只执行一次
- 需要get set吗 需要 因为需要来进行赋值或者获得值
- 在构造方法之间调用
- 之前用于局部变量和成员变量
- 语法格式 this();
- 两个构造器是能用来成员变量赋值 一个空参数 一个有参数
- 无参数构造器 调用有参构造器方法 在无参构造器中写 this(”李四”,20);
- this()必须放在第一行
- 内存图
构造器和一般方法的区别
This关键字
a) main方法压栈运行
b) 开始新建对象
c) 对象进入堆内存 初始化成员变量值
d) 对象调用空参构造方法
e) 空参构造调用了有参数的构造并且传递了实际的参数
f) 有参构造压栈运行 获得参数进行赋值 用this.的地址也就是对象的的地址进行赋值
g) 对象中的赋值完毕 有参数构造器出栈
h) 无参数构造出栈
i) 对象建立完成
j) T
- This简单应用
a) 没有重名的成员变量可以不加
b) 是否为同龄人
Super关键字
- 在子父类的构造方法之间调用
- 子类调用父类构造方法 两个类的问题
- Super();
- 父类不能调用子类
- 继承了父类的子类没有构造方法却调用了父类的构造方法 因为子类构造方法第一行有一个隐式代码 super();为了调用父类构造方法
- 子类需要知道父类构造方法怎么初始化赋值父类变量
- 内存图
方法区子类现金方法区还是父类 子类自动拥有父类成员 因此父类先进入
a) 父类先进入方法区
b) 子类进入方法区
子类继承父类 内存很大 需要寻找父类 因此用Super表示父类存储位置
c) 测试类进入方法区
d) main方法进入方法栈
e) 开始创建子类对象
f) 对象进入堆内存中 子类对象空间划分为两个区域 一个留给父类 一个留给自己
g) 自己使用的空间 this 没有成员变量 父类的空间 super 父类的成员变量进入对象堆内存 此时为默认值a=1(初始赋值)
h) 调用子类构造器
i) 子类构造器进栈运行
有一个super() 调用父类构造器
j) 父类构造器进栈运行
也有一个super()【继承Object类】
k) 父类进行a赋值,根据子类对象空间中的地址进行赋值
l) 父类构造器执行完毕 退栈
m) 子类构造器 退栈
n) 子类对象建立完成
- o) 子类对象将地址引用赋给对象变量
p) 变量直接调成员变量a
q) 子类对象中子类空间没有 然后就调用子类对象中父类空间的a
r) 然后输出
s) 然后main方法退栈
t) 整个结束
即使父类成员变量改为私有 即private 也会存在于子类对象的堆内存空间中
- super扩展2
a) 父类构造方法带参数 子类继承报错
原因:找不到父类的空参数构造器
b) 子类没有构造器 但是默认构造器中有super(),会找父类空参构造器 但是父类没有无参构造器
c) 因此需要在子类中手动写一个构造器 修改为super(父类参数类型的参数)
d) 子类中的重载构造方法 也需要更改 否则也会编译失败
e) 父类有多个重载构造方法 子类 super(参数) 任选一个就可以
f) 构造方法无法继承 子类无法重写
g) Super语句位于构造方法的第一行
- 扩展3
a) 构造方法第一行 不能同时写super() 和this()
b) 必须保证子类的所有构造方法调用到父类的构造方法(直接间接)
c)
d) 父类构造器也有super 继承object类 调用object类的构造器 object类构造器没有super因为他没有父类
- Super应用
- 练习 学生和工人
练习
It工程师改造
通过用构造方法的改造
修改变动小 有利于程序的扩展性 维护性
总结
l this
- 在方法中使用 谁调用了方法 this就代表谁 代表该方法的对象引用
- 当创建对象时this就存在
- 区分成员变量和局部变量
- Ctrl t 打开继承关系图
l 构造方法
- 定义格式 不能写 void
- 可以写return;但没有意义
- 创建对象时被调用 只调用一次
l Super
- 父类存储空间(理解为父类的引用,在子类对象空间中)
- 手动写了构造器 编译器不会创建 没有手写就会默认创建 第一行是super()
- 最好手动写为了避免出错
- 通过this调用本类中其他调用了父类的构造方法可以间接调用父类
- 不能同时存在 this 和super
- 概念引入
- 继承提高了代码的复用性
- 有些类不想被继承
final关键字
方法不想被重写
变量不想改变
- 可以用final
- 例如String类 不能被继承
- 特点
- 修饰类
a) 最终类
b) 没有子类 不能被继承
c) 但其他正常 可以定义方法 可以新建对象
- 修饰方法
a) 子类继承能调用
b) 但不能被重写
- 修饰变量
a) 修饰一次终生不可变
b) 修饰引用变量 变量保存的内存地址将永远不变 不能再被new 创建指向 也不能被赋予空
c) 举例 比如圆周率 固定保留多少位小数
- 修饰成员变量
a) Final修饰的成员变量,固定的不是内存的默认值 而是手动赋予的值
b) 可以手动赋值 也可以用构造方法赋值
c) 不能用set 方法赋值 set方法在建立对象后使用
d) 因为需要在创建对象前赋值否则报错
Static关键字
l 概念引入
- 之前定义的类中的方法和属性都是通过创建对象调用的
- 为了实现对象的共享数据
- 在变量前加入static
- 只是为了调用方法创建对象 没有访问到对象中的特有数据
- 为了可以直接调用该类中的方法
l 修饰特有数据
- 可以被类的名字直接调用 类名.变量名
- 变为共享类
l static内存图
- test类的.class文件进入方法区 先加载自己的静态成员main方法
- 静态成员main进入数据共享区(静态区),并且属于test这个类名
Javac xx.class (是文件)
Java xx(类名)
因为是静态是类名而不是文件名
- Person类文件进入方法区 加载静态成员 变量classname
- 变量classname进入方法共享区 赋予默认值null
- 开始执行运行main方法,jvm到静态区将main方法赋值一份压栈执行
- 执行输出person静态变量
- Jvm到数据共享区(静态区)找到属于person类的静态属性classname
- 然后输出
此时没有创建对象,内存中说明静态优先于非静态存在的
- 新建对象 对象进入堆内存
l 静态不能直接调用非静态
- 静态方法中不能调用非静态变量
- 原因: 静态生命周期(先人)优先于非静态生命周期(后人)位于内存
- 静态方法中不能写this 和super
原因:this和super表示本类对象引用和父类对象引用,由于静态先于一切存在,所以不能调用没有创建的
- 非要调用 就只能新建对象进行调用
l 使用场景
- 修饰成员变量和成员方法
- 成员变量
- 根据具体的事物进行使用
- 定义事物时,多个事物中是否有共性的数据
- 方法
- 跟着方法走
- 需要调用非静态时不能加静态
l 对象中的静态调用
- 成员变量看变量引用 是父类则调用父类
- 多态调用中
编译看父类 父类有编译成功 父类没有编译失败
运行 静态方法 运行父类中的静态方法
运行 非静态方法 运行子类的重写的方法
承成员变量 编译运行都看父类
- 原因
静态属于类不属于对象
对象的多态性 静态和对象无关 父类的引用.静态方法
直接可以用类名调用与后面new的子类对象无关
l 静态常量
- public static final 变量名
- 变量名全部大写
- 接口中的每个成员变量都是静态常量
匿名对象
l 概念
- 只有创建对象的语句 没有把对象地址值赋值给某个变量
- 只有 new 类名();
- 只能使用一次
l 特性
- 没有引用变量
- 只能使用一次 可以使用
- 例如 Scanner
- 频繁使用 资源浪费
- 可以当做参数传递
- 可以做返回值
内部类
l 概念
- 写在其他类的内部 可以是其他类的成员位置和局部位置
- 汽车类{发动机}
- 成员内部类 和 局部内部类
- 看成成员变量但本质是个类
l 定义
- Outer 外部类 Inner内部类
- 成员内部类可以使用成员修饰符
- 可以继承和实现接口
- 编译后的文件
- 调用格式
a) 内部类可已使用外部类成员 包括私有
b) 外部类使用内部类成员 需要建立内部类对象
c) 调用外部类中内部类的方法
i. 依靠外部类对象找到内部类
ii. 再通过内部类对象调用内部类方法
iii. 外部类名.内部类名 变量=new 外部类对象.new 内部类对象();
iv. 变量.方法名
l 成员内部类的同名变量调用
- 用this调用内部类成员变量 this.
- 用 外部类.this.变量名 调用外部类成员变量
- 外部类的方法里面建立的内部类
- 编译后的文件
- 相比内部类增加了个 1 因为可能还会有第二个方法内部类
- 调用局部内部类的方法
局部内部类
方法是无返回值 需要创建好一个内部类对象 并且调用内部类的方法
l 匿名内部类 内部类的实际使用
- 引入
内部类是为了应对跟更为复杂的类间关系 源代码中会涉及到 一般不会遇到,真正实际的应用是匿名内部类
- 概念
a) 是常用的内部类 是局部类一种
b) 临时定义某一指定类型的子类
c) 定义后马上创建刚刚定义的这个子类的对象
d) 前提是继承一个类或者实现一个接口
e) 智能写在方法中
- 调用
a) 之前调用接口的实现方法
接口
实现类
实现类对象 调用
多态对象 调用
太复杂
b) 匿名内部类简化了以上过程
c) 公式
new 接口或者父类(){
重写抽象方法
};
创建了接口的实现类的对象
d) 编译后的文件
e) 调用方法
new 接口或者父类(){
重写抽象方法
}.方法名();
- 练习
孔子的爸爸 同时调用两个方法
ConfuciusFatcher c=new ConfuciusFatcher() {
@Override
public void goClass() {
System.out.println("论语");
}
@Override
public void extral() {
System.out.println("LOL");
}
};
c.getClass();
c.extral();
包
l 概念
- 就是我们说的文件夹
- 包里面放的是类文件
- 项目中功能相同的类放在一个文件夹中
- 方便管理
- 项目分工也是以包为边界的
- 源文件 bin目录 和编译后class文件 src目录 的文件夹是一致的
- 分类管理
l 声明
- 公司网址反写
- 包名全部小写
- 关键字package
- Java源码包也是分类管理
util 工具包
io io流
net 网络编程
sql
lang 核心包(System 类 String类)
l 导包
- Lock包
- 导入最里面的包
- Ctrl shift o 自动导包
- 有了包之后 类的全名 加上包名
- 右键 copy qualifiled name
修饰符
l Public 最大权限
l Private 最小权限
l Default
- 没有写权限 就是默认全新 本包内都可以使用
- 两个不同包的两个类 默认权限 不可以使用 即使继承也不可以
- Protected
- 只给子类用
- 不同包也可以用
- 子类对象也不能调用
- 只能是子类的里面,不能建立对象,直接调用方法名
代码块
- {
}
- 限制变量作用域
- 构造代码块 先执行
{
代码
}
- 静态代码块 先执行优先于构造代码块
static{
}
- 静态代码块 只执行一次
构造代码块 建立一个对象执行一次