最新Java基础系列课程--Day07-面向对象的特性(二)https://developer.aliyun.com/article/1423501
接下来,在和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()方法。