黑白客 发表于 2021-2-4 15:58

面向对象基础知识及面试题详解

面向对象(oop)
1.初识面向对象
2. 方法回顾和加深
类和对象的关系
3. 对象的创建分析
创建与初始化对象
构造器详解
创建对象 内存分析
小结:
4. 面向对象三大特性
封装
继承
多态
抽象类
接口
6. 内部类

## 1.初识面向对象

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

## 2. 方法回顾和加深

- 方法的定义:

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

- 方法的调用

- 静态方法 static修饰

- 非静态方法

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

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

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

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

- 值传递和引用传递

    ```java
    /**
   * @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并没与变。

引用传递:

​       

```java
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 面里面可以选生成有参或无参的构造器

### 创建对象 内存分析

```java
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;

    publicvoidshot(){
      System.out.println("叫了一声");
    }
}
```



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

- 栈:

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

- 堆:

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

- 7,

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

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

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

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

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

- 方法区(在堆中):

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

- 静态方法区(在方法区中):

- 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修饰的属性的方法

```java
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;
    }

    publicvoidshot(){
      System.out.println("叫了一声");
    }
}
```

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

```java
/**
* @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 (类型转换)引用类型

```java
package com.wang.opp.demo3;

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

```java
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("吃");
    }
}
```

```java
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 = newA();

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关键字详解:**

```java
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();
    }
}
```

- 静态导入包

```java
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修饰的类,不可以再被继承。

### 抽象类

```java
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");
    }
    /*
    抽象类就是一个约束。只定义方法名字。不定义具体实现。
   
   */

}
```

```java
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的时候。不用将实例保存到变量中。而是直接使用。

sunnyAlvis 发表于 2021-3-17 09:48

学习学习,一直在学习,但是我从来没有坚持下来。。。

沉心云 发表于 2021-2-4 16:52

前来学习了,最近在学Java

dreamrise 发表于 2021-3-17 09:41

整理的不错,复习了一遍。
页: [1]
查看完整版本: 面向对象基础知识及面试题详解