02.Java面向对象问题

  1. 云栖社区>
  2. 博客>
  3. 正文

02.Java面向对象问题

潇湘剑雨 2018-12-24 16:36:30 浏览976

目录介绍

  • 2.0.0.1 重载和重写的区别?重载和重写绑定机制有何区别?父类的静态方法能否被子类重写?
  • 2.0.0.2 封装、继承、多态分别是什么?
  • 2.0.0.3 接口和抽象类的区别是什么?接口的意义是什么?抽象类的意义是什么?如何选择抽象类和接口?
  • 2.0.0.4 什么是内部类,有哪些?有什么作用?静态内部类和非静态内部类的区别?
  • 2.0.0.5 为什么内部类调用的外部变量必须是final修饰的?
  • 2.0.0.6 Java实现多态有哪些必要条件?具体怎么实现?多态的实现原理?多态的作用?
  • 2.0.0.7 什么是多态?多态的实现方式有哪些?多态有哪些弊端?
  • 2.0.0.9 静态变量和成员变量的区别?代码块有哪些?构造代码块和构造方法哪一个先执行?
  • 2.0.1.0 抽象类具有什么特点?抽象类和普通类有何区别?抽象类可以new吗?会出现什么问题?

好消息

  • 博客笔记大汇总【15年10月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计500篇[近100万字],将会陆续发表到网上,转载请注明出处,谢谢!
  • 链接地址:https://github.com/yangchong211/YCBlogs
  • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!所有博客将陆续开源到GitHub!

2.0.0.1 重载和重写的区别?重载和重写绑定机制有何区别?父类的静态方法能否被子类重写?

  • 重载

    • 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。   
  • 重写

    • 重写表示子类重写父类的方法
    • 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。
  • 重载和重写绑定机制有何区别?

    • 重载:类内多态,静态绑定机制(编译时已经知道具体执行哪个方法),方法同名,参数不同
    • 重写:类间多态,动态绑定机制(运行时确定),实例方法,两小两同一大(方法签名相同,子类的方法所抛出的异常、返回值的范围不大于父类的对应方法,子类的方法可见性不小于父类的对应方法)方法签名相同,子类的方法所抛出的异常、返回值的范围不大于父类的对应方法,子类的方法可见性不小于父类的对应方法
  • 父类的静态方法能否被子类重写

    • 父类的静态方法是不能被子类重写的,其实重写只能适用于实例方法,不能用于静态方法,对于上面这种静态方法而言,我们应该称之为隐藏。
    • 技术博客大总结
    • Java静态方法形式上可以重写,但从本质上来说不是Java的重写。因为静态方法只与类相关,不与具体实现相关。声明的是什么类,则引用相应类的静态方法(本来静态无需声明,可以直接引用)。并且static方法不是后期绑定的,它在编译期就绑定了。换句话说,这个方法不会进行多态的判断,只与声明的类有关。

2.0.0.2 面向对象编程的四大特性及其含义?封装、继承、多态分别是什么?

  • 封装

    • 将某事物的属性和行为包装到对象中,构成一个不可分割的独立实体。
    • 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。
  • 继承

    • 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。
    • 注意

      • 子类拥有父类非 private 的属性和方法。
      • 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
      • 子类可以用自己的方式实现父类的方法。
  • 多态

    • 所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
    • 在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。
  • 抽象

    • 对现实世界的事物进行概括,抽象为在计算机虚拟世界中有意义的实体

2.0.0.3 接口和抽象类的区别是什么?接口的意义是什么?抽象类的意义是什么?如何选择抽象类和接口?

  • 接口和抽象类的区别是什么

    • 接口的方法默认是 public,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),抽象类可以有非抽象的方法
    • 接口中的实例变量默认是 final 类型的,而抽象类中则不一定
    • 一个类可以实现多个接口,但最多只能实现一个抽象类
    • 一个类实现接口的话要实现接口的所有方法,而抽象类不一定
    • 接口不能用 new 实例化,但可以声明,但是必须引用一个实现该接口的对象 从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
  • 接口的作用是什么

    • 技术博客大总结
    • 1、重要性:在Java语言中, abstract class 和interface 是支持抽象类定义的两种机制。正是由于这两种机制的存在,才赋予了Java强大的 面向对象能力。
    • 2、简单、规范性:如果一个项目比较庞大,那么就需要一个能理清所有业务的架构师来定义一些主要的接口,这些接口不仅告诉开发人员你需要实现那些业务,而且也将命名规范限制住了(防止一些开发人员随便命名导致别的程序员无法看明白)。
    • 3、维护、拓展性:比如你要做一个画板程序,其中里面有一个面板类,主要负责绘画功能,然后你就这样定义了这个类。可是在不久将来,你突然发现这个类满足不了你了,然后你又要重新设计这个类,更糟糕是你可能要放弃这个类,那么其他地方可能有引用他,这样修改起来很麻烦。
    • 如果你一开始定义一个接口,把绘制功能放在接口里,然后定义类时实现这个接口,然后你只要用这个接口去引用实现它的类就行了,以后要换的话只不过是引用另一个类而已,这样就达到维护、拓展的方便性。
    • 4、安全、严密性:接口是实现软件松耦合的重要手段,它描叙了系统对外的所有服务,而不涉及任何具体的实现细节。这样就比较安全、严密一些(一般软件服务商考虑的比较多)。
  • 抽象类的意义是什么

    • 1.因为抽象类不能实例化对象,所以必须要有子类来实现它之后才能使用。这样就可以把一些具有相同属性和方法的组件进行抽象,这样更有利于代码和程序的维护。
    • 2.当又有一个具有相似的组件产生时,只需要实现该抽象类就可以获得该抽象类的那些属性和方法。
  • 如何选择抽象类和接口?

    • 使用接口:

      • 需要让不相关的类都实现一个方法,例如不相关的类都可以实现 Compareable 接口中的 compareTo() 方法;
      • 需要使用多重继承。
    • 使用抽象类:

      • 需要在几个相关的类中共享代码。
      • 需要能控制继承来的成员的访问权限,而不是都为 public。
      • 需要继承非静态和非常量字段。

2.0.0.4 什么是内部类,有哪些?有什么作用?静态内部类和非静态内部类的区别?

  • 什么是内部类

    • 内部类就是定义在另外一个类里面的类。它隐藏在外部类中,封装性更强,不允许除外部类外的其他类访问它;但它可直接访问外部类的成员。
  • 内部类有哪些

    • 成员内部类:成员内部类是外围类的一个成员,是依附于外围类的,所以,只有先创建了外围类对象才能够创建内部类对象。也正是由于这个原因,成员内部类也不能含有 static 的变量和方法;
    • 静态内部类:静态内部类,就是修饰为static的内部类,该内部类对象不依赖于外部类对象,就是说我们可以直接创建内部类对象,但其只可以直接访问外部类的所有静态成员和静态方法;
    • 局部内部类:局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效;
    • 匿名内部类:定义匿名内部类的前提是,内部类必须要继承一个类或者实现接口,格式为 new 父类或者接口(){定义子类的内容(如函数等)}。也就是说,匿名内部类最终提供给我们的是一个 匿名子类的对象。
  • 静态内部类和非静态内部类的区别有:

    • 静态内部类是指被声明为static的内部类,可不依赖外部类实例化;而非静态内部类需要通过生成外部类来间接生成。
    • 静态内部类只能访问外部类的静态成员变量和静态方法,而非静态内部类由于持有对外部类的引用,可以访问外部类的所用成员

2.0.0.5 为什么内部类调用的外部变量必须是final修饰的?

  • 为什么内部类调用的外部变量必须是final修饰的?

    • 简单解答:一方面,由于方法中的局部变量的生命周期很短,一旦方法结束变量就要被销毁,为了保证在内部类中能找到外部局部变量,通过final关键字可得到一个外部变量的引用;另一方面,通过final关键字也不会在内部类去做修改该变量的值,保护了数据的一致性。
    • 详细一点可以这样说:因为生命周期的原因。方法中的局部变量,方法结束后这个变量就要释放掉,final保证这个变量始终指向一个对象。首先,内部类和外部类其实是处于同一个级别,内部类不会因为定义在方法中就会随着方法的执行完毕而跟随者被销毁。问题就来了,如果外部类的方法中的变量不定义final,那么当外部类方法执行完毕的时候,这个局部变量肯定也就被GC了,然而内部类的某个方法还没有执行完,这个时候他所引用的外部变量已经找不到了。如果定义为final,java会将这个变量复制一份作为成员变量内置于内部类中,这样的话,由于final所修饰的值始终无法改变,所以这个变量所指向的内存区域就不会变。为了解决:局部变量的生命周期与局部内部类的对象的生命周期的不一致性问题

2.0.0.7 什么是多态?多态实现条件?多态的实现方式有哪些?

  • 什么是多态?

    • 多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
  • 多态实现条件?

    • Java实现多态有三个必要条件:继承、重写、向上转型。
    • 继承:在多态中必须存在有继承关系的子类和父类。
    • 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
    • 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
  • 多态的实现方式有哪些?

    • 多态作用:多态性就是相同的消息使得不同的类做出不同的响应。
    • 第一种实现方式:基于继承实现的多态

      • 基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。多态的表现就是不同的对象可以执行相同的行为,但是他们都需要通过自己的实现方式来执行,这就要得益于向上转型了。
      public class MainJava {
          public static void main(String[] args) {
              //定义父类数组
              Wine[] wines = new Wine[2];
              //定义两个子类
              Test1 test1 = new Test1();
              Test2 test2 = new Test2();
              Wine win e = new Wine();
              //父类引用子类对象
              wines[0] = test1;
              wines[1] = test2;
              for(int i = 0 ; i < 2 ; i++){
                  System.out.println(wines[i].toString() + "--" + wines[i].drink());
              }
              System.out.println("-------------------------------");
              System.out.println(test1.toString() + "--" + test1.drink());
              System.out.println(test2.toString() + "--" + test2.drink());
          }
          public static class Wine {
              private String name;
              public String getName() {
                  return name;
              }
              public void setName(String name) {
                  this.name = name;
              }
              public String drink(){
                  return "喝的是 " + getName();
              }
              public String toString(){
                  return null;
              }
          }
      
          public static class Test1 extends Wine{
              public Test1(){
                  setName("Test1");
              }
              public String drink(){
                  return "喝的是 " + getName();
              }
              public String toString(){
                  return "Wine : " + getName();
              }
          }
      
          public static class Test2 extends Wine{
              public Test2(){
                  setName("Test2");
              }
              public String drink(){
                  return "喝的是 " + getName();
              }
              public String toString(){
                  return "Wine : " + getName();
              }
          }
      }
    • 第二种实现多态的方式:基于接口实现的多态

      • 继承是通过重写父类的同一方法的几个不同子类来体现的,那么就可就是通过实现接口并覆盖接口中同一方法的几不同的类体现的。
      • 在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。
      • 继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。
  • 多态有哪些弊端?

2.0.0.9 静态变量和成员变量的区别?代码块有哪些?构造代码块和构造方法哪一个先执行?

  • 静态变量和成员变量的区别

    • A:所属不同

      • 静态变量属于类,所以也称为类变量
      • 成员变量属于对象,所以也称为实例变量(对象变量)
    • B:内存中位置不同

      • 静态变量存储于方法区的静态区
      • 成员变量存储于堆内存
    • C:内存出现时间不同

      • 静态变量随着类的加载而加载,随着类的消失而消失
      • 成员变量随着对象的创建而存在,随着对象的消失而消失
    • D:调用不同

      • 静态变量可以通过类名调用,也可以通过对象调用
      • 成员变量只能通过对象名调用
  • 代码块有哪些

    • A:代码块概述

      • 在Java中,使用{}括起来的代码被称为代码块。
    • B:代码块分类

      • 根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块。
    • C:常见代码块的应用

      • a:局部代码块

        • 在方法中出现;限定变量生命周期,及早释放,提高内存利用率
      • b:构造代码块

        • 在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
      • c:静态代码块

        • 在类中方法外出现,加了static修饰
        • 在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次。
  • 构造代码块和构造方法哪一个先执行?

2.0.1.0 抽象类具有什么特点?抽象类和普通类有何区别?抽象类可以new吗?会出现什么问题?

  • 抽象类具有什么特点

    • 抽象类和抽象方法都使用 abstract 关键字进行声明。抽象类一般会包含抽象方法,抽象方法一定位于抽象类中。
  • 抽象类和普通类有何区别

    • 抽象类和普通类最大的区别是,抽象类不能被实例化,需要继承抽象类才能实例化其子类。
    public abstract class AbstractClassExample {
        protected int x;
        private int y;
        public abstract void func1();
    
        public void func2() {
            System.out.println("func2");
        }
    }
    
    public class AbstractExtendClassExample extends AbstractClassExample {
        @Override
        public void func1() {
            System.out.println("func1");
        }
    }
  • 抽象类可以new吗?会出现什么问题?

    • 注意抽象类是不能被实例化的,也就是不能new出来的!
    • 如果执意需要new,则会提示
    • image

其他介绍

01.关于博客汇总链接

02.关于我的博客