Java从入门到放弃08—代码块/继承/关键字super/继承关系中的变量访问原则/继承中构造方法的关系/方法重写/final关键字
01 代码块
- 概念概述:在Java中,被一对{}括起来的内容被称为代码块。
- 分类:根据定义的位置和声明的不同分为:局部代码块,构造代码块,静态代码块,同步代码块。
- 局部代码块:定义在方法中的代码块。将变量的生命周期限定在一个方法中,能够尽早的释放空间和资源,利于提高内存利用率。
- 构造代码块:定义在类中方法外。构造代码块在创建对象时执行,优先于构造方法执行。每创建一次对象都会执行一次构造代码块和构造方法。
- 静态代码块:定义在类中方法外,加static状态修饰符。静态代码块随着类的加载而加载,优先于构造代码块和局部代码块执行,且由于类只加载了一次,因此静态代码块只执行一次。静态代码块中只能访问静态变量。
class Student {
static {
System.out.println("Student 静态代码块");
}
{
System.out.println("Student 构造代码块");
}
public Student() {
System.out.println("Student 构造方法");
}
}
class StudentDemo {
static {
System.out.println("StudentDemo的静态代码块");
}
public static void main(String[] args) {
System.out.println("我是main方法");
Student s1 = new Student();
Student s2 = new Student();
}
}
运行结果:StudentDemo的静态代码块
我是main方法
Student 静态代码块
Student 构造代码块
Student 构造方法
Student 构造代码块
Student 构造方法
02 继承
-
概念概述:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
-
理解:Java中,子类可以继承父类的非私有化的成员变量,成员方法等。
-
作用:将各个子类的共性向上抽取为父类,以提升代码的复用(重复利用)性和维护性。
-
继承的优势:提升了代码的复用性和维护性。
-
继承的弊端:增加了耦合性。
-
Tip:软件的设计原则:1.高内聚(一个类,单独完成某个功能的能力)2.低耦合(一个类要完成某个功能,需要依赖某些类)
-
语法:class 子类类名 extends 父类类名{}//表示子类继承了父类
- 继承的注意事项:
- Java只支持单继承,但是支持多层继承。(比如A类既想继承B类又想继承C类,继承关系可表示为:class A extends B {} class B extends C{})(课外拓展:C++也是面向对象的语言,但是C++支持多继承)
- 子类只能继承父类的非私有成员和方法。
- 构造方法不参与继承,但是可以通过super关键字去访问父类构造方法。如果父类只提供了无参构造方法,子类想要提供有参构造方法,可以通过super();调用父类空参构造,对父类数据进行初始化后,再执行本类的有参构造方法来实现。需要注意的是,如果父类只提供了有参构造方法,在创建子类对象时可以通过super(参数列表);调用父类的有参构造方法对父类进行初始化后,再执行本类的无参构造方法对该类对象进行实例化。
程序示例:
public class ExtendsTest {
public static void main(String[] args) {
//使用无参构造方法
Student student = new Student();
student.setName("张三");
student.setAge(18);
student.learning(student.getName());
System.out.println("---------------------------------");
Teacher teacher = new Teacher();
teacher.setName("李四");
teacher.setAge(32);
teacher.teaching(teacher.getName());
System.out.println("---------------------------------");
//使用有参构造方法
Student student1 = new Student("王五",19);
student1.learning(student1.getName());
System.out.println("---------------------------------");
Teacher teacher1 = new Teacher("赵六",38);
teacher1.teaching(teacher1.getName());
System.out.println("---------------------------------");
}
}
class People {//父类
public String name;
public int age;
public People() {
}
public People(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Student extends People {//子类
public Student() {//子类的无参构造方法
super();//该语句是默认执行的,可以不写出
}
public Student(String name, int age) {//子类的有参构造方法1,使用super调用父类的有参构造方法
super(name, age);//该语句不能省略必须写出
}
public void learning(String name) {
System.out.println(name+"的职责是学习");
}
}
class Teacher extends People{//子类
public Teacher() {
}
public Teacher(String name, int age) {//子类的有参构造方法2,注意:如果需要传入的参数(形参)为父类中的私有变量,下面的代码块会报错。
super();//默认执行,可以省略
this.name=name;
this.age=age;
}
public void teaching(String name){
System.out.println(name+"的职责是教学");
}
}
运行结果:张三的职责是学习
---------------------------------
李四的职责是教学
---------------------------------
王五的职责是学习
---------------------------------
赵六的职责是教学
03 SUPER关键字
- super:父类空间的一个标识,可理解为对父类的引用,使用super可以访问父类的数据(成员变量、成员方法、构造方法)
- 对比this理解:this 是本类空间的一个标识,代表本类的引用,哪个对象调用这个方法,方法中的this就代表这个对象。
04 继承关系中的变量访问原则
- 遵循就近原则,局部变量(形参)位置>本类的成员位置>父类的成员位置
程序示例:
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);//由于没有传参,依据就近原则,先在方法中找局部变量,因此打印局部变量num,30
System.out.println(this.num);//this是本类空间的标识符,谁调用代表谁,因此打印的是本类的成员变量num,20
System.out.println(super.num);/super是父类空间标识符,该语打印的是父类空间的成员变量num,10
}
}
class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
05 继承中构造方法的关系
- 在创建子类对象时,子类中所有的构造方法默认都会访问父类中空参数的构造方法。
- 存在继承关系后,在初始化子类时,先要完成父类数据的初始化。因为,子类想要继承父类的数据,可能还会使用父类的数据。因此,必须要让父类的构造方法执行,来完成父类数据的初始化,然后再完成自己的数据的初始化。
- 在每个子类的构造方法的第一行,无论是空参构造还是有参构造都会默认有一条语句(但不显示,也可以自己写出,但是该语句必须放在子类构造方法的第一行):子类中super(); 作用是调用父类的空参构造,先完成父类数据的初始化。父类中的super();语句调用的是object类的空参构造。
- 如果父类只提供了无参构造方法,子类想要提供有参构造方法,可以通过super();调用父类空参构造,对父类数据进行初始化后,再执行本类的有参构造方法来实现。需要注意的是,如果父类只提供了有参构造方法,在创建子类对象时可以通过super(参数列表);调用父类的有参构造方法对父类进行初始化后,再执行本类的无参构造方法对该类对象进行实例化。
- 构造方法中this()和super()不能共存。
程序示例1:父类只提供了无参构造方法,子类如何提供给有参构造方法
public class MyTest {
public static void main(String[] args) {
Son son = new Son(10);
}
}
class Father{
int num=1000;
public Father() {
super();//父类构造方法中的super();访问的是object类的构造方法
System.out.println("这是父类的空参构造");
}
}
class Son extends Father{
int b=10;
public Son() {
super();//访问父类的无参构造方法,完成父类数据的初始化。
System.out.println("这是子类的空参");
}
public Son(int b) {//传入的参数不能是父类中的私有化变量,否则构造代码块会报错
super();//调用父类的空参构造,完成父类数据的初始化。
this.b = b;
System.out.println("子类有参构造执行了");
}
}
运行结果: 这是父类的空参构造
子类有参构造执行了
程序示例2:如果父类只提供了有参构造,如何使用子类的空参构造
public class MyTest {
public static void main(String[] args) {
Zi zi = new Zi();
Zi zi = new Zi(10);
}
}
class Fu{
int num=10;
public Fu(int num) {//父类只提供了有参构造
super();
this.num = num;
System.out.println("父类的有参构造执行了");
}
}
class Zi extends Fu{
int num=100;
public Zi() {
super(10);//调用父类的有参构造方法对父类进行初始化
System.out.println("子类的空参构造执行了");
}
public Zi(int num) {
super(num);
System.out.println("子类的有参构造执行了");
}
}
运行结果:父类的有参构造执行了
子类的空参构造执行了
父类的有参构造执行了
子类的有参构造执行了
06 继承中的方法重写(覆盖)
-
方法重写(覆盖):当子类出现了父类一模一样的方法(方法名,参数列表,返回值类型一致),子类方法会覆盖父类方法。
-
继承中的方法重写机制便于子类对父类方法的功能进行拓展,既能沿袭父类的方法,又可以实现子类特有的功能。
-
@override可以检查是否发生了方法重写。快捷键ctrl+O
-
静态方法属于类,不算重写。
-
方法重写的注意事项:
1.父类私有的方法,子类无法重写。私有的方法子类无法继承,更不能重写。
2.子类在重写父类方法时,权限修饰符不能比父类的低,要比父类的高或者一样,最好一样。权限修饰符等级public>protected>缺省的>private
3.静态方法不参与重写。
程序示例:
public class MyTest {
public static void main(String[] args) {
//为什么要有方法重写的这种机制。如果说子类对父类的方法实现不满意,那么子类就可以覆盖他,或者说,子类想要对父类的方法的实现功能进行扩展,也可以使用方法重写的这种机制
Zi zi = new Zi();
zi.show();//子类和父类中都有该方法,执行时执行子类的方法
zi.test();//子类中特有的方法
}
}
class Fu {
int num=100;
public void show(){
System.out.println("我是父类的show方法");
}
}
class Zi extends Fu{
int num=200;
public void test(){
System.out.println("我是子类的test方法");
}
@override
public void show() {//子类重写父类中的show方法
System.out.println("我是子类的show方法");
}
}
运行结果:我是子类的show方法
我是子类的test方法
07 final关键字
-
回顾:常量可以分为字面值常量和自定义常量,常量的命名字母全部大写。
-
final修饰特点
修饰类: 被修饰的类不能被继承final class A
修饰方法: 被修饰的方法不能被重写
public final void test(){}
修饰变量: 被修饰的变量不能被重新赋值,因为这个量其实已经是一个常量了
final int NUM=100;
修饰引用数据类型:被修饰的引用数据类型的地址值不能被改变
final 类名 对象名=new 类名();