面向对象基础总结

1.对象和类

  1.1 对象和类的关系:对象是类的实例,类是对象的模板。

  1.2 对象:拥有属性和方法

    属性:静态特征,数据,变量

    方法:动态特征,行为,功能

    属性是数据,方法就是对数据的操作

  1.3 面向对象:
    对象:现实世界中的所有实体都是对象(万物皆对象)

     类 : 对具有共同属性和行为的对象进行抽象,得到的一个抽象的概念

    在面向对象编程时要追求低内聚,高耦合(模块越独立越好,模块间的关系越松散越好)

    面向对象编程的特点和好处:面向对象更方便代码的修改,维护,扩展;数据和功能是一个整体

2.封装

  2.1 什么是封装:
    将类的某些信息隐藏在类内部,不允许外部程序直接访问,通过调用方法来实现对隐藏信息的操作和访向。

    隐藏对象的属性和实现细节,仅对外提供公共访问方式。

    方法:封装操作

    类:数据+对数据的操作

    getter和setter方法:不能直接操作成员变量

  2.2 如何使用封装:

    使用访问修饰符  

  2.2.封装的好处:

    将变化隔离;便于使用;提高重用性;安全性。

  2.3 封装的格式:   

    1、使用访问修饰符修饰成员变量和成员方法
    2、对外提供getter和setter方法

3.继承
    3.1 什么是继承:

      继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。

   3.2 继承的优缺点:   

      优点 :

      新的实现很容易,因为大部分是继承而来的 
      
很容易修改和扩展已有的实现 

      缺点 :
      打破了封装,因为基类向子类暴露了实现细节 
      白盒重用,因为基类的内部细节通常对子类是可见的 
      当父类的实现改变时可能要相应的对子类做出改变 
      不能在运行时改变由父类继承来的实现 


      由此可见,组合比继承具有更大的灵活性和更稳定的结构,一般情况下应该优先考虑组合。只 
      有当下列条件满足时才考虑使用继承: 
      子类是一种特殊的类型,而不只是父类的一个角色 
      子类的实例不需要变成另一个类的对象 
      子类扩展,而不是覆盖或者使父类的功能失效

    3.3 继承的格式:

      子类名 extends 父类名{ }

    3.4 继承关系下代码的执行顺序 

      父类的静态代码块
      子类的静态代码块
      父类的构造代码块
      父类的无参构造方法
      子类的构造代码块
      子类的无参构造方法
      =============================
      父类的构造代码块
      父类的无参构造方法
      子类的构造代码块
      子类的有参构造方法
       总结:1、优先调用父类
          2、静态代码优先加载,且只加载一次(作用:第一个对象创建时,执行一些操作(记录日志:))
          3、构造代码块每次调用构造方法时都会调用(作用:每一个该类创建时可以记录日志)
          4、子类的构造方法不管有参无参都会先去调用父类的无参构造

 1 //测试类
 2 public class TestDemo{
 3     public static void main(String[] args) {
 4         Son son =new Son();
 5         System.out.println("=============================");
 6         Son son2 =new Son("name");
 7     }
 8 }
 9 //父类
10 class Father {
11     static {
12         System.out.println("父类的静态代码块");
13     }
14     {
15         System.out.println("父类的构造代码块");
16     }
17     public Father() {
18         System.out.println("父类的无参构造方法");
19     }
20     public  Father(String name) {
21         System.out.println("父类的有参构造方法");
22     }
23 
24 }
25 //子类
26 class Son extends  Father {
27     static {
28         System.out.println("子类的静态代码块");
29     }
30     {
31         System.out.println("子类的构造代码块");
32     }
33     public Son() {
34         System.out.println("子类的无参构造方法");
35     }
36     public Son(String name) {
37         System.out.println("子类的有参构造方法");
38     }
39     
40 }
41 //执行结果:
42 /*父类的静态代码块
43 子类的静态代码块
44 父类的构造代码块
45 父类的无参构造方法
46 子类的构造代码块
47 子类的无参构造方法
48 =============================
49 父类的构造代码块
50 父类的无参构造方法
51 子类的构造代码块
52 子类的有参构造方法
53 */

4.构造方法

  4.1 定义和作用
    在Java中,任何变量在被使用前都必须先设置初值。Java提供的为类的成员变量赋初值的专门方法。(初始化变量

  4.2  常识:子类的所有构造方法都会去访问一次父类的无参构造方法

    问题:为什么子类要去访问父类的构造方法?

    解析:因为子类继承父类,会继承到父类中的数据,所以必须要看父类是如何对自己的数据进行初始化的。所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程。

    问题:如果父类中没有无参的构造方法该怎么办?

    分析:父类中没有无参构造,那么子类在初始化的时候就会报错。

       解决办法:1、在父类中加一个无参构造方法

          2、通过使用super关键字去显示的调用父类的带参构造方法

          3、子类通过this去调用本类的其它构造方法(比如用子类的有参去调用自己的无参构造方法,但无参构造里一定要有super())

5.访问修饰符

  5.1 访问修饰符使用范围

    用来修饰成员变量和成员方法,不能用来修饰局部变量

  5.2 访问修饰符权限

            同类   同包    子类    其他包

    private            V  X  X  X

      默认      V  V  X  X

    protected     V  V  V  X

    public      V  V  V  V 

6.四个关键字   

  6.1 static(静态的)

    使用范围:用来修饰成员变量、成员方法和代码块

    作用 :

      1.想要实现对象中的共性数据的对象共享。可以将这个数据进行静态修饰。

      2.被静态修饰的成员,可以直接被类名所调用。

      3.静态随着类的加载而加载。而且优先于对象存在。

    命名方式:

      属性(成员变量):
          有static修饰:静态成员(静态变量)

         没有static修饰:实例成员(非静态变量)(非静态成员)

      方法(成员方法):          

          有static修饰:静态方法(静态方法)

         没有static修饰:实例方法(非静态方法)(非静态方法)

      代码块({ })  :

          有static修饰:静态代码块

         没有static修饰:非静态代码块(构造代码块)

     总结 :

      a.不管是静态方法还是非静态方法,都需要调用后执行,其执行的次序和在类里声明的次序无关,区别是静态方法是“class.method"方式执行,非静态方法是"object.method"方式执行,即后者需要创建一个对象。
      b.静态成员变量(也称类变量)先于非静态成员变量初始化,静态成员变量在类第一次加载时初始化,所有对象共享一份静态成员变量,非静态成员变量则在对象创建时初始化  

  

  6.2  final(最终的)

    使用范围:修饰类、修饰方法、修饰变量

    作用:1、修饰的类不可被继承

       2、修饰的方法不能被重写

       3、修饰的变量的值不能更改(即为常量,通常变量名全大写)

    作用(详细):

       1、被final修饰的类不能被继承

       2、被final修饰的成员变量

          a. 必须初始化值。

          b. 被fianl修饰的成员变量赋值,有两种方式:1、直接赋值 2、全部在构造方法中赋初值。

          c. 如果修饰的成员变量是基本类型,则表示这个变量的值不能改变。

          d. 如果修饰的成员变量是一个引用类型,则是说这个引用的地址的值不能修改,但是这个引用所指向的对象里面的内容还是可以改变的。

       3、被final修饰的方法不能被重写

          a. 一个类的private方法会隐式的被指定为final方法。

          b. 如果父类中有final修饰的方法,那么子类不能去重写。

  6.3  this和super

       两者定义的区别:

          this代表本类的引用

          super代表父类存储空间的标识(可以理解为父类的引用,可以操作父类的成员)

       两者使用的区别:

          调用成员变量:

            this.成员变量     调用本类的成员变量

            super.成员变量 调用父类的成员变量

          调用构造方法:

            this(...)  调用本类的构造方法
            super(...)    调用父类的构造方法

          调用成员方法:

            this.成员方法     调用本类的成员方法

            super.成员方法  调用父类的成员方法

7.方法的相互调用

    静态方法是“class.method"方式执行,非静态方法是"object.method"方式执行,即后者需要创建一个对象。

  7.1 同类 :

     静态调用静态

        a.直接调

        b.类名.方法名

        c.对象名.方法名(不建议使用,因为这样不能分辨是静态调静态还是静态调非静态)

     静态调用非静态

        创建调用类的对象,再对象名.方法名

     非静态调用静态

        a.直接调用

        b.类名.方法名

        c.对象名.方法名(不建议使用)

     非静态调用非静态

        a.直接调用

        b.对象名.方法名

  7.2 不同类

     静态调用静态

        类名.方法名

     静态调用非静态

        创建调用类的对象,再对象名.方法名

     非静态调用静态

        类名.方法名

     非静态调用非静态

        对象名.方法名

8.方法的重载

  同一个类中,方法名相同,参数的数量,类型,顺序不同即为重载(只与参数有关)

9.方法的重写

  发生在继承关系下,子类对父类允许访问的方法的实现过程进行重新编写, 方法签名相同(即返回值和形参都不能改变。即外壳不变,核心重写)

细节题:要答全面

10.局部变量和成员变量的区别

  内存空间:

    局部变量:栈

    成员变量:数据存储在堆中,栈中存储堆空间的地址

  初始值:

    局部变量:没有初始默认值

    成员变量:有初始默认值

  作用域:

    局部变量:声明的有效的代码块范围使用

    成员变量:类中都能使用

11.类中定义的静态成员变量和非静态成员变量的区别

  静态成员变量    :属于类,无论创建多少对象,内存中只有一个         调用方法:类.静态成员变量

  非静态成员变量:属于对象,每次创建一个对象都会分配独立的存储空间     调用方法:对象.非静态成员变量

12.列举抽象类和抽象方法的相关语法

  a.抽象方法只有定义,没有实现

  b.抽象方法所在的类必须是抽象类

  c.抽象类中可以不定义抽象方法

  d.子类继承抽象类必须实现抽象类的抽象方法       

 13.多态

   13.1什么是多态

    解释a.同一对象,调用相同的方法,执行不同的操作。

    解释b.同一引用类型,使用不同的实例执行不同的方法。

  13.2多态的优缺点

       优点:
      提高了代码的扩展性,前期定义的代码可以使用后期的内容。
     缺点:
      前期定义的内容不能使用(调用)后期子类的特有内容。

  13.3 多态的应用

    a.使用父类类型作为方法的参数
    b.使用父类类型作为方法的返回值

  13.4 多态的实现步骤   

    1、子类重写父类的方法
    2、程序运行时,子类对象赋给父类(向上转型)(Object obj = new Dog();)
    3、通过父类对象调用方法,执行的是子类的方法

  13.5 多态的表现形式

      向上转型:子类转向父类

      向下转型:父类转向子类

          绑定方法:
          1.如果是非抽象类,则通过父类名 引用名 = new 子类名();然后使用instanceOf关键字来检查左边的对象是否为右边的实例;

            如果是抽象类,则通过抽象类名 引用名 = new 实现类名();

          2.使用instance0关键字来检查左边的对象是否为右边的实例;

               Father f = new Son();

                if(f instanceof Son) {

                  ((Son) f).run();//确认左边的对象是右边的实例后则可以调用方法

                }

    向下转型会遇到的异常:

在继承关系下著名的异常:java.lang.ClassCastException(类型转换异常)

父类Animal有两个子类Cat和Dog

向下转型

Animal a = new Cat;

强制转换  Cat c2  =(Cat)a;

可以调用猫的方法c2.catchMouse();

但是
Animal b = new Dog;

强制转换  Cat c3  =(Cat)b;   此时编译是可以通过的  但是运行就会报错,因为狗和猫没有继

承关系

  举例:a.使用父类类型作为方法的参数

 1 //父类Pet
 2 public class Pet {
 3     public void eat() {
 4         System.out.println("动物吃东西");
 5     }
 6 
 7 }
 8 //子类Dog
 9 public class Dog extends Pet {
10     public void eat() {
11         System.out.println("狗吃肉");
12     }
13 
14 }
15 //子类Cat 
16 public class Cat extends Pet {
17     public void eat() {
18         System.out.println("猫吃鱼");
19     }
20 
21 }
22 //主人
23 public class Master {
24     public void feed(Pet pet) {//直接让父类做形参,将子类对象的地址值赋值给父类
25 //变量,这样调用的就是子类的方法,因为编译器只认地址,地址是子类的就调用子类
26 //的方法
27         pet.eat();
28     }
29 
30 }
31 //测试类
32 
33 public class TestDemo {
34     public static void main(String[] args) {
35         Master ma = new Master();
36         ma.feed(new Dog());
37         ma.feed(new Cat());
38 
39     }
40 }
41 //执行结果
42 狗吃肉
43 猫吃鱼

   举例:b.使用父类类型作为方法的返回值 

//简单工厂模式 :
    缺点:破坏了开闭原则,但是以后的学习可以通过反射+配置文件重构代码
/* 结构的组成: 一个抽象产品(父类) 若干个实体产品(子类) 简单工厂:一个静态方法,返回值是父类对象 测试类:调用时,只需要知道父类和工厂,无需关注具体的子类 */ /* 简单工厂: 产品 抽象产品Car 实体产品Benz BMW 工厂 生产产品 缺点:破坏开闭原则,以后可以通过反射+配置文件重构代码 23个经典的设计模式中没有简单工厂 */ //抽象产品Car public class Car { public void run() { } } //实体产品 public class BMW extends Car { public void run() { System.out.println("BMW run"); } } public class Benz extends Car { public void run() { System.out.println("Benz run"); } } //工厂 public class Factory { public static Car createCar(String type) { Car car = null; switch (type) { case "BMW": car = new BMW(); break; case "Benz": car = new Benz(); break; default: break; } return car; } } //测试类 public class TestDemo { public static void main(String[] args) { System.out.println("先生你要买什么"); Scanner sc = new Scanner(System.in); Factory.createCar(sc.next()).run(); } }

 23中设计模式中最简单的单例模式:

       无论引用多少次对象,内存中只分配一个

 1 public class MySingle {
 2     // 无论引用多少次对象,内存中只分配一个对象
 3     static MySingle mySingle;
 4 
 5     private MySingle() {//私有化构造方法
 6 
 7     }
 8 
 9     public static MySingle getSingle() {//要是静态的不然不能调用方法
10         if (mySingle == null) {
11             mySingle = new MySingle();
12         }
13         return mySingle;    //返回实例对象
14     }
15 }
16 
17 
18 public class MySingleTest {
19 
20     public static void main(String[] args) {
21 
22         System.out.println(MySingle.getSingle());
23     }
24 
25 }