java基础面试:继承、final关键字、抽象类、接口

继承

  • 子类能继承父类的非私有成员变量和成员方法。

  • 继承后子类的对象由子类与父类共同组成,每次new出来的对象都是由父类与子类中的所有成员共同组成,所谓的父类中的private无法被继承是指无法访问private修饰的成员,并不是private修饰的成员不存在,就如同单独的一个类中同样无法通过对象去访问它的私有成员

虽然private修饰的父类的私有成员无法直接通过.来访问,但是父类的私有变量同样会在子类对象所存的地址对应的堆内存中开辟空间,可以通过父类方法中的set和get方法来访问

调用父类的public方法时,通过地址找到堆内存中类的地址,再通过类的地址找到子类,然后通过子类找到父类

访问修饰符

java基础面试:继承、final关键字、抽象类、接口_第1张图片project类型:是可以在任意包下继承父类的子类里访问,不是子类对象可以访问

单继承

  • java是单继承的:一个子类只能继承一个父类,但是一个父类可以被多个子类继承
  • A继承了父类B,就不能再继承其他的父类,但是父类B还可以被C继承
  • java不支持多继承,但是支持多层继承,如:A继承B,B继承C

Object

  • Object类是所有类的祖宗,所有类都是Object类的子类或子孙类

方法重写

概念

    当子类觉得父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称,参数列表均与父类一样的方法来覆盖父类的方法

注意事项

  •     重写后,方法的访问遵循就近原则
  •     使用Override注解表示重写
  •     子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限(public>protected>缺省)。
  •     重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。
  •     私有方法、静态方法不能被重写

子类中访问其它成员的特点

  •     在子类方法中访问成员变量和成员方法时,按照就近原则
  •         子类方法中访问成员变量优先级:局部变量 > 子类成员变量 > 父类成员变量
  •         子类方法中调用重写的方法,会自动调用子类中重写后的
  •         如果想访问父类成员,需要用super关键字
  •         如果想访问子类成员,需要用this关键字
     
子类构造器的特点
  • 子类的全部构造器,会先默认调用父类的无参构造器,在执行自己的构造器

  • 如果父类没有无参构造器,则必须在子类构造器中显式调用父类的有参构造器

子类构造器调用父类构造器的常用应用场景
  • 需要对父类和子类的成员变量同时进行初始化时

final

final关键字可以修饰类、方法和变量
  • 修饰类:该类被称为最终类,特点是不能被继承了。

    • 一般在工具类中使用
  • 修饰方法:该方法被称为最终方法,特点是不能被重写了。

  • 修饰变量:该变量只能被赋值一次。(必须在初始化时赋值)

  • final可以用来修饰局部变量和成员变量(实例成员变量和静态成员变量)

  • final修饰基本类型变量时,变量存储的数据不能被改变

  • final修饰引用类型的变量时,变量存储的地址不能变,但是地址指向的对象的内容可以改变

常量
  • 概念
    • 使用static final修饰的已经初始化的成员变量
  • 作用
    • 通常用于记录系统的配置信息
  • 命名规范
    • 使用大写英文单词,多个单词使用下划线连接起来
  • 使用常量记录系统配置信息的优势
    • 代码可读性更好
    • 可维护性更好
  • 执行原理
    • 程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的。也就是说不会影响性能,这些常量不会在运行时才找值,而是在编译后就将所有常量直接替换成需要的字面量

抽象类abstract

  • 抽象类
    • abstract修饰的类
  • 抽象方法
    • abstract修饰的方法
    • 抽象方法中不能有方法体,只能由方法签名
  • 抽象类注意事项
    • 抽象类中不一定有抽象方法,有抽象方法的类一定为抽象类

  • 类该有的成员(成员变量,方法,构造器)抽象类都可以有,也就是说抽象类中既可以有抽象方法,也可以有实例方法,只要类中有一个抽象方法则该类就是抽象类
  • 一个类继承抽象类,必须重写该类所有的抽象方法,否则必须将当前类也定义为抽象类
  • 抽象类特点
    • 抽象类不允许创建对象,仅作为一种特殊的父类,让子类继承并实现
  • 抽象类的好处
    • 父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们设计这样的抽象类是为了更好的支持多态。
抽象类常见应用场景
  • 模板方法设计模式
    • 解决方法中存在部分重复代码的问题
  • 写法
    • 定义一个抽象类
    • 在类中写两个方法
      • 一个为模板方法:将相同代码放入
        • 最好使用final来修饰模板方法
      • 一个为抽象方法:将具体实现交给子类

接口

  • 使用interface定义接口
  • 接口不能创建对象
  • 接口中只能由属性和抽象方法
    •     属性默认为常量,默认使用public static final修饰
    •     方法默认是抽象方法,默认使用public abstract修饰
  • 接口需要被类使用implements实现,实现接口的类叫实现类
  • 一个实现类可以实现多个接口,但是必须要重写所有接口的抽象方法,否则要将实现类定义为抽象类
接口的好处
  • 弥补了类单继承的不足,一个类同时可以实现多个接口。

  • 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现。

JDK8之后接口中新增的三种方法
  • 默认方法,使用default修饰,可以被重写,但没必要
  • 私有方法,使用private修饰,只能在接口内部调用
  • 静态方法:使用static修饰

新增的三种方法的好处

  •     增加了接口的能力,更便于项目的扩展和使用
  •     在实际开发中,如果有100个类实现了某一个接口,那么当该接口需要新增一个功能时,对应的100个实现类都需要重写该新增的方法,那么工作量会很大,而现在只要使用新增的三种方法则只需要操作接口即可,实现类会自动继承新增的默认方法,也可通过接口直接调用新增的静态方法
//接口
public interface A {
    /*
    * 接口中的默认方法(实例方法)
    * 1. 必须使用default关键字修饰,默认被public修饰
    * 2. 接口中的默认方法,可以通过接口的实现类对象,直接调用
    * 3. 接口中的默认方法,也可以被接口的实现类进行覆盖重写
    */
    default void method1(){
        System.out.println("A接口的默认方法");
        method2();
    }

    /*
    * 接口中的私有方法(实例方法)
    * 1. 必须使用private关键字修饰
    * 2. 只能在接口中被调用
    * 3. JDK9之后才有私有方法,可以被接口中的默认方法或者静态方法调用
    */
    private void method2() {
        System.out.println("A接口的私有方法");
    }

    /*
    * 接口中的静态方法(类方法)
    * 1. 必须使用static关键字修饰,默认被public修饰
    * 2. 接口中的静态方法,可以通过接口名直接调用
    */
    static void method3(){
        System.out.println("A接口的静态方法");
    }
}
//实现类
public class B implements A{
}
//测试类
public class Test {
    public static void main(String[] args) {
        A a = new B();
        a.method1();
        A.method3();
    }
}
/*
result:
        A接口的默认方法
        A接口的私有方法
        A接口的静态方法
*/

接口的多继承

一个接口可以继承多个接口

好处

  • 便于实现类去实现接口

    • 比如A接口继承了B和C接口,那么实现类只需要实现A接口,就可以实现A,B,C三个接口,此时实现类必须重写A,B,C三个接口中的全部方法

接口其他注意事项
  • 一个接口继承多个接口,如果多个接口中存在方法签名不一致,则此时不支持多继承。

    • 此时当前接口不知道应该继承哪个方法
  • 一个接口继承多个接口,如果多个接口中存在方法签名一致,则此时只需要重写一次即可,支持多继承

//一个接口继承多个接口,如果多个接口中存在方法签名不一致,则此时不支持多继承。
interface D{
    void test();
}
interface E{
    String test();
}
//会报错,无法继承
interface F extends D,E{
}
//一个接口继承多个接口,如果多个接口中存在方法签名一致,则此时只需要重写一次即可,支持多继承
public class Test1 implements C{
    @Override
    public void test() {
        System.out.println("test");
    }
    
}
interface A{
    void test();
}
interface B{
    void test();
}
interface C extends A,B{

}

一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的。

//一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的。
public class Test3 {
    public static void main(String[] args) {
        T3 t3 = new T3();
        t3.m1();//没有重写的情况下,优先使用父类的方法
    }
}

class T1 {
    public void m1() {
        System.out.println("T1.m1");
    }
}
interface T2 {
    default void m1() {
        System.out.println("T2.m1");
    }
}
class T3 extends T1 implements T2 {
}
/*
result:
		T1.m1	
*/

一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。

//一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
public class Test4 {
    public static void main(String[] args) {
        C3 c3 = new C3();
        c3.hi();
    }
}
interface C1{
    void hi();
}
interface C2{
    void hi();
}
class C3 implements C1,C2{
    @Override
    public void hi() {
        System.out.println("hi");
    }
}

你可能感兴趣的:(java,面试,开发语言)