各位同学,接下来的二天课程中,我们继续学习面向对象的相关课程。面向对象是写Java程序的核心套路,如何你不懂面向对象,那就相当于Java你白学了。所以在接下来的二天时间里,各位同学也需要克服重重困难好好学习。
前面我们说过面向对象最核心的套路是:设计对象来处理数据,解决问题。 如果你把面向对象高级这一部分课程学好,你设计出来的对象将更加好用。
在正式学习面向对象高级课程之前,我给大家提一些学习上的建议。目前我们学习的面向对象高级部分的知识点,就像一个一个的螺丝钉,在学习过程中你可能并不知道这些螺丝钉是用在哪里的,解决的什么问题。必须等这些内容都学习完之后,才能知道用这些螺丝钉可以用来搞飞机、造航母、造火箭。
所以,现阶段我们在学习过程中,主要关注下面几点就可以了。等整个基础课程学习完之后,再慢慢感在到哪里用。
一,类的私有成员和公共成员
1.1 私有成员
类的成员声明前加上私有访问控制符private,则成员只能被该类自身访问和修改,而不能被其他类(包括该类的子类)访问。达到了对数据最高级别保护的目的。
示例:
public class demo{ private int age = 100; public int getAge(){ return age; //可以在类的内部方法中使用private成员,但外部类不可以 } }
那么外部类怎么访问一个类的内部私有成员呢?比如上个示例中,可以通过公有的成中方法来访问私有的成中属性。如果一个方法被声明为私有的,则不可以被外部类访问调用。
1.2 公共成员
类的成员声明前加上公共访问控制符public,则表示该成员可以被其他类所访问。造成安全性和数据封装性的下降,所以一般减少该成员的使用。
public class Demo{ private int age = 100; public String name = "sisa"; public int getAge(){ return age; //可以在类的内部方法中使用private成员,但外部类不可以 } }
上述示例中:name属性为公有的,getAge()方法为公有的,可以被外部类来访问
public class Demo01{ public static void main(String[] args){ Demo demo = new Demo(); demo.name = "sisa2023"; int age = demo.getAge(); } }
1.3 缺省访问控制符
若在类成员的前面不加任何访问控制符,则该成员具有缺省的访问控制特性。
缺省访问控制权,表示这个成员只能被同一个包(类库)中的类所访问和调用,如果一个子类与父类位于不同的包中,子类也不能访问父类中的缺省访问控制成员,也就是说其他包中的任何类都不能访问缺省访问控制成员。
同理,对于类来说,如果一个类没有访问控制符,说明它具有缺省访问控制特性。
二、静态
接下来,我们学习一下面向对象编程中很常见的一个关键字static.
static读作静态,可以用来修饰成员变量,也能修饰成员方法。我们先来学习static修饰成员变量。
1.1 static修饰成员变量
Java中的成员变量按照有无static修饰分为两种:类变量、实例变量。它们的区别如下图所示:
由于静态变量是属于类的,只需要通过类名就可以调用:类名.静态变量
实例变量是属于对象的,需要通过对象才能调用:对象.实例变量
- 下面是代码演示(注意静态变量,和实例变量是如何调用的)
为了让大家对于这两种成员变量的执行过程理解更清楚一点,在这里给大家在啰嗦几句,我们来看一下上面代码的内存原理。
- 最后总结一下
- 1.类变量:属于类,在内存中只有一份,用类名调用 - 2.实例变量:属于对象,每一个对象都有一份,用对象调用
1.2 static修饰成员变量的应用场景
学习完static修饰成员变量的基本使用之后,接下来我们学习一下static修饰成员变量在实际工作中的应用。
在实际开发中,如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成类变量来记住。
我们看一个案例**
需求:系统启动后,要求用于类可以记住自己创建了多少个用户对象。**
- 第一步:先定义一个
User
类,在用户类中定义一个static修饰的变量,用来表示在线人数;
public class User{ public static int number; //每次创建对象时,number自增一下 public User(){ User.number++; } }
- 第二步:再写一个测试类,再测试类中创建4个User对象,再打印number的值,观察number的值是否再自增。
public class Test{ public static void main(String[] args){ //创建4个对象 new User(); new User(); new User(); new User(); //查看系统创建了多少个User对象 System.out.println("系统创建的User对象个数:"+User.number); } }
运行上面的代码,查看执行结果是:系统创建的User对象个数:4
1.3 static修饰成员方法
各位同学,学习完static修饰成员变量之后,接下来我们学习static修饰成员方法。成员方法根据有无static也分为两类:类方法、实例方法
有static修饰的方法,是属于类的,称为类方法;调用时直接用类名调用即可。
无static修饰的方法,是属于对象的,称为实例方法;调用时,需要使用对象调用。
我们看一个案例,演示类方法、实例方法的基本使用
- 先定义一个Student类,在类中定义一个类方法、定义一个实例方法
public class Student{ double score; //类方法: public static void printHelloWorld{ System.out.println("Hello World!"); System.out.println("Hello World!"); } //实例方法(对象的方法) public void printPass(){ //打印成绩是否合格 System.out.println(score>=60?"成绩合格":"成绩不合格"); } }
- 在定义一个测试类,注意类方法、对象方法调用的区别
public class Test2{ public static void main(String[] args){ //1.调用Student类中的类方法 Student.printHelloWorld(); //2.调用Student类中的实例方法 Student s = new Student(); s.printPass(); //使用对象也能调用类方法【不推荐,IDEA连提示都不给你,你就别这么用了】 s.printHelloWorld(); } }
搞清楚类方法和实例方法如何调用之后,接下来再啰嗦几句,和同学们聊一聊static修饰成员方法的内存原理。
1.类方法:static修饰的方法,可以被类名调用,是因为它是随着类的加载而加载的; 所以类名直接就可以找到static修饰的方法 2.实例方法:非static修饰的方法,需要创建对象后才能调用,是因为实例方法中可能会访问实 例变量,而实例变量需要创建对象后才存在。 所以实例方法,必须创建对象后才能调用。
关于static修饰成员变量、和静态修饰成员方法这两种用法,到这里就学习完了。
1.4 工具类
学习完static修饰方法之后,我们讲一个有关类方法的应用知识,叫做工具类。
如果一个类中的方法全都是静态的,那么这个类中的方法就全都可以被类名直接调用,由于调用起来非常方便,就像一个工具一下,所以把这样的类就叫做工具类。
- 我们写一个生成验证码的工具类
public class MyUtils{ public static String createCode(int n){ //1.定义一个字符串,用来记录产生的验证码 String code = ""; //2.验证码是由所有的大写字母、小写字母或者数字字符组成 //这里先把所有的字符写成一个字符串,一会从字符串中随机找字符 String data = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ"; //3.循环n次,产生n个索引,再通过索引获取字符 Random r = new Random(); for(int i=0; i<n; i++){ int index = r.nextInt(data.length()); char ch = data.charAt(index); //4.把获取到的字符,拼接到code验证码字符串上。 code+=ch; } //最后返回code,code的值就是验证码 return code; } }
- 接着可以在任何位置调用
MyUtils
的createCOde()方法
产生任意个数的验证码
//比如这是一个登录界面 public class LoginDemo{ public static void main(String[] args){ System.out.println(MyUtils.createCode()); } }
//比如这是一个注册界面 public class registerDemo{ public static void main(String[] args){ System.out.println(MyUtils.createCode()); } }
工具类的使用就是这样子的,学会了吗?
在补充一点,工具类里的方法全都是静态的,推荐用类名调用为了防止使用者用对象调用。我们可以把工具类的构造方法私有化。
public class MyUtils{ //私有化构造方法:这样别人就不能使用构造方法new对象了 private MyUtils(){ } //类方法 public static String createCode(int n){ ... } }
1.5 static的注意事项
各位同学,到现在在我们已经学会了static修饰的变量、方法如何调用了。但是有一些注意事项还是需要给大家说明一下,目的是让大家知道,使用static写代码时,如果出错了,要知道为什么错、如何改正。
public class Student { static String schoolName; // 类变量 double score; // 实例变量 // 1、类方法中可以直接访问类的成员,不可以直接访问实例成员。 public static void printHelloWorld(){ // 注意:同一个类中,访问类成员,可以省略类名不写。 schoolName = "DTS"; printHelloWorld2(); System.out.println(score); // 报错的 printPass(); // 报错的 ystem.out.println(this); // 报错的 } // 类方法 public static void printHelloWorld2(){ } // 实例方法 public void printPass2(){ } // 实例方法 // 2、实例方法中既可以直接访问类成员,也可以直接访问实例成员。 // 3、实例方法中可以出现this关键字,类方法中不可以出现this关键字的 public void printPass(){ schoolName = "sisa2"; //对的 printHelloWorld2(); //对的 System.out.println(score); //对的 printPass2(); //对的 System.out.println(this); //对的 } }
1.6 static应用(代码块)
各位同学,接下来我们再补充讲解一个知识点,叫代码块;代码块根据有无static修饰分为两种:静态代码块、实例代码块
我们先类学习静态代码块:
public class Student { static int number = 80; static String schoolName = "sisa"; // 静态代码块 static { System.out.println("静态代码块执行了~~"); schoolName = "sisa"; } }
静态代码块不需要创建对象就能够执行
public class Test { public static void main(String[] args) { // 目标:认识两种代码块,了解他们的特点和基本作用。 System.out.println(Student.number); System.out.println(Student.number); System.out.println(Student.number); System.out.println(Student.schoolName); // sisa } }
执行上面代码时,发现没有创建对象,静态代码块就已经执行了。
关于静态代码块重点注意:静态代码块,随着类的加载而执行,而且只执行一次。
再来学习一下实例代码块
实例代码块的作用和构造器的作用是一样的,用来给对象初始化值;而且每次创建对象之前都会先执行实例代码块。
public class Student{ //实例变量 int age; //实例代码块:实例代码块会执行在每一个构造方法之前 { System.out.println("实例代码块执行了~~"); age = 18; System.out.println("有人创建了对象:" + this); } public Student(){ System.out.println("无参数构造器执行了~~"); } public Student(String name){ System.out.println("有参数构造器执行了~~"); } }
接下来在测试类中进行测试,观察创建对象时,实例代码块是否先执行了。
public class Test { public static void main(String[] args) { Student s1 = new Student(); Student s2 = new Student("张三"); System.out.println(s1.age); System.out.println(s2.age); } }
对于实例代码块重点注意:实例代码块每次创建对象之前都会执行一次
三、构造方法和重载
3.1 构造方法
构造方法(constructor)是一种特殊的方法,它是在对象被创建时初始化对象的成员的方法,也称为构造器。它有如下特点。
1、构造方法的方法名与类名相同。
2、构造方法没有返回值,也不能有void。
3、构造方法的主要作用是对类对象的初始化工作。
4、构造方法一般不能由编程人员显式地直接调用,而是用new来调用。
5、在创建一个类的对象的同时,系统会自动调用该类的构造方法为新的对象初始化。
6、可带参数,还可以完成赋值之外的其他复杂操作
如果省略构造方法,Java编译器会自动为该类生成一个默认的构造方法,程序在创建对象时会自动调用默认的构造方法。默认的构造方法没有参数,在其方法体中也没有任何代码,即什么也不做。若class前面有public修饰符,则默认的构造方法前面也是public。一旦用户为某类定义了构造方法,系统就不再提供默认的构造方法,这是Java的覆盖所致。
关于构造器在第4章己讲述。
3.3 方法重载
面向对象的三大特性之一:多态性:一个程序中同名的多个不同方法共存的情况。常用重载和覆盖(重写)。
方法的重载是实现“多态”的方法之一。
方法重载的特征:
1、方法的重载是指方法带有不同的参数,但使用相同的名字。
2、方法的参数不同则表示实现不同的功能,但功能相似。
所谓参数不同是指:参数个数不同、参数类型不同、参数的顺序不同。参数的名字不同不能说明是方法的重载。
3、方法的重载和返回值没有关系
示例:
int add(int x, int y); int add(int x, int y, int z); float add(float f1, float f2); float add(float f1, int y); float add(int y, float f1); float add(int x, int y); int add(int u, int v);
构造方法的重载:方法名相而参数不同
public class Student{ private int age; private String name; public Student(){ } public Student(int age,String name){ this.age = age; this.name = name; } }
从某一构造方法内调用另一构造方法,必须通过关键字this来调用的,否则编译出错。
this关键字必须写在构造方法内的第一行位置。
public class Student{ private int age; private String name; public Student(){ System.out.println("空参构造方法"); } public Student(int age,String name){ this.Student(); System.out.println("非空参构造方法"); } }
注意:
构造方法一般都是public,因为它们在创建对象时,是在类的外部被系统自动调用的。 构造函数若被声明为private,则无法在构造方法所在的类以外的地方被调用,但在该类的内部还是可以被调用。
四,基本类型与包装类类型之间的自动转换
基本数据类型间除了boolean和char类型外,都可以相互转换
1 基本数据类型转包装类型–》装箱
int a =10 ; Integer i1 = a;//可以自动转,自动装箱 Integer a1 = new Integer(a);//手动装箱 Integer i = Integer.valueOf(a);
2 包装类型转基本数据类型–》拆箱
2 包装类型转基本数据类型–》拆箱
Integer a =10 ; int i1 = a;//可以自动转,自动拆箱 int i2 = a.intValue();//手动拆箱
3 把字符串转换成基本数据类型,调用包装类的parseXXX方法或者valueOf方法
3 把字符串转换成基本数据类型,调用包装类的parseXXX方法或者valueOf方法
String s = "1234"; int i = Integer.parseInt(s); double b = Double.parseDouble(s); boolean boo = Boolean.parseBoolean(s); int i = Integer.valueOf(s);
4 把基本数据类型转换成字符串
int i =9; //方法1 String s = i+""; //方法2 String s = String.valueOf(i); //方法3 String s = Integer.toString(i);
五、继承
5.1 继承快速入门
各位同学,我们继续学习面向对象相关内容。面向对象编程之所以能够能够被广大开发者认可,有一个非常重要的原因,是因为它有三大特征,继承、封装和多态。封装我们在基础班已经学过了,接下来我们学习一下继承。
接下来,我们演示一下使用继承来编写代码,注意观察继承的特点。
public class A{ //公开的成员 public int i; public void print1(){ System.out.println("===print1==="); } //私有的成员 private int j; private void print2(){ System.out.println("===print2==="); } }
然后,写一个B类,让B类继承A类。在继承A类的同时,B类中新增一个方法print3
public class B extends A{ public void print3(){ //由于i和print1是属于父类A的公有成员,在子类中可以直接被使用 System.out.println(i); //正确 print1(); //正确 //由于j和print2是属于父类A的私有成员,在子类中不可以被使用 System.out.println(j); //错误 print2(); } }
接下来,我们再演示一下,创建B类对象,能否调用父类A的成员。再写一个测试类
public class Test{ public static void main(String[] args){ B b = new B(); //父类公有成员,子类对象是可以调用的 System.out.println(i); //正确 b.print1(); //父类私有成员,子类对象时不可以调用的 System.out.println(j); //错误 b.print2(); //错误 } }
到这里,关于继承的基本使用我们就算学会了。为了让大家对继承有更深入的认识,我们来看看继承的内存原理。
这里我们只需要关注一点:子类对象实际上是由子、父类两张设计图共同创建出来的。
所以,在子类对象的空间中,既有本类的成员,也有父类的成员。但是子类只能调用父类公有的成员。
5.2 继承的好处
各位同学,学习完继承的快速入门之后,接下来我们学习一下继承的好处,以及它的应用场景。
我们通过一个案例来学习
观察代码发现,我们会发现Teacher类中和Consultant类中有相同的代码;其实像这种两个类中有相同代码时,没必要重复写。
我们可以把重复的代码提取出来,作为父类,然后让其他类继承父类就可以了,这样可以提高代码的复用性。改造后的代码如下:
接下来使用继承来完成上面的案例,这里只演示People类和Teacher类,然后你尝试自己完成Consultant类。
- 先写一个父类 People,用来设计Teacher和Consultant公有的成员。
public class People{ private String name; public String getName(){ return name; } public void setName(String name){ this.name=name; } }
- 再写两个子类Teacher继承People类,同时在子类中加上自己特有的成员。
public class Teacher extends People{ private String skill; //技能 public String getSkill(){ return skill; } public void setSkill(String skill){ this.skill=skill; } public void printInfo(){ System.out.println(getName()+"具备的技能:"+skill); } }
- 最后再写一个测试类,再测试类中创建Teacher、Consultant对象,并调用方法。
public class Test { public static void main(String[] args) { // 目标:搞清楚继承的好处。 Teacher t = new Teacher(); t.setName("播仔"); t.setSkill("Java、Spring"); System.out.println(t.getName()); System.out.println(t.getSkill()); t.printInfo(); } }
执行代码,打印结果如下:
关于继承的好处我们只需要记住:继承可以提高代码的复用性
5.3 权限修饰符
各位同学,在刚才使用继承编写的代码中我们有用到两个权限修饰符,一个是public(公有的)、一个是private(私有的),实际上还有两个权限修饰符,一个是protected(受保护的)、一个是缺省的(不写任何修饰符)。
接下来我们就学习一下这四个权限修饰符分别有什么作用。
什么是权限修饰符呢?
权限修饰符是用来限制类的成员(成员变量、成员方法、构造器…)能够被访问的范围。
每一种权限修饰符能够被访问的范围如下
下面我们用代码演示一下,在本类中可以访问到哪些权限修饰的方法。
public class Fu { // 1、私有:只能在本类中访问 private void privateMethod(){ System.out.println("==private=="); } // 2、缺省:本类,同一个包下的类 void method(){ System.out.println("==缺省=="); } // 3、protected: 本类,同一个包下的类,任意包下的子类 protected void protectedMethod(){ System.out.println("==protected=="); } // 4、public: 本类,同一个包下的类,任意包下的子类,任意包下的任意类 public void publicMethod(){ System.out.println("==public=="); } public void test(){ //在本类中,所有权限都可以被访问到 privateMethod(); //正确 method(); //正确 protectedMethod(); //正确 publicMethod(); //正确 } }
接下来,在和Fu类同一个包下,创建一个测试类Demo,演示同一个包下可以访问到哪些权限修饰的方法。
public class Demo { public static void main(String[] args) { Fu f = new Fu(); // f.privateMethod(); //私有方法无法使用 f.method(); f.protectedMethod(); f.publicMethod(); } }
接下来,在另一个包下创建一个Fu类的子类,演示不同包下的子类中可以访问哪些权限修饰的方法。
public class Zi extends Fu { //在不同包下的子类中,只能访问到public、protected修饰的方法 public void test(){ // privateMethod(); // 报错 // method(); // 报错 protectedMethod(); //正确 publicMethod(); //正确 } }
接下来,在和Fu类不同的包下,创建一个测试类Demo2,演示一下不同包的无关类,能访问到哪些权限修饰的方法;
public class Demo2 { public static void main(String[] args) { Fu f = new Fu(); // f.privateMethod(); // 报错 // f.method(); //报错 // f.protecedMethod();//报错 f.publicMethod(); //正确 Zi zi = new Zi(); // zi.protectedMethod(); } }
5.4 单继承、Object
刚才我们写的代码中,都是一个子类继承一个父类,那么有同学问到,一个子类可以继承多个父类吗?
Java语言只支持单继承,不支持多继承,但是可以多层继承。就像家族里儿子、爸爸和爷爷的关系一样:一个儿子只能有一个爸爸,不能有多个爸爸,但是爸爸也是有爸爸的。
public class Test { public static void main(String[] args) { // 目标:掌握继承的两个注意事项事项。 // 1、Java是单继承的:一个类只能继承一个直接父类; // 2、Object类是Java中所有类的祖宗。 A a = new A(); B b = new B(); ArrayList list = new ArrayList(); list.add("java"); System.out.println(list.toString()); } } class A {} //extends Object{} class B extends A{} // class C extends B , A{} // 报错 class D extends B{}
5.5 方法重写
各位同学,学习完继承之后,在继承的基础之上还有一个很重要的现象需要给大家说一下。
叫做方法重写。为了让大家能够掌握方法重写,我们先认识什么是方法重写,再说一下方法的应用场景。
什么是方法重写
当子类觉得父类方法不好用,或者无法满足父类需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。
注意:重写后,方法的访问遵循就近原则。下面我们看一个代码演示
写一个A类作为父类,定义两个方法print1和print2
public class A { public void print1(){ System.out.println("111"); } public void print2(int a, int b){ System.out.println("111111"); } }
再写一个B类作为A类的子类,重写print1和print2方法。
public class B extends A{ // 方法重写 @Override // 安全,可读性好 public void print1(){ System.out.println("666"); } // 方法重写 @Override public void print2(int a, int b){ System.out.println("666666"); } }
接下来,在测试类中创建B类对象,调用方法
public class Test { public static void main(String[] args) { // 目标:认识方法重写,掌握方法重写的常见应用场景。 B b = new B(); b.print1(); b.print2(2, 3); } }
执行代码,我们发现真正执行的是B类中的print1和print2方法
知道什么是方法重写之后,还有一些注意事项,需要和大家分享一下。
- 1.重写的方法上面,可以加一个注解@Override,用于标注这个方法是复写的父类方法 - 2.子类复写父类方法时,访问权限必须大于或者等于父类方法的权限 public > protected > 缺省 - 3. 重写的方法返回值类型,必须与被重写的方法返回值类型一样,或者范围更小 - 4. 私有方法、静态方法不能被重写,如果重写会报错。
关于这些注意事项,同学们其实只需要了解一下就可以了。实际上我们实际写代码时,只要和父类写的一样就可以( 总结起来就8个字:声明不变,重新实现)
方法重写的应用场景
学习完方法重写之后,接下来,我们还需要大家掌握方法重写,在实际中的应用场景。方法重写的应用场景之一就是:子类重写Object的toString()方法,以便返回对象的内容。
比如:有一个Student类,这个类会默认继承Object类。
public class Student extends Object{ private String name; private int age; public Student() { } public Student(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; } }
其实Object类中有一个toString()方法,直接通过Student对象调用Object的toString()方法,会得到对象的地址值。
public class Test { public static void main(String[] args) { Student s = new Student("播妞", 19); // System.out.println(s.toString()); System.out.println(s); } }
但是,此时不想调用父类Object的toString()方法,那就可以在Student类中重新写一个toSting()方法,用于返回对象的属性值。
package com.itheima.d12_extends_override; public class Student extends Object{ private String name; private int age; public Student() { } public Student(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; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
重新运行测试类,结果如下
好了,到这里方法什么是方法重写,以及方法重写的应用场景我们就学习完了。
5.6 子类中访问成员的特点
各位同学,刚才我们已经学习了继承,我们发现继承至少涉及到两个类,而每一个类中都可能有各自的成员(成员变量、成员方法),就有可能出现子类和父类有相同成员的情况,那么在子类中访问其他成员有什么特点呢?
- 原则:在子类中访问其他成员(成员变量、成员方法),是依据就近原则的
定义一个父类,代码如下
public class F { String name = "父类名字"; public void print1(){ System.out.println("==父类的print1方法执行=="); } }
再定义一个子类,代码如下。有一个同名的name成员变量,有一个同名的print1成员方法;
public class Z extends F { String name = "子类名称"; public void showName(){ String name = "局部名称"; System.out.println(name); // 局部名称 } @Override public void print1(){ System.out.println("==子类的print1方法执行了="); } public void showMethod(){ print1(); // 子类的 } }
接下来写一个测试类,观察运行结果,我们发现都是调用的子类变量、子类方法。
public class Test { public static void main(String[] args) { // 目标:掌握子类中访问其他成员的特点:就近原则。 Z z = new Z(); z.showName(); z.showMethod(); } }
- 如果子类和父类出现同名变量或者方法,优先使用子类的;此时如果一定要在子类中使用父类的成员,可以加this或者super进行区分。
public class Z extends F { String name = "子类名称"; public void showName(){ String name = "局部名称"; System.out.println(name); // 局部名称 System.out.println(this.name); // 子类成员变量 System.out.println(super.name); // 父类的成员变量 } @Override public void print1(){ System.out.println("==子类的print1方法执行了="); } public void showMethod(){ print1(); // 子类的 super.print1(); // 父类的 } }
5.7 子类中访问构造器的特点
各位同学,我们知道一个类中可以写成员变量、成员方法,还有构造器。在继承关系下,子类访问成员变量和成员方法的特点我们已经学过了;接下来再学习子类中访问构造器的特点。
我们先认识子类构造器的语法特点,再讲一下子类构造器的应用场景
子类中访问构造器的语法规则
- 首先,子类全部构造器,都会先调用父类构造器,再执行自己。
执行顺序,如下图按照① ② ③ 步骤执行:
子类访问构造器的应用场景
- 如果不想使用默认的
super()
方式调用父类构造器,还可以手动使用super(参数)
调用父类有参数构造器。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zcioyLVN-1690168860693)(assets/1664163881728.png)]
在本类中访问自己的构造方法
刚才我们学习了通过super()
和super(参数)
可以访问父类的构造器。有时候我们也需要访问自己类的构造器。语法如下
this(): 调用本类的空参数构造器 this(参数): 调用本类有参数的构造器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DO8Jlqqv-1690168860694)(assets/1664170865036.png)]
最后我们被this和super的用法在总结一下
访问本类成员: this.成员变量 //访问本类成员变量 this.成员方法 //调用本类成员方法 this() //调用本类空参数构造器 this(参数) //调用本类有参数构造器 访问父类成员: super.成员变量 //访问父类成员变量 super.成员方法 //调用父类成员方法 super() //调用父类空参数构造器 super(参数) //调用父类有参数构造器 注意:this和super访问构造方法,只能用到构造方法的第一句,否则会报错。
六、Java语言的垃圾回收
垃圾回收(Garbage-collection)是Java语言提供的一种自动内存回收功能,可以让程序员减轻许多内存管理的负担,也减少程序员犯错的机会。
当一个对象被创建时,JVM会为该对象分配一定的内存、调用该对象的构造方法并开始跟踪该对象。当该对象停止使用时,JVM将通过垃圾回收器回收该对象所占用的内存。
Java是如何知道一个对象无用呢?系统中的任何对象都有一个引用计数器来计数。
垃圾回收的好处:
1、它把程序员从复杂的内存追踪、检测和释放等工作解放出来;
2、它防止 了系统内存被非法释放,从而使系统更稳定。
垃圾回收的特点:
1、只有当一个对象不被任何引用类型的变量使用时,它的内存才可能被垃圾回收器回收;
2、不能通过程序强迫回收器立即执行;
3、当垃圾回收器将要释放无用对象的内存时,先调用该对象的finalze()方法。