05--面向对象的三大特征

面向对象总结

1. 什么是面向对象

   1.1 面向对象(Object Oriented)是一种思想,90年代以后软件开发的主流思想.由于现实社会是由各种各样的事物所组成的,

       而我们编程又是在模拟现实社会,那么在程序也要用一些东西来表示现实社会中的事物,这些东西就是程序中的对象。

       我们在程序中使用这些对象,对其特征和行为进行操作进行编程,这就是面向对象编程。在使用面向对象编程思想之前,

       我们通常用面向过程的思想编程,先分析出解决问题的步骤,然后按照步骤一步一步实现。

   1.2 面向对象编程的优点

      1.2.1 提高代码复用性。

      1.2.2 使用者无需关心具体细节。  

      1.2.3 转变程序员角色,更加符合人的思维习惯。  


2. 类与对象

   2.1 什么是类: 类是用来描述对象的。由于对象是虚拟出来的东西,是看不见摸不着的,我们需要在程序中使用对象,

                 就需要用一种方式来描述对象,然后根据这个描述来创建对象。

   2.2 类和对象的关系: 对象是类的实例,类是对象的描述。

   2.3 怎么定义类: 将一系列特征相似的对象的共同特征及行为抽取出来进行描述,写在一个class中,

                    用成员变量描述对象的特征,用成员方法来描述对象的行为。


class Person { String name; int age; void speak(){System.out.println("My name is " + name);System.out.println("I am " + age + " years of age");  }}

2.4 怎么使用类创建对象:使用new关键字和指定类名来创建一个对象。

    //对象的产生

    Person p = new Person();

    这句话先在堆内存中创建了一个对象,然后栈内存中创建一个变量引用了对象的地址。

   2.5 成员变量初始化

    当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。

    基本数据类型初始化值为0,引用数据类型初始化值为null。

05--面向对象的三大特征_第1张图片

   2.6 对象的使用:当我们创建对象之后可以使用点语法来访问对象的属性和方法。例如:
    Person p = new Person();
    p.name = "张三";        // 访问属性(成员变量)
    p.age = 20;
    p.speak();            // 访问方法
   2.7 对象的生命周期:对象的生命周期从new关键字创建时开始,到没有任何引用到达对象时结束(成为垃圾)。
   2.8 匿名对象
      2.8.1 我们可以不定义变量引用对象,使用new关键字创建对象后直接使用,这样的对象没有名字,所以叫匿名对象。
      2.8.2 通常我们需要使用一个对象且只使用一次的时候,就可以使用匿名对象。比如将对象作为一个参数传递给另外一个函数。
      2.8.3 匿名对象因为没有任何引用到达,在使用一次之后即成为垃圾。
        

3. 封装(Encapsulation)

   3.1 什么是封装?
    将一类事物的特征和行为定义在一起,可以通过这个定义创建对象,使用对象进行编程
    封装时需要将对象的属性和一些实现细节隐藏,仅对外提供必须的访问方式。
   3.2 怎么封装?
    将所有属性隐藏,提供公有方法对其访问。
    将不需要对外提供的方法隐藏。
   3.3 封装的优点
      3.3.1 提高安全性:在访问对象的属性时候通过方法实现,在方法中可以进行校验。隐藏不必要提供的方法避免错误的调用。
      3.3.2 简化编程:使用者无需关心对象内部具体实现细节,只要根据对象功能调用指定方法。

4. 构造函数(Constructor)

   4.1什么是构造函数?
      4.1.1 构造函数是一个特殊的函数。
      4.1.2 函数名和类名相同。
      4.1.3 没有返回值类型。注意:没有返回值类型不等同于void。
      4.1.4 在使用new关键字创建对象之后自动调用。
   4.2 构造函数的重载
    构造函数的重载和普通函数相同,函数名相同,参数列表不同即可。
   4.3 构造函数的调用
      4.3.1 构造函数在new关键字创建对象时调用。
      4.3.2 构造函数可以在该类其他构造函数的第一个语句使用this关键字调用。
   4.4 所有类都有构造函数
    每一个类都有构造函数,即使我们没有显式定义构造函数,也会生成一个默认无参的构造函数,其中没有任何内容。
    生成的构造函数只在未定义任何构造函数时生成,如果我们定义了一个有参的构造函数,那么就不会生成无参的了。
   4.5 构造函数的访问权限
      4.5.1 在定义构造函数时,如无特殊需要,应使用public关键字修饰构造函数。
      4.5.2 在一些特定情况下,我们不想让别人创建该类对象,那么可以使用private修饰构造函数,例如单态设计模式。
   4.6 this关键字
      4.6.1 this关键字除了在构造函数中调用其他构造函数以外,还可以当做一个引用使用。其用于方法中,
            哪个对象调用该方法,this就引用哪个对象。
      4.6.2 方法中局部变量和成员变量重名,我们想调用成员变量时就可以使用this.变量名形式访问成员变量。
      4.6.3 在方法中要将调用该方法的对象作为参数传递给另一个方法时,可以将this作为实参传给该方法。
      4.6.4 在内部类中访问外部类的成员时,需要使用外部类名.this.成员名形式访问。
   4.7 函数的参数传递
      4.7.1 基本数据类型的变量作为实参传入函数之后,在函数中将形参改变,调用处的实参不变。
            因为基本数据类型的值是直接存在变量中,传入函数之后函数中的形参也同样存了一个值,
        这两个值是没有联系的,所以函数中将形参改变时修改的只是函数中的变量的值,和调用处的实参无关。
      4.7.2 引用数据类型的变量作为实参传入函数之后,在函数中将形参改变,调用处的实参改变。
            因为引用数据类型变量中存储的是地址,传入函数之后函数中的形参存储的也是同样一个地址,
        函数中将这个形参改变时改变的都是同一个地址上的对象,所以一边改变两边都变。

5. static关键字

   5.1 static关键字用来修饰类的成员,被这个关键字修饰的成员都和类加载有关。
   5.2 JVM运行时不会将所有类加载到内存,因为无法确定程序中要使用哪些。类在第一次使用时加载,只加载一次。
   5.3 静态变量
      5.3.1 用static修饰的变量就是静态变量。
      5.3.2 静态变量在类加载后就初始化。
      5.3.3 静态变量被类的所有实例所共享。
      5.3.4 静态变量可以使用 类名.变量名 形式访问。
      5.3.5 如果在定义一个类的时候,发现一个成员变量需要被所有实例所共享,那么这个成员变量就需要定义为static的。
   5.4 静态方法
      5.4.1 用static修饰的方法就是静态方法。
      5.4.2 静态方法在类加载后就可以使用。
      5.4.3 静态方法可以使用 类名.方法名 形式访问。
      5.4.4 静态方法不能直接访问外部非静态成员。
        因为外部非静态成员必须在类创建对象之后才能使用,而静态方法可以在没创建对象时就使用。
        如果要在静态方法内部访问外部非静态成员,需要先创建该类对象,通过对象访问。
      5.4.5 静态方法中不能使用this关键字。
        因为this是个引用,哪个对象调用方法就引用哪个对象。而静态方法有可能不是被对象调用的,this无从引用。
      5.4.6 如果一个方法不用访问非静态成员,那么就可以定义为静态的,这样使用者就不需要创建对象,直接用类名调用。
        静态方法通常是作为工具方法或者一个可以产生对象的方法被声明,目的是为了让调用者更方便的使用,
        不必创建对象。
   5.5 静态代码块:用static修饰的代码块就是静态代码块。
      5.5.1 静态代码块在类加载后执行。
      5.5.2 静态代码块和静态方法相同,不能使用外部非静态成员。
      5.5.3 静态代码块执行和静态变量的初始化顺序由代码从上到下顺序决定。
      5.5.4 如果我们有一段代码想在别人使用某个类的时候就运行, 而且只运行一次, 那么就可以写在静态代码块中.
   5.6 静态内部类
      5.6.1 用static修饰的内部类就是静态内部类。
      5.6.2 静态内部类在类加载后就可以创建对象,无需创建外部类对象。


6. 垃圾回收

   6.1 对象在没有任何引用可以到达时,生命周期结束,成为垃圾。
   6.2 所有对象在被回收之前都会自动调用finalize()方法。
   6.3 一个对象在成为垃圾之后不会被马上回收,JVM会检测内存中的垃圾堆积到一定程度时才会回收,
       如果我们不想等到这个时候才回收,可以使用System.gc()方法来通知虚拟机回收垃圾。
       调用该方法之后JVM会开启新线程做处理垃圾的工作,这需要一定时间。


7. 单态设计模式(SingletonPattern)  

   7.1 什么是设计模式
    在编程过程中我们经常会遇到一些典型的问题或需要完成某种特定需求,而这些问题和需求前人也曾经遇到过,
    他们经过大量理论总结和实践验证之后优选出的代码结构、编程风格、以及解决问题的思考方式,这就是设计模式(Design pattern)。
    设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免得我们自己再去思考和摸索。
   7.2 单态(单例)设计模式
    单态设计模式(Singleton pattern)就是要保证在整个程序中某个类只能存在一个对象,这个类不能再创建第二个对象。
   7.3 单态设计模式的写法
      7.3.1 私有化构造函数,阻止创建新对象。
      7.3.2 由于需要返回一个对象,那么我们就需要在类内部自己创建一个对象,并使用成员变量记住它。
    由于该类不能创建对象,所以这个成员变量不能是普通的成员变量,需要静态,这样在类加载之后就可以创建一个唯一的对象了。
    我们不希望其他类修改这个成员变量,所以将其私有。
      7.3.3 提供一个公有的方法用来获取唯一的一个对象。这个方法由于需要在不创建对象的情况下使用,所以需要静态。

        /*
	 * 饿汉式:
	 * 1,将构造函数私有
	 * 2,创建本类的对象,用private static final修饰
	 * 3,提供公共的方法用来返回这个对象,用static修饰
	 * ----------------------------------------------
	 * 懒汉式:
	 * 1,将构造函数私有
	 * 2,声明本类的对象,用private static修饰
	 * 3,在方法内部做判断对象的引用是否为空,为空则创建对象
	 */
	class Persion {
		private Persion() {
		} // 将构造函数私有,禁止其它类创建对象
		 /*
		 // 饿汉式
		 private static final Persion p = new Persion();
		 public static Persion getPersion() {
		 return p;
		 }
		 */
		// 懒汉式
		private static Persion p = null;
		public static synchronized Persion getPersion() {
			if (p == null)
				synchronized (Persion.class) {
					if (p == null) {
						p = new Persion();
					}
				}
			return p;
		}
	}


8. 继承(Inherit)

   8.1 什么是继承
      8.1.1 在程序中,可以使用extends关键字让一个类继承另外一个类。
      8.1.2 继承的类为子类(派生类),被继承的类为父类(超类, 基类)。
      8.1.3 子类会自动继承父类所有的方法和属性。
   8.2 为什么要使用继承
      8.2.1 当我们发现一个类的功能不行,方法不够用时,就可以派生子类,增加方法。
      8.2.2 当我们需要定义一个能实现某项特殊功能的类时,就可以使用继承。
      8.2.3 最终还是为了一个目的,提高代码的复用性。
      8.2.4 当我们定义一个类时,发现另一个类的功能这个类都需要,而这个类又要增加一些新功能时,
            就可以使用extends关键字继承那个类,这样那个被继承类的功能就都有了,不必重写编写代
        码。这时只要在新的类中编写新的功能即可,原有代码就被复用了。
   8.3 继承的特点
      8.3.1 Java只支持单继承,不支持多继承,但是可以多重继承
        因为如果一个类继承多个类,多个类中有相同的方法,子类调用该方法时就不知道该调用哪一个类中的方法了。
      8.3.2 向上转型
         8.3.2.1 子类对象可以当作父类对象使用,因为父类有的功能子类都有
     8.3.2.2 父类对象不能当作子类对象,因为子类有的父类不一定有
     8.3.2.3 可以定义一个父类类型的变量来记住子类对象,这在程序中称之为向上转型
      8.3.3 强制类型转换
         8.3.3.1 把一个子类当做父类来用的时候,不能调用子类特有方法。
        因为编译时编译器会做语法检查,看到变量是父类类型那么就会到父类中查找是否有该方法,没有则报错。
        这种情况下,就需要强制类型转换,将父类类型强转成子类类型。
     8.3.3.2 以(子类名)变量名形式进行强制类型转换
        强制类型转换时,无论类型是否匹配编译都不会报错,但如果类型不匹配运行会报错,
        我们可以使用instanceof进行判断,编译时预知错误。
         8.3.3.3 在子类当做父类来用时,不能调用特有方法,如果一定要调用,就需要强制类型转换回子类。
             在做转换时最好instanceof判断一下类型是否匹配。
   8.4 子类覆盖(Override)父类方法
      8.4.1 覆盖方法必须和被覆盖方法具有相同的方法名称、参数列表和返回值类型。
      8.4.2 子类的方法返回值类型可以是父类方法返回值类型的子类。
      8.4.3 如果在子类中想调用父类中的那个被覆盖的方法,我们可以用“super.方法名”的格式。
      8.4.4 如果直接调用方法,是在当前子类中先查找,如果子类有会调用子类的。使用super形式只在父类中查找,子类有没有都不调用。
      8.4.5 覆盖方法时,不能使用比父类中被覆盖的方法更严格的访问权限。
        因为有可能将子类对象当做父类对象来使用,那么能获取到的父类对象中的方法在子类中必须都能获取到。
      8.4.6 覆盖方法时,不能比父类抛出更多的异常。
        子类只能比父类强,不能比父类弱。
   8.5 重载(Overload)和重写(Override)的区别:
      8.5.1 重载是方法名相同,参数列表不同,和返回值类型无关。
      8.5.2 重写是方法名、参数列表、返回值类型全相同。
      8.5.3 @Override 注解,可以检查覆盖是否成功
   8.6 继承的应用细节
      8.6.1 子类不继承父类私有成员
        父类中私有成员对外不可见,子类对象中无法访问这些成员。
      8.6.2 构造函数不被继承
        构造函数通常用来初始化类的成员变量,父类和子类的成员变量不同,初始化方式也不同,构造函数的名字也不同。
   8.7 子类对象实例化过程
      8.7.1 子类构造函数中可以使用super关键字调用父类构造函数。
      8.7.2 在子类创建对象时一定会调用父类构造函数。即使没有显式调用,也会默认调用父类无参构造函数。
      8.7.3 在子类中第一行用this关键字去调其他的构造方法,这时系统将不再自动调父类的。
            但其他构造函数中会调用父类构造函数。
      8.7.4 在构造方法中this和super关键字只能出现一次,而且必须是第一个语句。
        以后在设计类的时候,最好定义一个无参的构造方法,不然子类实例化的时候就容易出错。
      8.7.5 子类当做父类使用时需要注意
        当我们在调用某个类的一个方法时,此方法声明需要一个父类对象,这时我们可以将一个子类对象作为实参传递过去,
        注意此时方法定义的形参为父类,在方法中使用父类变量调用方法时,其实是调用子类的方法。
      8.7.6 在方法中用父类变量访问属性,访问的是父类的属性。
      8.7.7 在把子类当做父类来用时,使用父类变量访问方法,访问的是子类的方法。
    因为虚拟机会找到变量引用的地址,根据这个地址来访问方法,这叫动态分配。
    这种机制没有被使用到类的成员变量上,如果用父类变量访问属性,那么会直接找到父类的属性,不会看地址是哪个对象。


9. 多态(Polymorphism)

   9.1 什么是多态
    多态字面上的意思就是多种形态。在面向对象语言中,我们可以将函数的形参定义为一个父类类型,
    而在真正调用该函数时这个父类类型的所有子类对象都可以传入,根据传入的子类对象不同函数可以运行处多种形态。
   9.2 多态的特点
      9.2.1应用程序不必为每一个子类编写功能调用,只需要对父类进行处理即可。这一招叫“以不变应万变”,
       可以大大提高程序的可复用性。
      9.3 子类的功能可以被父类的变量调用,这叫向后兼容,可以提高程序的可扩充性和可维护性。
          现在写的程序可以调用将来写的程序不足为奇。



10. 抽象类

   10.1 什么是抽象类
      10.1.1 使用abstract关键字修饰的类就是抽象类,抽象类不能new对象。
      10.1.2 没有方法体的方法为抽象方法,使用abstract关键字修饰。
      10.1.3 有抽象方法的类必须声明为抽象类。
      10.1.4 抽象类不一定含有抽象方法。
   10.2 为什么要定义抽象类
      10.2.1 如果有多个类具有相同的方法声明,而方法的实现不一样,这时就可以抽象出父类,将方法在父类中声明
      10.2.2 别人在学习我们的软件时,只需要学习父类就知道子类有什么方法


11. final关键字

   11.1 final标记的类不能被继承。
   11.2 final标记的方法不能被子类重写。
   11.3 final标记的变量即为常量,只能赋值一次。注意引用数据类型和基本数据类型的区别。
   11.4 使用public static final共同修饰的常量就是全局常量。通常全部字母大写。


12. 模板设计模式(TemplatePattern)

   12.1 为什么要使用模板方法设计模式
      12.1.1 在解决一些问题或者设计一个软件的时候,需要先定义一个模板,就相当于一种事先定义好的协议。
      12.1.2 以后要做这系列的事情都按照这个模板来做。这样就实现统一化管理。
   12.2 如何实现模板方法设计模式
      12.2.1 定义一个抽象的父类做为模板,定义所有需要的方法
      12.2.2 在父类中实现供外界调用的主方法,将方法声明为final
      12.2.3 根据不同业务需求定义子类实现父类的抽象方法



13. 接口(Interface)

   13.1 什么是接口
    接口是一种特殊的抽象类,接口中声明的所有方法都是抽象的。使用interface关键字定义一个接口
   13.2 接口优点
    一个类可以实现多个接口,更好的支持多态
   13.3 接口的用法
      13.3.1 我们可以定义一个类来实现接口,使用implements关键字
      13.3.2 实现一个接口需要实现接口中所有的方法,抽象类除外
      13.3.3 通常使用匿名内部类来实现一个接口
      13.3.4 接口可以继承接口,使用extends关键字。 接口不能继承抽象类,因为抽象类中可能有不抽象的方法。
   13.4 接口中的方法和变量
      13.4.1 接口中定义的方法默认是公有的抽象的,被public abstract修饰
      13.4.2 接口中定义的变量默认为全局常量,使用public static final修饰
   13.5 abstract class和interface的区别
      13.5.1 抽象类中可以有不抽象的方法,接口中全是抽象的方法
      13.5.2 抽象类用extends继承,接口用implements实现
      13.5.3 抽象类中的变量和方法没有默认修饰符,接口中的变量默认为public static final的,
         接口中的方法默认为public abstract
      13.5.4 一个类只能继承一个抽象类,一个类可以实现多个接口
   13.6 什么时候用抽象类,什么时候用接口
      13.6.1 如果能用接口,就不用抽象类,因为别人实现接口可以不占用继承的位置。
      13.6.2 如果定义一个抽象的父类,其中所有方法都是抽象的,那么就定义为接口。
      13.6.3 如果定义一个抽象的父类的时候,需要有不抽象的方法,那么只能定义为抽象类。


你可能感兴趣的:(Java)