继承

继承

  1. 继承的概念:
    继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义(重写),以及追加属性和方法(添加额外的父类没有的子类特有的方法)
  2. 实现继承的格式
  • 继承通过extends实现
  • 格式:class 子类 extends 父类 { }
    举例:class Dog extends Animal { }
  1. 继承带来的好处
  • 继承可以让类与类之间产生关系,即子父类关系。产生子父类关系后,子类则可以使用父类中非私有的成员变量和成员方法
  • 而且子类想要有自己的特有的方法可以自己添加或重写
  1. 子类又称作派生类
    父类又称作基类、超类
  2. 子类的特点是:
  • 可以继承父类的可访问的成员变量和方法
  • 可以有自己的成员变量和方法
  • 静态方法、静态成员变量也可以被子类继承(private的不会)
package com.liudashuai;

public class Demo2 {
    public static String s="父类的静态变量";
    int i=12;
    public static void f(){
        System.out.println("父类的静态方法");
    }
}
package com.liudashuai;

public class Demo1 extends Demo2{
    public static void main(String[] args) {
        Demo1 demo1=new Demo1();
        String s1 = demo1.s;
        System.out.println(s1+" "+s);//说明静态变量是可以被继承
        demo1.f();//说明静态方法也是可以被继承
        System.out.println(demo1.i);//说明靠对象也是可以访问静态变量的,且说明不一定要public的属性才被继承
    }
}
  1. 继承的完整例子
public class Fu {
    public void show() {
        System.out.println("show方法被调用");
    }
}
public class Zi extends Fu {
    public void method() {
        System.out.println("method方法被调用");
    }
}
public class Demo {
    public static void main(String[] args) {
        //创建对象,调用方法
        Fu f = new Fu();
        f.show();

        Zi z = new Zi();
        z.method();
        z.show();
    }
}
  1. 继承的好处
  • 提高了代码的复用性(多个类相同的成员可以放到同一个父类中)
  • 提高了代码的维护性(如果方法的代码需要修改,修改父类的一处方法即可)
  1. 继承弊端
  • 继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性。
  1. 什么时候适合使用继承关系呢?
    答:符合is a关系时:
    is…a的关系指的是:谁是谁的一种。例如:老师和学生是人的一种,那人就是父类,学生和老师就是子类。
    你看猫是狗的一种,就说不同,所以要是把猫作为子类,狗作为父类就不科学。这个设计父子类设计时要符合生活常识。

变量访问的特点

  1. 子类方法中访问一个变量
  • 先在子类的局部变量找,要是找到就用这个局部变量的值(就算有一个名字一模一样的成员变量,那也不会去访问哪个成员变量的)
  • 然后要是在局部变量里面找不到的话,就去成员变量去去找
  • 要是成员变量找不到的话,就去父类的成员变量去找
  • 要是父类没有就找父类的父类
  • ……
  • 要是都没有找到就报错
  1. 例子:
class Fu {
    int num = 10;
}
class Zi {
    int num = 20;
    public void show(){
        int num = 30;
        System.out.println(num);
    }
}
public class Demo1 {
    public static void main(String[] args) {
        Zi z = new Zi();
        z.show();	// 输出show方法中的局部变量30
    }
}
  1. 我对继承的理解:
    子类拿到了父类的所有方法,但是子类看不见父类的private的方法和属性,不管是静态的方法和普通的成员方法都是可以拿到的。相当于子类里原封不动地写了父类所有的方法和属性(除了修饰符)。修饰符的作用还是跟随父类,即父类设置了private或不设置(父类同包下的类可以访问),那子类原封不动写下的父类方法的访问范围还是得看父类那个原始写的位置(相当于子类继承了全部方法,然后有些方法被修饰符给隐藏了)。且要是父类重写了父类的父类的方法,那么子类是继承父类重写的方法,super关键字也是访问父类重写的那个方法,要是父类没有重写爷类的那个方法,那么就是父类继承了爷类的那个方法,那么你用super也是调用那个父类继承爷类的那个方法。

super&this

this&super关键字:

  • this:代表本类对象(且是调用this所在方法的那个对象)的引用
  • super:代表父类存储空间的标识(可以理解为父类对象引用),调用上一级的那个类的方法或属性。(父类有就不会去调用爷类,父类没有但是爷类有,那么父类会继承爷类的那个方法,super也是调用那个爷类的方法)

super和this关键字的使用(shis()和super()在构造方法使用都得放在第一句,所以一个构造方法中不能有super()有有this(),但是默认的super(),即你不写super(),然后在构造方法中的第一句写this是可以的)(this.XX()方法和super.XX()方法不要求一定要写第一句)(this()和super()只能在构造方法中使用,且只能是第一句)

  • 成员变量:
  • this.成员变量 - 访问本类成员变量
  • super.成员变量 - 访问父类成员变量
  • 成员方法:
  • this.成员方法 - 访问本类成员方法
  • super.成员方法 - 访问父类成员方法
  • 构造方法:
  • this(…) - 访问本类构造方法
  • super(…) - 访问父类构造方法

注意点:不能在静态的方法中使用this和super关键字。为什么呢?

首先来了解下static 关键字

当一个方法和属性被static属性修饰时,这些方法和属性是优先于对象加载进入内存的,是随着类的加载而加载的

this关键字的理解this是当前对象的引用,super是指父类的引用

当静态方法加载进内存进栈时,如果在静态方法中有this 和 super 关键字时,this和super也被加载到了内存,但是这个时候并没有对象的引用,this和super没有初始化,所有编译会报错。

但是成员方法里可以使用super关键字来访问父类的静态方法或属性。(可以说是this是指调用那个写有this的那个方法的对象,而super是去调用那个调用写有super的方法的那个对象里面的父类继承的方法或属性)

构造方法中的默认super

  1. 继承中构造方法的访问特点
    注意:子类中所有的构造方法默认隐藏地有一个super(),都会访问父类中无参的构造方法
    子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,原因在于,每一个子类构造方法的第一条语句默认都是:super()。但是你只要自己写了super(……)那个默认隐藏的super()就失效了。
    问题:如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?
  • 通过使用super关键字去显示的调用父类的带参构造方法
  • 在父类中自己提供一个无参构造方法

推荐方案:

自己给出无参构造方法

  1. 执行过程:
package com.liudashuai;

public class Demo3 extends Demo2{
    public static void main(String[] args) {
        Demo2 demo2=new Demo2(11);//1
    }//12
}
package com.liudashuai;

public class Demo2 extends Demo1{
    int a=1;//8
    int b=2;//9
    public Demo2(int i) {//2
        super(18);//3
        int zz=15;//11
    }
    public Demo2() {
        super(19);
    }
    int i=11;//10
}
package com.liudashuai;

public class Demo1{
    int h=12;//5
    int j=13;//6

    public Demo1(int x) {//4
        int k=11;//7
    }
}

参数列表的变量先执行,然后执行super,然后执行父类的构造方法的参数列表,然后执行父类的成员变量(假设父类上面没有父类了,不然还得先继续执行父类的super),然后执行父类构造方法中剩下的语句,然后执行调用父类构造方法的那个类的成员变量,然后执行那个类的剩下的语句。总之先执行参数列表,然后super,然后成员变量,然后构造方法剩下的语句。

要是有super.方法();这个是不会先执行的,他是和普通方法一样,不会先去执行这个super.方法();

如下

package com.liudashuai;

public class Demo2 extends Demo1{
    int s=15;//7
    public Demo2() {//2
        super.f();//这个不是3哦他是和下面的g()一样的没有像super()这样优先于成员方法执行。//8
        g();//10
        int ff=45;//12
    }

    private void g() {
        System.out.println("hello");//11
    }
    public static void main(String[] args) {
        Demo2 demo2=new Demo2();//1
    }//13
}
package com.liudashuai;

public class Demo1{
    int a=12;//4
    int b=13;//5

    public Demo1() {//3
        int x=65;//6
    }

    protected void f() {
        int i=11;//9
    }
}
  1. super内存图
  • 对象在堆内存中,会单独存在一块super区域,用来存放父类的数据 (就是你new了一个子类,子类默认会调用那个super()方法创建一个父类的对象,且他们是连在一起的,所以子类的地址001可以访问父类的对象的内容,但是他们又是有一个线隔开的,父类的在一边,子类的在一边,然后子类001这个地址优先是访问子类的变量,要是有就用没有再去找父类的成员变量,要是没有继续向下一个父类找,直到找到为止或找不到报错。访问方法也是一样的先在子类找,再到父类找,子类可以重写父类的方法,但是方法不在堆里面,所以这里没有画,但是找的规则是差不多的,自己理解就行了,不用画。)

Java中子类和继承的考试题 java子类与继承知识点_jvm

方法的访问特点

方法中访问某个子类对象的一个方法,那么他的查找顺序是:

  1. 先在子类成员方法范围找,要是找不到
  2. 就在父类成员方法范围找
  3. 如果继续找不到继续向爷类的成员方法里找
  4. ……
  5. 找完所有父类都没有找到就报错

重写

  1. 重载注意点:
    (即静态方法和非静态方法也可以构成重载,只要方法名参数列表不一样)
    这样的
public void f(){}
//public static void f(){
//}这样是错误的不构成重载的,即重载不看static
public static void g(int i){}
public int g(){}//这样也构成重载
static void h(int i){}
static void h(){}//这个也构成重载
  1. 什么是方法重写:子类出现了和父类中一模一样的方法声明。(方法名一样,参数列表也必须一样)
  2. 重写的话,必须子类和父类的那个方法的static、方法名、参数列表都是相同的(父类和子类两个方法都是有static的,返回类型和方法名和参数列表都一样不会报错,但是这个不是叫重写,叫隐藏,所以我们重写不去看static和非static方法有没有构成重写也不去看static和static方法有没有构成重写。其实重写是为了运行时多态,而静态方法初始化时就和类做了绑定,哪来的什么多态特征,所以静态方法不能被重写,也没必要重写)。但是下面这样是可以的。
package com.liudashuai;

public class Demo2 extends Demo1{
    public static Integer f(int i, int j){
        System.out.println("hello");
        return 1;
    }
}
package com.liudashuai;

public class Demo1{
    static Number f(int i,int j){
        System.out.println("nihao");
        return 1;
    }
}

就是子类的static会隐藏父类的static的方法名和参数列表都相同的那个方法(注意是隐藏,而不是重写)

且要是子类方法和父类的方法要是方法名和参数列表一样,但是一个有static有没有就会出错。(所以不存在判断static和非static方法是否重写,也不存在判断static方法和static方法之间有没有构成重写)

package com.liudashuai;

public class Demo1{
    static Number f(int i,int j){
        System.out.println("nihao");
        return 1;
    }
}
package com.liudashuai;

public class Demo2 extends Demo1{
     //Number f(int i,int j){提示错误
       // System.out.println("nihao");
        //return 1;
    //}
}
  1. 方法重写的应用场景
  • 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的其他功能,又可以定义了子类特有的方法去覆盖父类的那个方法。
  1. 重写的Override注解
  • 用来检测当前的方法,是否是重写的方法,起到【校验】的作用。就是检查你写的方法有没有严格符合重写的格式。
  1. 注意事项:
  • 子类重写父类的方法时,修饰符可以不一样,但是要求子类的访问权限不能低于父类的访问权限(子类访问权限要更大才行)
  • 父类的私有方法不能重写也不能被继承(你理解为子类继承了但是看不见也行)
  • 子类重写的方法抛出异常的范围不能比父类那个被重写方法抛出异常的范围更大,可以相同。
  • 子类重写方法的返回类型也可以和父类的返回类型不一样
    但是,子类重写方法的返回类型得是父类被重写方法的返回类型的子类父子类重写和被重写方法的返回类型一样
    比如:
package com.liudashuai;

public class Demo1{
    Number f(int i,int j){
        System.out.println("nihao");
        return 1;
    }
}
package com.liudashuai;

public class Demo2 extends Demo1{
    public Integer f(int i, int j){
        System.out.println("hello");
        return 1;
    }
}

java继承的注意事项

  1. java中继承的注意事项
  • Java中类只支持单继承,不支持多继承(但是可以实现多个接口,单继承,多实现
  • 错误范例:class A extends B, C { }
  • Java中类支持多层继承

例子:

public class Granddad {

    public void drink() {
        System.out.println("爷爷爱喝酒");
    }

}

public class Father extends Granddad {

    public void smoke() {
        System.out.println("爸爸爱抽烟");
    }

}

public class Mother {

    public void dance() {
        System.out.println("妈妈爱跳舞");
    }

}
public class Son extends Father {
	// 此时,Son类中就同时拥有drink方法以及smoke方法
}

  1. 包是什么,作用是什么
    包就是文件夹,作用是:用来管理类文件的
  2. 包的定义格式
  • package 包名; (多级包用.分开)
  • 例如:package com.h;相当于在模块文件夹下,建了一个com文件夹,又在com包下建了一个h文件夹。
  1. 通过记事本写的程序如何来运行有带包名的程序(如果没有IDEA和eclipse的情况下)(这个了解就行了)
    带包编译&带包运行(在cmd下操作的)
  • 带包编译:javac –d . 类名.java
  • 例如:javac -d . com.heima.demo.HelloWorld.java
  • 带包运行:java 包名+类名
  • 例如:java com.heima.demo.HelloWorld

import

  1. 要是没有import
    你要使用别的包下的某个类,就得这样,写全限定类名。(本包下的类可以直接用类名访问,不用导包)
package com.heima;

public class Demo {
    public static void main(String[] args) {
        // 1. 没有导包,创建Scnaner对象
        java.util.Scanner sc = new java.util.Scanner(System.in);
    }
}
  1. 但是用import的话,就不用写那个前缀了,直接写类名就行了,简便了很多。
package com.heima;

import java.util.Scanner;//这个是导入那个java.util下的这个Scanner这个类

public class Demo {
    public static void main(String[] args) {
        // 1. 没有导包,创建Scnaner对象
        Scanner sc = new Scanner(System.in);
    }
}

修饰符

权限修饰符

Java中子类和继承的考试题 java子类与继承知识点_开发语言_02

状态修饰符

状态修饰符是:final和static

  1. final
  • fianl关键字的意思
  • final代表最终的意思,可以修饰成员方法,成员变量,类
  • final修饰类、方法、变量的效果
  • fianl修饰类:这个被修饰的类叫最终类,该类不能被继承(不能有子类,但是可以有父类)
  • final修饰方法:被修饰的方法叫最终方法,该方法不能被子类重写,但是子类可以用父类的那个final修饰的方法。
  • final修饰变量:表明该变量是一个常量,不能再次赋值。
  • final修饰局部变量要注意的是:
  • fianl修饰基本数据类型变量
  • final 修饰指的是基本类型的数据值不能发生改变
  • final修饰引用数据类型变量
  • final 修饰指的是引用类型的地址值不能发生改变,但是地址里面的内容是可以发生改变的(即比如,你声明Student类型的变量s时用final修饰,那么这是s的指向不能变了,他的地址不能变。但是s这个对象里面的对象属性可以变。)
  • 举例:
public static void main(String[] args){
    final Student s = new Student(23);
  	s = new Student(24);  // 错误
 	s.setAge(24);  // 正确
}
  1. static关键字
  • static的概念
  • static关键字是静态的意思,可以修饰【成员方法】,【成员变量】。修饰成员变量就叫静态变量或叫类变量,修饰成员方法就叫静态方法
  • static修饰的特点
  1. 被类的所有对象共享,这也是我们判断是否使用静态关键字的条件
  2. 可以通过类名调用,也可以通过对象名调用**【推荐使用类名调用】**
  • 例子
class Student {

    public String name; //姓名
    public int age; //年龄
    public static String university; //学校	共享数据!所以设计为静态!

    public void show() {
        System.out.println(name + "," + age + "," + university);
    }

}

public class StaticDemo {
    public static void main(String[] args) {
	    // 为对象的共享数据赋值
        Student.university = "传智大学";

        Student s1 = new Student();
        s1.name = "林青霞";
        s1.age = 30;
        s1.show();

        Student s2 = new Student();
        s2.name = "风清扬";
        s2.age = 33;
        s2.show();
    }
}
  • static的访问特点
  • 非静态的成员方法
  • 能访问静态的成员变量
  • 能访问非静态的成员变量
  • 能访问静态的成员方法
  • 能访问非静态的成员方法
  • 静态的成员方法
  • 能访问静态的成员变量
  • 能访问静态的成员方法
  • 总结成一句话就是:
  • 静态成员方法只能访问静态成员方法,但是非静态成员方法可以直接访问静态的成员方法,当然静态成员方法访问静态成员方法访问成员方法肯定可以
  • 注意点:static的成员方法可以new出对象用 " 对象.方法名() " 来访问,也可以用 " 类名.方法名() "来直接用,且要是在同一个类下的成员方法和静态方法都可以直接用。但是成员方法只能new出来然后用 " 对象.方法名() " 来访问,或者同类下,成员方法可以直接访问和使用。