Day08JavaSE——面向对象之继承&重写&final关键字
文章目录
代码块
继承
方法重写与方法重载
final关键字
代码块
A:代码块概述
在Java中,使用{}括起来的代码被称为代码块。
B:代码块分类
根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块(多线程讲解)。
C:常见代码块的应用
a:局部代码块
在方法中出现;限定变量生命周期,及早释放,提高内存利用率
b:构造代码块
在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
c:静态代码块
在类中方法外出现,加了static修饰
在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次。
概述
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
//代码块:就是被一对{}所括起来的内容
//代码块根据定义位置的不同可分为:局部代码块,构造代码块,静态代码块,同步代码块(后面说)
//定义在方法中的代码块
int num2 = 200;
{
/*局部代码块:在方法中出现,限定变量生命周期,及早释放,提高内存利用率*/
int num = 20;
Scanner scanner = new Scanner(System.in);
System.out.println("局部代码块执行了");
System.out.println(num2);
}
System.out.println("=======================");
//创建对象时就会调用构造代码块。
//构造代码块优先于构造方法执行
//每次创建对象构造代码块都会执行
Student student = new Student();
Student student1 = new Student();
}
}
public class Student {
public Student(){
System.out.println("构造方法执行了");
}
//跟构造方法同级的代码块,构造代码块优先于构造方法执行
{
System.out.println("构造代码块执行了");
}
//静态代码块
//静态修饰的,是随着类的加载而执行的
// 用于给类初始化,在加载的时候就执行,并且只执行一次
static {
System.out.println("我们在类加载的时候,就可以在静态代码块里面编写代码,做一些准备工作");
System.out.println("静态代码块");
}
}
面试题
A:看程序写结果
class Student {
static {
System.out.println("Student 静态代码块"); //3
}
{
System.out.println("Student 构造代码块"); //4、6
}
public Student() {
System.out.println("Student 构造方法"); //5、7
}
}
class StudentDemo {
static {
System.out.println("StudentDemo的静态代码块"); //1
}
public static void main(String[] args) {
System.out.println("我是main方法"); //2
Student s1 = new Student();
Student s2 = new Student();
}
}
执行优先级静态代码块-构造代码块-构造方法
继承
通过继承案例概述继承
public class Test {
public static void main(String[] args) {
System.out.println("=========继承=========");
//继承:就是把多个事物的共性部分,向上抽取到父类当中,以实现代码的复用性和维护性。
/*继承:父辈的财产,子代可以继承
* 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中
* 那么多个类无需再定义这些属性和行为,只要继承那个类即可。
*
* 通过extends关键字可以实现类与类的继承
* class 子类名 extends 父类名 {}
* 单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。*/
Cat cat = new Cat();
cat.name="喵喵";
cat.age=5;
System.out.println(cat.name);
System.out.println(cat.age);
cat.eat();
cat.sleep();
cat.catchMouth();
System.out.println("====================");
Dog dog = new Dog();
dog.name="石头";
dog.age=4;
System.out.println(dog.name);
System.out.println(dog.age);
dog.eat();
dog.sleep();
dog.lookDoor();
}
}
public class Animal {
String name;
int age;
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
public class Cat extends Animal{
public void catchMouth(){
System.out.println("抓老鼠");
}
}
public class Dog extends Animal{
public void lookDoor(){
System.out.println("看门");
}
}
以上代码图示
继承的优缺点
class GrandFather{
private String g="ggggggg";
public String getG() {
return g;
}
public void setG(String g) {
this.g = g;
}
public void show(){
System.out.println("爷爷中的show方法。");
}
}
class Father extends GrandFather{
private String g="ffffffffff";
public String getG() {
return g;
}
public void setG(String g) {
this.g = g;
}
public void show(){
System.out.println("爸爸中的show方法。");
super.show();
System.out.println(super.getG());
}
}
class Son extends Father{
}
继承的注意事项
public class Test {
public static void main(String[] args) {
/*注意事项:
* 1、父类的私有成员,子类不能访问
* 2、子类不能继承父类的构造方法,但是可以通过super关键字去访问父类的构造方法
* 父类的构造方法调用格式为super(···),
* 调用本类的构造方法格式为this(···)
* 3、不要为了部分功能而去继承,尽量减少继承,提高内聚,降低耦合*/
//继承其实体现了一种关系,谁是谁的一种,就可以使用继承
Son son = new Son();
System.out.println(son.getG());
son.setG("ooooooooooooo");
System.out.println(son.getG());
//访问方法
son.show();
}
}
class Father {
public Father(){
System.out.println("父类的构造方法调用了");
}
private String g="ffffffffff";
public String getG() {
return g;
}
public void setG(String g) {
this.g = g;
}
public void show(){
System.out.println("爸爸中的show方法。");
}
}
class Son extends Father {
}
继承中成员变量关系
A:子类中的成员变量和父类中的成员变量名称不一样
因为是引用类型,所以直接使用变量名,会去指定地址寻找
B:子类中的成员变量和父类中的成员变量名称一样
在子类中访问一个变量的查找顺序("就近原则")
a: 在子类的方法的局部范围找,有就使用
b: 在子类的成员范围找,有就使用
c: 在父类的成员范围找,有就使用
d:如果还找不到,就报错
public class Test {
public static void main(String[] args) {
/*父类变量的访问原则
* 在子类的方法的局部范围找,有就使用
在子类的成员范围找,有就使用
在父类的成员范围找,有就使用
如果还找不到,就报错*/
Son son = new Son();
son.show(20);
}
}
class Father {
static int num=200;
}
class Son extends Father{
static int num=600;
public void show(int num){
/*System.out.println(c);
System.out.println(a);
System.out.println(num);*/
System.out.println(num); //20
System.out.println(this.num); //600
System.out.println(super.num); //200
}
}
this和super的区别和应用
public class Test {
public static void main(String[] args) {
/*super:表示的是父类的空间标识,你可以理解为父类的一个引用,或者说是对象
* 我们就可以使用super这个关键字,去访问父类的数据
* super和this
* 访问父类的成员变量
* super.成员变量名
* 访问本类的成员变量名
* this.成员变量名
* 访问父类的成员方法
* super.成员方法名
* 访问本类的成员方法名
* this.成员方法名
* 访问父类的构造方法
* super()
* 访问本类的构造方法
* this()
* 调用的是有参构造还是空参构造是根据后面括号里面参数的个数以及参数的类型识别的*/
Son son = new Son();
son.test();
}
}
class Father{
int num=200;
int f=600;
public void Show(){
System.out.println("父类的show方法。");
};
}
class Son extends Father{
int num=20;
int f=9000;
public void Show(){
System.out.println("子类的show方法");
}
public void test(){
System.out.println(super.num); //200
System.out.println(super.f); //600
System.out.println(this.num); //20
System.out.println(this.f); //9000
System.out.println("====================");
super.Show();
this.Show();
this.Show();
}
}
继承中构造方法的关系 & 构造方法的注意事项
public class Test {
public static void main(String[] args) {
/*当我们在创建子类对象时,为什么会先去调用父类的构造方法?
*因为有了继承关系后,当我们去初始化子类的时候,子类要继承父类的一些数据
* 所以在new子类的对象的时候,会先调用父类的构造方法,来完成父类数据的初始化
* 然后再初始化自己的数据
*/
//我们在什么时候去调用父类构造呢?
/*在每个类的构造方法中的第一行有一行默认代码super();
* 这行代码就是去调用了父类的空参构造*/
/*在Java中有一个顶层 父类 Object 这个类就是老祖宗类,所有的类,都是直接或间接继承自他。*/
Son son = new Son();
}
}
class Father extends Object{
int f=100;
public Father(){
System.out.println("父类的构造方法调用了");
}
}
class Son extends Father{
int s=200;
public Son(){
System.out.println("子类的构造方法调用了");
}
}
public class Test {
public static void main(String[] args) {
/*当我们创建子类对象时,子类的构造方法的第一行会默认有一句super();
去调用父类的空参构造
若父类没有空参构造:
1、给父类提供一个空参构造
2、想办法去调用父类的有参构造*/
Son son = new Son();
Son son1 = new Son();
}
}
class Father{
/*public Father(){
System.out.println("父类的空参构造被访问");
}*/
public Father(int num){
System.out.println("父类的有参构造");
}
}
class Son extends Father{
public Son(){
super(10);
System.out.println("调用了父类的有参构造,子类的空参构造执行了");
}
public Son(int num){
this(); //访问本类的空参构造
System.out.println("子类的有参构造执行了");
}
}
继承面试题
A:案例演示
看程序写结果1
class Fu{
public int num = 10;
public Fu(){
System.out.println("fu"); //1
}
}
class Zi extends Fu{
public int num = 20;
public Zi(){
System.out.println("zi"); //2
}
public void show(){
int num = 30;
System.out.println(num);//30
System.out.println(this.num);//20
System.out.println(super.num);//10
}
}
class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
/*结果分析:
创建子类对象会去调用父类的空参构造,将父类初始化。接着再初始化子类。
最后调用子类的show方法,里面成员变量的调用遵循就近原则
所以第一个输出局部变量num=30
第二个输出本类的成员变量引用num=20
第三个输出父类的成员变量引用num=10*/
B:案例演示
看程序写结果2
class Fu {
static {
System.out.println("静态代码块Fu"); //1
}
{
System.out.println("构造代码块Fu"); //3
}
public Fu() {
System.out.println("构造方法Fu"); //4
}
}
class Zi extends Fu {
static {
System.out.println("静态代码块Zi"); //2
}
{
System.out.println("构造代码块Zi"); //5
}
public Zi() {
super();
System.out.println("构造方法Zi"); //6
}
}
class Test{
public static void main(String[] args){
Zi z = new Zi(); //请执行结果。
}
}
/*结果分析
静态代码块属于类,是随着类的加载而加载在方法区的静态区的
在同一类中,构造代码块先于构造方法执行*/
继承中成员方法的关系
当子类的方法名和父类的方法名不一样的时候,直接调用。
当子类的方法名和父类的方法名一样的时候
通过子类调用方法:
先查找子类中有没有该方法,如果有就使用
在看父类中有没有该方法,有就使用
如果没有就报错
方法重写
public class Test {
public static void main(String[] args) {
/*当子类和父类出现一摸一样的方法的时候(方法名,返回值,参数一样)
* 就会发生方法覆盖现象,称之为方法重写
* 子类方法会覆盖父类方法
*
* 因为子类方法对父类方法的功能实现不满意,所以子类要改写自己的功能实现方法
* 或者子类要扩展父类的功能*/
Son son = new Son();
son.eat();
son.sonShow();
//访问父类eat功能
son.fuView();
}
}
public class Father {
public void eat(){
System.out.println("父类的eat");
}
}
public class Son extends Father{
public void sonShow(){
System.out.println("子类的show执行了");
}
public void eat(){
System.out.println("子类的eat功能");
}
public void fuView(){
super.eat();
}
}
子类的会覆盖父类的一模一样的方法,要想访问父类的方法就需要在子类中写调用方法
方法重写概述 & 应用
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
Cat cat = new Cat();
dog.eat();
cat.eat();
}
}
class Animal{
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
class Dog extends Animal{
//方法重写
public void eat(){
System.out.println("吃骨头");
}
public void lookDog(){
System.out.println("看门");
}
}
class Cat extends Animal{
//子类对父类功能实现不满意,子类可以写一个和父类一模一样名字一样的方法,实现逻辑不一样即可
public void eat(){
System.out.println("吃鱼");
}
public void catchMouth(){
System.out.println("抓老鼠");
}
}
注意事项
A:方法重写注意事项
a:父类中私有方法不能被重写
因为父类私有方法子类根本就无法继承(其实父类的方法子类是继承了的,但是使用不了)
b:子类重写父类方法时,访问权限不能更低
最好就一致
c:父类静态方法,子类也必须通过静态方法进行重写
其实这个算不上方法重写,但是现象确实如此,至于为什么算不上方法重写,多态中会讲解
子类重写父类方法的时候,最好声明一模一样。
public class Test {
public static void main(String[] args) {
/*重写的注意事项:
* 1、父类私有的方法子类不能重写
* 2、子类在重写父类的方法时,方法前面的权限修饰符不能比父类的低,最好一样
* 3、静态方法不参与重写*/
Son son = new Son();
son.Call();
son.show();
}
}
class Father{
public void Call(){
System.out.println("012346546");
}
public static void show(){
System.out.println("父类的静态方法");
}
}
class Son extends Father{
@Override
public void Call() {
System.out.println("重写了非静态的父类方法");
}
public static void show(){
System.out.println("没有重写子类的静态方法");
}
}
案例练习
A:案例演示: 使用继承的学生和老师案例
public class Test {
public static void main(String[] args) {
/*A:案例演示: 使用继承的学生和老师案例*/
Student student = new Student();
student.name="Adair";
student.age=23;
System.out.println(student.name);
System.out.println(student.age);
student.eat();
student.sleep();
student.play();
System.out.println("==============================");
Teacher teacher = new Teacher();
teacher.name="Tom";
teacher.age=30;
System.out.println(teacher.name);
System.out.println(teacher.age);
teacher.eat();
teacher.sleep();
teacher.teach();
}
}
public class Person {
String name;
int age;
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
public class Student extends Person{
@Override
public void eat() {
System.out.println("学生爱吃麻辣烫");
}
@Override
public void sleep() {
System.out.println("学生爱睡懒觉");
}
public void play(){
System.out.println("play game");
}
}
public class Teacher extends Person{
@Override
public void eat() {
System.out.println("老师爱吃面");
}
@Override
public void sleep() {
System.out.println("老师爱早起");
}
public void teach(){
System.out.println("teach");
}
}
猫狗案例
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.breed = "黑背";
dog.name = "tony";
dog.age = 3;
System.out.println(dog.breed);
System.out.println(dog.name);
System.out.println(dog.age + "岁");
dog.eat();
dog.sleep();
dog.lookDoor();
System.out.println("===================");
Cat cat = new Cat();
cat.breed = "布偶";
cat.name = "hapi";
cat.age = 1;
System.out.println(cat.breed);
System.out.println(cat.name);
System.out.println(cat.age + "岁");
cat.eat();
cat.sleep();
cat.catchMouth();
}
}
public class Animal {
String breed;
String name;
int age;
public void eat(){
System.out.println("eat");
}
public void sleep(){
System.out.println("sleep");
}
}
public class Cat extends Animal{
//共性
/*String breed;
String name;
int age;
public void eat(){
System.out.println("eat");
}
public void sleep(){
System.out.println("sleep");
}*/
//特性
@Override
public void eat() {
System.out.println("eat fish");
}
public void catchMouth(){
System.out.println("抓老鼠");
}
}
public class Dog extends Animal{
//共性
/*String breed;
String name;
int age;
public void eat(){
System.out.println("eat");
}
public void sleep(){
System.out.println("sleep");
}*/
//特性
@Override
public void eat() {
System.out.println("eat meet");
}
public void lookDoor(){
System.out.println("看门");
}
}
final关键字
由于继承中有一个方法重写的现象,而有时候我们不想让子类去重写父类的方法.这对这种情况java就给我们提供了一个关键字: final
final关键字是最终的意思,可以修饰类,变量,成员方法。
修饰类 & 方法 & 变量特点
public class Test {
public static void main(String[] args) {
/*final 最终的 可以修饰变量,可以修饰方法,可以修饰类*/
//final修饰变量,此变量为一个常量
//常量名一般大写
final int num=100;
//num=200; 报错
System.out.println(num);
final double A=3.14; //自定义常量
System.out.println(A);
//final修饰类,此类不能被继承
//final修饰方法,此方法不能被重写,只能继承使用
//final修饰引用类型,指地址值不能改变
}
}
//final修饰类,此类不能被继承
final class Father{
}
//class Son extends Father{} 报错
class fu{
public void show(){}
public final void test(){}
}
class zi extends fu{
@Override
public void show() {
}
/*@Override
public final void test() {
}
报错,不能重写*/
}
方法重写的现象,而有时候我们不想让子类去重写父类的方法.这对这种情况java就给我们提供了一个关键字: final==
final关键字是最终的意思,可以修饰类,变量,成员方法。
修饰类 & 方法 & 变量特点
public class Test {
public static void main(String[] args) {
/*final 最终的 可以修饰变量,可以修饰方法,可以修饰类*/
//final修饰变量,此变量为一个常量
//常量名一般大写
final int num=100;
//num=200; 报错
System.out.println(num);
final double A=3.14; //自定义常量
System.out.println(A);
//final修饰类,此类不能被继承
//final修饰方法,此方法不能被重写,只能继承使用
//final修饰引用类型,指地址值不能改变
}
}
//final修饰类,此类不能被继承
final class Father{
}
//class Son extends Father{} 报错
class fu{
public void show(){}
public final void test(){}
}
class zi extends fu{
@Override
public void show() {
}
/*@Override
public final void test() {
}
报错,不能重写*/
}