java面向对象(oop)基础知识既面试题详解

1.初识面向对象

  • 面向过程思想
    • 步骤清晰简单,第一步做什么,第二步做什么…
    • 面向过程适合处理一些较为简单的问题
  • 面向对象思维
    • 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
    • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题。
  • 对于描述复杂的事物,为了从宏观上把握,从整体上分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。
  • 面向对象编程(oop)
  • 面向对象编程的本质就是:以类的方式组织代码,以对象的方式组织(封装)数据。
  • 抽象
  • 三大特征
    • 封装
    • 继承
    • 多态
  • 从认识的角度考虑是先有对象后有类。对象,是具体的事物。类是抽象的,是对对象的抽象
  • 从代码运行角度考虑是先有类后有对象。类是对象的模板

2. 方法回顾和加深

  • 方法的定义:

    • 修饰符
    • 返回类型
    • break:跳出switch,结束循环 continue。结束方法 返回一个值return
    • 方法名:注意规范就ok 见名知意
    • 参数列表:(参数类型,参数名)…
    • 异常抛出:疑问,后面讲解
  • 方法的调用

    • 静态方法 static修饰

    • 非静态方法

      静态方法不可以直接调用同一个类中的非静态方法:因为静态方法是和类一块存在的,也就是有类的时候就有了静态方法。但是非静态方法是跟随类实例化的(对象)也就是有了new的类对象之后,才有非静态方法。

      当一个已经存在的调用一个不存在的,所以就会报错。

      同时:一个类中非静态可以直接调用非静态。静态可以直接调用静态。

    • 形参和实参(类型要一致)

    • 值传递和引用传递

      /**
       * @Auther: 王海新
       * @Date: 2021/1/31 15:29
       * @Description: 值传递
       */
      public class demo1 {
          public static void main(String[] args) {
              int a = 1;
              System.out.println(a);
              test(1);
              System.out.println(a);
          }
      
          private static void test(int i) {
              i = 10;
          }
      }
      

    两个输出结果都为1。.因为是值传递,它只是把数值传递过去。原来的a并没与变。

    引用传递:

    package com.wang.opp.demo1;
    
    /**
     * @Auther: 王海新
     * @Date: 2021/1/31 15:59
     * @Description: 引用传递 对象 : 本质还是值传递。我们之前说过,java只有值传递。
     */
    public class demo2 {
        public static void main(String[] args) {
            Perosn perosn = new Perosn();
            System.out.println(perosn.name);
            test(perosn);
            System.out.println(perosn.name);
        }
    
    
        private static void test(Perosn i) {
            //i是一个对象。指向了上面的Perosn perosn = new Perosn();就像是一个具体的人,
            // 可以改变它的属性,所以再次输出时,这个对象的name就改变了
            i.name = "海新";
        }
    }
    /** 
    * @Description: 定义一个类。在一个文件中可以有多个类,但只能有一个public修饰的类。
    * @Param:  
    * @return:  
    * @Author: 王海新
    * @Date:  
    */
    class Perosn{
        String name;
    }
    

    上述代码传递对象时,就可以改变了其中的name。可能大家还要些疑惑。之后我们会从对象 和内存两个方法再做详细解释。

    • this关键字(先打个照面,之后方法继承和多态时讲解。)

类和对象的关系

  • 类是一种抽象的数据类型,它是对某一类事物整体描述/定义。但并不能够代表某一个具体的事物
    • 动物,植物,手机,电脑…(类就是这样,表示一类,但不能代表某一个具体的动物,植物。。。)
    • Person类,Pet类,Car类等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为
  • 对象是抽象概念的具体实例
    • 张三就是人的具体实例,张三家的旺财就是狗的一个具体实例。
    • 能够体现出特点,展示出功能的是具体的实例,而不是一个抽象的概念

我们可以将这些思想转化为代码实现。

3. 对象的创建分析

创建与初始化对象

  • 使用new关键字创建对象
  • 使用new关键字创建的时候,除了分配内存空间之外,还会给 创建好的对象进行默认的初始化以及对类中构造器的调用。
  • 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有一下两个特点:
    • 必须和类的名字相同
    • 必须没有返回类型,也不能写void
  • 构造器必须要掌握
  • 类实例化后会返回一个自己的对象!这时才会给这个对象分配空间,初始化以及对类中构造器的调用。
  • 以类的方式组织代码,以对象的组织(封装)数据。

构造器详解

  • 一个类即使什么都不写,它也会有一个方法。就是构造器。
  • 与类名相同,没有返回值 public修饰。
  • 一个类可以有多个构造器。但是各个构造器的参数个数,或者类型必须不同。
  • 默认有一个空参构造器。如果创建了有参构造器。空参构造器就不会默认创建。如果需要调用无参,需要手动声明一个空参构造器。
  • 使用new关键字创建对象,本质是在调用构造器。
  • 当创建的时候,传递了什么参数,就会调用相同类型的构造器。
  • 构造器用来初始化值
  • idea快捷键:alt + insert =》constructor 面里面可以选生成有参或无参的构造器

创建对象 内存分析

package com.wang.opp;

/**
 * @Auther: 王海新
 * @Date: 2021/2/1 12:14
 * @Description: 内存分析
 */
public class demo2 {
    public static void main(String[] args) {
        Pet dog= new Pet();
        dog.name = "旺财";
        dog.age = 1;

        Pet cat= new Pet();
        cat.name = "加菲猫";
        cat.age = 1;
    }
}

/** 
* @Description: 动物类
* @Param:  
* @return:  
* @Author: 王海新
* @Date:  
*/
class Pet{
    String name;
    int age;

    public  void  shot(){
        System.out.println("叫了一声");
    }
}

如以上代码在内存中的分析:

  • 栈:

    • 3,main方法入栈执行
    • 5,dog:引用变量名,引用下一步子啊堆中分配的内存空间
  • 堆:

    • 6,new Pet() 执行,在堆中分配空间,并初始化值 name:null。age:0

    • 7,

      dog.name = "旺财";
      dog.age = 1;
      

      执行。赋值(之前说过,类来操作代码。对象操作数据)

    • 8,赋值:name:旺财 age : 1

    • 9,(之后可能会回收掉堆中的内存,也有可能不回收)具体收回时机有很多算法控制,后面讲到垃圾回收时会详解。 希望就关注一波吧。蟹蟹!

      ​ 然后重复4-8步骤创建cat对象的过程。

  • 方法区(在堆中):

    • 1,程序运行,首先在方法区中加载启动类demo2。同时加载常量及静态方法"旺财" 1 “加菲猫” 1
    • 4,Pet dog= new Pet();被执行。在方法区中加载Pet类。并加载其中的常量以及方法。name age shot()
  • 静态方法区(在方法区中):

    • 2,将main方法加载

小结:

  1. 类与对象

    类是一个模板:抽象。对象是一个具体的实例

  2. 方法:

    定义,调用!

  3. 对象的引用

    引用类型

    基本类型(8种)

    对象是通过引用来操作的:栈–》堆

  4. 属性:字段(Field) 成员变量

    默认初始化

    数字:0 0.0

    char:u0000

    boolean:false

    引用:null

    修饰符 属性类型 属性名 = 属性值;

  5. 对象的创建和使用

    • 必须使用new 关键字创建对象,构造器 Person haixin = new Person();
    • 对象的属性: haixin.name
    • 对象的方法: haixin.sleep();
  6. 类:

    静态的属性: 属性

    动态的行为: 方法

    封装 继承 多态

4. 面向对象三大特性

封装

  • 该露的露,该藏的藏

    • 我们的程序设计要追求:“高内聚,低耦合”、高内聚就是类的内部数据操作细节自己完成。不允许外部干涉。低耦合:仅少量的方法给外部使用。
    • 封装(数据的隐藏)
      • 通常。应禁止直接方法一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
    • 记住这句话就够了:属性私有,get/set
  • 就是在属性上添加private关键字

    private String name

  • 用private(私有)修饰的关键字与public(共有)相对应,在其它类中无法直接通过方法名.name的方式调用。而需要使用规定的方法。

  • get /set就是规定的获取private修饰的属性的方法

class Pet{
    private String name;
    private int 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;
    }

    public  void  shot(){
        System.out.println("叫了一声");
    }
}

如上 调用相应的方法set给属性赋值。用get获取值

/**
 * @Auther: 王海新
 * @Date: 2021/2/1 12:14
 * @Description: 内存分析
 */
public class demo2 {
    public static void main(String[] args) {
        Pet dog= new Pet();
        dog.setName("旺财");
        dog.setAge(1);

        Pet cat= new Pet();
        dog.setName("加菲猫");
        dog.setAge(1);
     
    }
}
  • 为什么要使用封装

    因为在设置数据的时候,有些数据是不合法的。我们可以通过封装时,在方法中设置一些检测。来使得我们的数据更安全。

    1. 提高程序的安全性,保护数据
    2. 隐藏代码实现细节
    3. 统一接口
    4. 系统可维护性增加了
  • 封装的set/get方法也可以重载。其实判断两个方法是否相同就参考两个点:方法名和参数列表

继承

  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
  • extend的意思是“扩展”。子类是父类的扩展。
  • JAVA中只有单继承,没有多继承!一个儿子只能有一个爸爸。一个爸爸可以有多个儿子
  • 继承是类和类之间的关系。除此之外类和类之间的关系还有依赖,组合,聚合等。
  • 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类用extends来表示
  • 子类和父类之间,从意义上讲应该具有is a 的关系。
  • 私有的东西无法被继承

快捷键:Ctrl + h 可以查看当前类的继承关系

  • object类

    object类是所有类的父类。我们平时定义的类都默认继承了object类。所以我们刚刚定义的类不写任何东西。在使用其对象的时候,也会有很多方法 属性 可以直接使用。

  • super

    当子类重载了父类的方法或者变量的时候。用super来表示调用的是父类的。默认是调用子类的。也可以用this.来表示当前类的东西。

    super.name 就表示调用的是父类的name

    • 如果父类私有的(private修饰)。则也无法调用。
    • 同时,super() 表示调用父类的构造器。super(int 1) 就表示调用父类的有参构造器。
    • super()在子类的构造器第一行,如果调用this(有参或无参)也需要在第一行。
    • 默认调用了父类的无参构造器。并且super必须在第一行。如果父类没有无参构造器就会报错(所以前面我们要求,在写了有参构造器之后,手动写一个无参构造器。避免之后出错)
    • 通过在构造器中打印语句。我们知道先执行了父类 再执行子类
  • super注意点:

    1. super调用父类的构造方法,必须在调用方法的第一个
    2. super必须只能出现在方法或者构造方法中
    3. super和this不能同时调用构造方法!
  • VS this

    • 代表的对象不同

      this:本身调用者这个对象

      super: 代表父类对象的应用

    • 前提

      this:没有继承也可以使用

      super:只能在继承条件才可以使用

    • 构造方法

      this()本身的构造器

      super() 父类的构造器

  • 重写

    ​ A(extend)继承B

    • 静态方法和非静态方法区别很大

      假如入A和b都定义了public static void test(){

      }方法

      A a = new A();

      a.test();//结果打印A 中的test

      B b = new A();

      b.test();//执行的是B中的test

      假如入A和b都定义了public void test(){

      }方法

      A a = new A();

      a.test();//结果打印A 中的test

      B b = new A();//父类的引用指向了子类

      b.test();//结果打印A 中的test

      总结:只有在非静态方法中才能实现真正的重写,静态方法是重写不了的。

      非静态的不是私有的方法 才可以重写

      idea有提示,只有在打断点的位置出现一个O加一个向上的箭头,才表示重写成功了

    • 快捷键:alt+insert 中的override method。可以自动在子类中生成父类的重写方 法

    • 重写和重载:

      重写是指重写父类中的

      重载是指本 类中方法名相同,参数列表不同

    • 重新:需要有继承关系,子类重写父类的方法

      1. 方法名必须相同

      2. 参数列表必须相同

      3. 修饰符:范围可以扩大但不能缩小:(修饰符这部分我们还没有全部讲到,大家可以这样记忆。子类的修饰符权限必须大于等于父类)

        public>Protected>Default>private

      4. 抛出异常:范围:可以被缩小但不能扩大:(子类的异常范围只能等于小于父类)

        ClassNotFoundExeception == >Exception(大)

      重写,子类的方法和父类的方法必须要一致:方法体不同!

    • 为什么要重写:

      ​ 父类的功能,子类不一定都需要,或者不一定都满足

      Alt + insert =》override

多态

动态编译:类型:可扩展性

  • 多态注意事项:
    1. 多态是方法的多态,属性没有多态
    2. 父类和子类,有联系 类型转换异常!ClasCastException!
    3. 存在条件:继承关系,方法需要重写,父类引用指向子类对象!
    4. Father f1 = new son();
    5. 不可以继承的方法和常量(无法继承,自然没办法实现多态)
      1. static 方法:属于类,它不属于实例
      2. final 常量
      3. private方法
  • 多态
    • 既同一方法可以根据发送对象的不同而采用多种不同的行为方式
    • 一个对象的实际类型是确定的,但可以指向对象的引用类型的类型有很多种(父类,有关系的类)
    • 多态存在的条件
      • 有继承关系
      • 子类重写父类方法
      • 父类引用指向子类对象
    • 注意:多态是方法的多态,属性没有多态性
    • instanceof (类型转换)引用类型
package com.wang.opp.demo3;

/**
 * @Auther: 王海新
 * @Date: 2021/2/2 16:27
 * @Description:
 */
public class Persion {
public  void run(){
    System.out.println("Persion");
}
}
package com.wang.opp.demo3;

/**
 * @Auther: 王海新
 * @Date: 2021/2/2 16:27
 * @Description:
 */
public class Student extends Persion {
    @Override
    public void run() {
        System.out.println("Student");
    }

    public void eat() {
        System.out.println("吃");
    }
}
package com.wang.opp.demo3;

/**
 * @Auther: 王海新
 * @Date: 2021/2/2 16:26
 * @Description: 启动类
 */
public class Application {
    public static void main(String[] args) {
        //一个对象的实际类型是确定的
        //new Student
        //new Student


        Student student = new Student();
        //可以指向的引用类型就不确定了:父类的引用指向子类
        Persion persion = new Student();
        Object object = new Student();

        //对象能执行那边的方法主要看对象左边的类型:和右边关系不大
        student.run();
        //父类型可以调用子类型,但是不能调用子类独有的方法。
        persion.run();//结果都是执行子类重写后的方法。



    }
}
  • 类型转换,我们可以通过类型转换instanceof,来判断两个类是否可以进行强制转换

    ​ A extends B

    ​ C extends B

    Object object = new A();

    sout(object instanceof A);//true

    sout(object instanceof Object );//true

    sout(object instanceof B);//true

    sout(object instanceof C);//flase

    object的引用指向的是A,和C并没有直接关系。所以打印结果为false。但是不报错(因为C的父类的父类也是Object

    sout(A Iinstanceof B);

    //直接报类型转换错误。因为A和B并没有一点关系

    我们可以通过instanceof是否编译通过,判断两者是否有父子关系

  • 类型转换:

    • 子类可以直接转换为父类。父类转换为子类。需要强转
    • 子类转换为父类(强转),会丢失自己独有的一些方法!父类转化为子类,会丢失被子类重写的方法(执行子类中的重写方法)。
    • 方便方法的调用,将一些类转换就可以调用不同的方法。减少重复的代码!简洁

    抽象:继承 封装 多态 面向对象的三大基本特征都是为了抽象

    抽象也是编程思想

static关键字详解:

package com.wang.opp.demo4;

/**
 * @Auther: 王海新
 * @Date: 2021/2/3 17:16
 * @Description: 静态代码块
 */
public class Persion {

    public Persion() {//3.第三次执行,每次调用都执行
        System.out.println("构造函数");
    }

    {//2,第二执行,每次调用都执行。一般用来赋初始值
        System.out.println("匿名代码块");
    }

    static {//1.最先执行,且仅执行一次
        System.out.println("静态代码块");
    }

    public static void main(String[] args) {
        Persion persion = new Persion();
        System.out.println("= ============");
        Persion persion1 = new Persion();
    }
}
  • 静态导入包

    package com.wang.opp.demo4;
    //静态导入包
    import static java.lang.Math.random;
    /**
     * @Auther: 王海新
     * @Date: 2021/2/3 17:26
     * @Description: 静态导入包
     */
    public class Student {
        public static void main(String[] args) {
            //输出一个随机数
            System.out.println(Math.random());
            //静态导入包之后 就可以直接用
            System.out.println(random());
        }
    }
    

同时,用final修饰的类,不可以再被继承。

抽象类

package com.wang.opp.demo5;

/**
 * @Auther: 王海新
 * @Date: 2021/2/3 17:41
 * @Description: 抽象类,因为单继承的原因,抽象类用的并没有下面要讲的接口用的多
 */

public abstract class Action {

    public abstract void run();
    public void say(){
        System.out.println("hah");
    }
    /*
    抽象类就是一个约束。只定义方法名字。不定义具体实现。
    
     */

}
package com.wang.opp.demo5;

/**
 * @Auther: 王海新
 * @Date: 2021/2/3 17:41
 * @Description:
 */
//继承抽象类就必须要重写抽象类中的抽象方法。除非子类也是一个抽象类
public class a extends Action{
    @Override
    public void run() {

    }
}
  1. 不能new这个抽象类,只能靠子类去实现它:就是一个约束
  2. 抽象类中可以编写普通的方法
  3. 抽象方法必须再抽象类中
  • 思考题 :
    • 抽象类有构造器吗? 有!因为抽象类也属于类。我们可以通过手写一个查看,或者通过将生成的class文件放idea中反编译。看看是否有构造器
    • 抽象类存在的意义 抽象出来,提高开发效率,增强相互协作。

接口

  • 普通类:只有具体实现
  • 抽象类:具体实现和规范(抽象方法)都有!
  • 接口:只有规范!自己无法写方法。约束和实现分离:面向接口编程
  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。
  • **接口的本质是契约,**就像我们人间的法律一样。制定好后大家都要准守。
  • OO的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计 模式都只针对具体了抽象能力的语言(比如c# c++ java等),就是因为设计模式所研究的,实际上就是如果合理的去抽象。
  • 声明类的关键字是class,声明接口的关键字是interface
  • 接口中的抽象方法默认都是 public abstract类型的,所以可以省略不用声明。直接写一个 void run(); void say(); 即可
  • 接口中的属性默认都是静态常量 public static final修饰。(一般都不在接口中定义常量)
  • 接口不能被实例化,接口中没有构造方法
  • implements可以是实现多个接口
  • 必须要重写接口中的方法

6. 内部类

内部类就是在类的内部再定义一个类,比如A类中定义B类,那么B类相对于A类来说就是内部类,而A相对于B来说就是外部类了

  • 内部类通过外部类的对象.new

  • 内部类可以直接方法外部类的私有变量。但是静态内部类无法访问非静态的外部类私有变量。(因为静态内部类先在内存中加载)

  • 一个java类中可以有多个class类,但是只能有一个public class类

  • 接口,在另一个类中new接口然后实现里面的方法,

    new User(){

    //实现User接口中的方法

    }

    这个类也是匿名内部类

  1. 成员内部类 定义在类中的类
  2. 静态内部类 定义
  3. 局部内部类 定义在方法中的类
  4. 匿名内部类 在调用的时候,也就是new的时候。不用将实例保存到变量中。而是直接使用。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑白极客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值