自学Java基础知识第八天
day08
1. 继承
1.1 继承中的成员变量
1. 子类可以继承到父类中所有非私有成员变量, 继承到了可以直接使用
2. 如果子类定义出了与父类同名的成员变量
a : 在子类中,使用子父类重名成员变量时, 根据变量就近访问原则, 优先使用子类中定义的成员变量;
变量就近访问原则 : 如果有局部变, 优先使用局部变量; 没有局部变量, 优先使用本类成员变量; 没有本类成员变量, 再使用父类中的可继承成员变量...
b : 在子类中, 想要使用父类中的成员变量, 使用super关键字
super : 表示当前类型对象的父类引用
super.i; // 父类成员变量i的使用
代码
package com.ujiuye.extendsdemo; public class Fu { int i = 10; int j = 20; } |
package com.ujiuye.extendsdemo; public class Zi extends Fu { // 1. Zi类继承到了父类中成员 i 和 j // Zi类中定义了与父类同名成员i int i = 99;
// useVariable功能 : 使用子父类中的成员变量 public void useVariable(int i) { // 参数列表上局部变量i使用 System.out.println(i); // Zi类成员变量i System.out.println(this.i); // Fu类成员变量i System.out.println(super.i); } } |
package com.ujiuye.extendsdemo; public class TestFuAndZi { public static void main(String[] args) { Zi z = new Zi(); z.useVariable(100); } } |
1.2 this和super关键字在内存中的理解
1. 子类的.class字节码文件进入方法区之前, 父类的.class字节码文件要优先于子类进入到方法区中
2. 当创建子类对象时, 要先在子类的堆内存空间区域中开辟出父类的成员内存空间, 保证父类先进入到内存将一切可继承的成员准备好, 子类才可以直接继承使用; 接下来子类成员进内存
1.3 继承中的成员方法
1. 子类可以继承到父类中所有非私有成员方法功能, 继承到了可以直接使用
2. 如果子类认为从父类继承来的方法功能, 不能满足子类需求, 可以重写从父类继承来的方法功能, 通常重写是为了让方法越来越好
子类重写父类继承来的方法功能要求:
1) 方法的返回值类型, 方法名, 参数列表与父类方法保持一致
2) 方法修饰符方面, 子类重写的方法修饰符范围大于等于父类修饰范围
public公共---->默认修饰------>private
如果类, 方法, 成员变量, 没有任何权限修饰, 那就是默认修饰, 默认修饰不写出来
3) 在子类重写方法之上, 使用注解 @Override 验证方法是否是重写方法
注意 : 子类重写方法之后, 优先使用子类重写方法功能
- 如果在子类已经重写父类某方法前提下, 想要调用父类的同名方法功能, 使用super关键字, super.方法名(实际参数);
代码
package com.ujiuye.extendsdemo; public class Fu { int i = 10; int j = 20;
public void fun() { System.out.println("父类---fun"); } public int getSum(int x, int y) { return x + y; } } |
package com.ujiuye.extendsdemo; public class Zi extends Fu { // 1. Zi类继承到了父类中成员 i 和 j // Zi类中定义了与父类同名成员i int i = 99; // useVariable功能 : 使用子父类中的成员变量 public void useVariable(int i) { // 参数列表上局部变量i使用 System.out.println(i); // Zi类成员变量i System.out.println(this.i); // Fu类成员变量i System.out.println(super.i); }
// 2. Zi类继承到了父类中方法fun, getSum @Override public void fun() { System.out.println("子类---fun"); // 调用父类fun方法 super.fun(); } } |
package com.ujiuye.extendsdemo; public class TestFuAndZi { public static void main(String[] args) { // 1. 成员变量测试 Zi z = new Zi(); z.useVariable(100); System.out.println(z.j);// 20
// 2. 方法测试 z.fun();// 调用子类重写方法 int sum = z.getSum(3, 5);// 调用从父类继承来的方法功能 System.out.println(sum); } } |
1.4 继承中的构造方法
1. 父类的构造方法子类无法继承, 子类构造方法中可以调用父类构造, 一定调用
2. 继承中的构造:
1) 子类构造方法方法第一行,如果没有手动调用任何构造, 那么系统会自动(默认)调用父类的空参数构造方法, 调用super();
2) 子类构造方法第一行手动调用构造, 系统不会再自动添加父类构造调用
注意:
- super() 必须在子类构造的有效行第一行, 保证父类成员优先于子类进堆内存
- this() 必须在构造有效行第一行, 间接保证父类成员优先于子类进堆内存
- super() 和this() 都必须在构造有效行第一行, 二选一
代码
package com.ujiuye.extendsdemo; public class Fu { int i = 10; int j = 20;
public void fun() { System.out.println("父类---fun"); }
public int getSum(int x, int y) { return x + y; }
// 定义出一个空参数父类构造 public Fu() { System.out.println("我是父类构造"); }
public Fu(int i) { this.i = i; } } |
package com.ujiuye.extendsdemo; public class Zi extends Fu { // 1. Zi类继承到了父类中成员 i 和 j // Zi类中定义了与父类同名成员i int i = 99; // useVariable功能 : 使用子父类中的成员变量 public void useVariable(int i) { // 参数列表上局部变量i使用 System.out.println(i); // Zi类成员变量i System.out.println(this.i); // Fu类成员变量i System.out.println(super.i); }
// 2. Zi类继承到了父类中方法fun, getSum @Override public void fun() { System.out.println("子类---fun"); // 调用父类fun方法 super.fun(); }
// 3. 继承中构造 public Zi() { // 父类构造调用 // super(); super(2000); } public Zi(String s) { // 手动调用本类构造,本类构造第一行还是父类构造调用 // this() 在第一行也是为了保证父类成员优先于子类进内存 this(); } } |
package com.ujiuye.extendsdemo; public class TestFuAndZi { public static void main(String[] args) { // 1. 成员变量测试 Zi z = new Zi(); z.useVariable(100); System.out.println(z.j);// 20
// 2. 方法测试 z.fun();// 调用子类重写方法 int sum = z.getSum(3, 5);// 调用从父类继承来的方法功能 System.out.println(sum); } } |
1.5 this和super关键字的使用总结
1. this关键字 :
a : 区分成员变量和局部变量重名问题, 带有this.关键字表示成员变量的使用
b : 本类构造方法之间调用, this(被调用构造实际参数);
- super关键字:
a : 区分子类与父类中重名成员变量和方法功能, 带有super.关键字表示父类的成员变量或者方法功能使用
b : 子类构造方法第一行super(被调用父类构造实际参数); 调用父类构造
注意 : 在构造方法调用场景下, this() 或者 super() , 两者都必须在构造方法有效行第一行, 因此两者的调用二选一
2. 代码块(了解)
2.1代码块的介绍
1. 代码块 : 表示将代码放置到一对大括号中, 将代码块放置位置不同, 作用效果和运行机制就会不同
2. 代码块分类:
1) 局部代码块
2) 构造代码块
3) 静态代码块(掌握)
4) 同步代码块(多线程再讲解)
2.2 局部代码块
1. 格式: 使用一对大括号包裹代码
2. 位置 : 定义在方法中
3. 作用:
1) 为了限定变量作用范围, 定义在局部代码块中的变量, 只能在局部代码块中使用, 出了局部代码块,不能再继续使用
2) 如果一个变量不能再使用, 那么这个变量所占有的内存空间就会变成垃圾, 等待JVM虚拟机进行空间回收, 变相节省内存空间
4.注意事项:
局部代码块之外定义的变量, 如果在局部代码块中进行修改, 出了局部之外, 修改仍然生效, 因此局部代码块之外定义的变量, 不受局部代码块限制
代码
package com.ujiuye.block; public class Demo01_局部代码块 { public static void main(String[] args) { int j = 20;
// 定义出局部代码块 { // 因为变量i定义在局部代码块中, 因此i的使用范围只能在局部代码块中 // 出了布局代码块, i变量不能使用 int i = 10; System.out.println(i); j = 99;
} //i cannot be resolved to a variable // System.out.println(i); i变量超出了最大使用范围 System.out.println(j);// 99 } } |
2.3 构造代码块
1. 格式 : 使用一对大括号包裹代码
2. 位置 : 定义在类中方法外
3. 构造代码块运行机制:
每次创建对象时, JVM虚拟机主动调用一次构造代码块, 构造代码块在构造方式之前运行
4.作用 :
1) 可以为对象中的成员变量进行赋值
2) 因为构造代码块在构造方法之前运行, 因此如果多个构造方法有相同代码处理逻辑, 可以将相同逻辑提升到构造代码块中运行
代码
package com.ujiuye.block; public class Demo02_构造代码块 { int i; int j;
// 构造代码块 { // 1. 给成员变量进行赋值 i = 10; j = 20; System.out.println("我是代码块"); // 2. 因为构造代码块在构造方法之前运行, 因此如果多个构造方法有相同代码处理逻辑, 可以将相同逻辑提升到构造代码块中运行 System.out.println("我是构造"); }
public Demo02_构造代码块() { //System.out.println("我是构造"); }
public Demo02_构造代码块(int i,int j) { this.i = i; this.j = j; //System.out.println("我是构造"); }
public static void main(String[] args) { Demo02_构造代码块 demo = new Demo02_构造代码块(); System.out.println(demo.i); System.out.println(demo.j);
Demo02_构造代码块 demo1 = new Demo02_构造代码块(); } } |
2.4 静态代码块(掌握)
- 格式: 使用一对大括号包裹代码, 在大括号外使用static 关键字标识静态代码块
static{
}
- 位置 : 定义在类中方法外
- 执行机制:
静态属于类, 静态代码块也属于类, 当类型的.class字节码文件加载进入方法区, 静态成员需要加载到静态区域中, 静态代码块会由JVM虚拟机调用执行, 静态代码块只随着类的加载运行一次
- 作用:
1) 可以为类型中的静态成员变量进行赋值
2) 如果类中有一进入内存就需要马上运行的代码, 可以设计在静态代码块中, 例如 : 驱动的加载, 交易中人民币与其他币种的汇率兑换, 在执行交易之前, 汇率要先准备好, 才能保证交易的正常运作, 且汇率兑换比率执行一次就可以
代码
package com.ujiuye.block; public class Demo03_静态代码块 { static String name;
// 定义出静态代码块 static { // 1. 可以为静态成员变量进行赋值 name = "张三"; System.out.println("静态代码块执行了"); }
public static void main(String[] args) { Demo03_静态代码块 demo = new Demo03_静态代码块(); System.out.println(Demo03_静态代码块.name);
Demo03_静态代码块 demo1 = new Demo03_静态代码块(); } } |
3.final关键字
1. final : 关键字,表示最终的, 最后的, 不可改变
2. final修饰 : 类, 方法, 变量(最常用)
a : 使用final修饰的类, 最终类, 不能当父类, 其他使用一切正常
b : 使用final修饰方法, 最终方法, 可以被子类继承使用,但是子类不能重写
c : 使用final修饰变量, 最终变量, 不可改变的变量, final修饰的变量只能手动赋值一次, 值无法修改, 使用final修饰的变量称为常量
1) final修饰基本数据类型, 对应的数值不能修改
2) final修饰引用数据类型, 引用的地址不能修改, 地址中的数据可以修改
3) final修饰成员变量, 需要在变量进入内存之前进行手动赋值
注意 : final修饰变量行业内部命名规则 : 变量名全大写, 多个英文单词之间使用_进行分隔
final修饰类代码
package com.ujiuye.finaldemo; // 使用final修饰的最终类, 不能有子类 public final class FinalClass { int i = 10; static int j = 99; public void fun() { System.out.println("fun-----"); } } |
package com.ujiuye.finaldemo;
//The type FinalClassZi cannot subclass the final class FinalClass // 使用final修饰的类FinalClass , 不能有子类 /*public class FinalClassZi extends FinalClass{
}*/ |
package com.ujiuye.finaldemo; public class TestFinal { public static void main(String[] args) { // 1. final修饰的类可以正常使用 System.out.println(FinalClass.j);// 99
FinalClass f = new FinalClass(); System.out.println(f.i);// 10 f.fun();// fun----- } } |
final修饰方法代码
package com.ujiuye.finaldemo; public class FinalMethod { int i = 1000; public void eat() { System.out.println("吃饭"); }
public final void sleep() { System.out.println("每个人每天睡8小时"); } } |
package com.ujiuye.finaldemo; public class FinalMethodZi extends FinalMethod { // 继承到了父类中的eat和sleep @Override public void eat() { System.out.println("每天只吃两顿饭"); }
/* * final修饰的方法功能, 子类可以继承使用,但是不能重写 * @Override public void sleep() { System.out.println("每个人每天睡10小时"); }*/ } |
package com.ujiuye.finaldemo; public class TestFinal { public static void main(String[] args) { // 1. final修饰的类可以正常使用 System.out.println(FinalClass.j);// 99
FinalClass f = new FinalClass(); System.out.println(f.i);// 10 f.fun();// fun-----
// 2. final修饰的方法 FinalMethodZi zi = new FinalMethodZi(); zi.eat();// 每天只吃两顿饭 zi.sleep();// 每个人每天睡8小时 } } |
final修饰变量代码
package com.ujiuye.finaldemo; public class FinalVariable { // 静态常量 static final String SCHOOL_NAME = "第一中学"; // 5. fianl修饰成员变量, 需要在创建对象完成之前进行final变量的手动赋值 // The blank final field w may not have been initialized(初始化, 表示赋值) // final修饰的成员变量w, 在进入到内存可以使用之前, 必须完成一次手动赋值 final int w;
public FinalVariable() { w = 100; }
public static void main(String[] args) { // 1. Math数学类中, 有静态成员常量 PI // static final double PI System.out.println(Math.PI);// 3.141592653589793
// 2. 修改校名 // The final field FinalVariable.schoolName cannot be assigned // final修饰变量只能一次手动, 其值无法修改 // FinalVariable.SCHOOL_NAME = "一中";
// 3. final修饰基本数据类型, 表示基本类型的值不可修改 final int i = 10; // i = 10;
// 4. final修饰引用数据类型, 表示final修饰的fm所对应内存地址不能修改, 没存地址中的数据可以修改 final FinalMethod fm = new FinalMethod(); // fm = new FinalMethod(); fm.i = 999; } } |
4. Eclipse进阶
- 内容辅助生成: alt + /
辅助完成代码补全:
1) main alt+/ 补全main方法功能
2) syso alt+/ 补全标准输出语句
3) 关键字补全 : 给出关键字的开头字母, 帮助补全关键字
4) 帮助代码进行命名
5) 常用语法结构, 可以使用alt + / 自动生成和补全
- 常用快捷键使用:
1) 导包 : ctrl + shift + o , 将代码中所有的为进行导包的类型统一进行包的导入
2) 注释 :
a : 单行注释 : ctrl + / , 取消注释 ctrl + /
b : 多行注释 : ctrl + shift + /, 取消多行注释 : ctrl + shift + \
3) 删除 : ctrl + d 每次删除一行内容, 当前鼠标所在行
4) 重命名 : 项目工程, 类重命名, 使用F2(Fn + F2)
开发中常用的快捷键:
5) ctrl + f : 表示查找或者替换
6) ctrl + o : 查看当前类型的大纲内容, 将类型中的成员变量, 方法罗列出来, 点击对应的变量和方法,做代码快速定位
7) ctrl + 代码(变量, 方法,类) : 跟进到代码的来源,查看源代码
- 代码生成:
alt + shift + s
5. 包package
- 包 : 就是进行不同的类型文件的分类管理
- 包的使用:
1) 不同的包package下, 可以定义出相同的类名, 类全名带有包名
举例 : com.ujiuye.homework.Test2;
com.ujiuye.finaldemo.Test2;
2) 包的命名规则 : 全球唯一, 公司域名倒序写作
举例 : com.ujiuye.包名(包名表示包的作用)
- 导包: 将使用类型所在具体路径使用import关键字进行导入, 需要通过导包, 定位使用的类型所在的具体路径位置, 才能将类型加载进入内存中, 才能使用
1) 同一个package包下的类,可以直接使用,不需要导包
2) 不同package包下的类的使用,需要通过import关键字进行导包
3) java.lang包下的所有类型, 可以直接使用, 不需要导包
4) 在导包时候 import java.util.*; // 将util下的所有类都可以进行导入, 使用*替代
但是不建议导入*使用, 使用哪个类型, 导入具体的包, 不要导入*